forked from seth/ipv4.army
refactor a lot
This commit is contained in:
parent
cf21a56d7a
commit
deb223c642
27 changed files with 401 additions and 381 deletions
88
src/back/Sockets/Hyperate.ts
Normal file
88
src/back/Sockets/Hyperate.ts
Normal file
|
@ -0,0 +1,88 @@
|
|||
import ReconnectingWebSocket from 'reconnecting-websocket';
|
||||
|
||||
export default class {
|
||||
private _socket: ReconnectingWebSocket;
|
||||
private _keepAlive: NodeJS.Timeout | null;
|
||||
private _interval: NodeJS.Timeout | null;
|
||||
private _callback: (data: number) => void;
|
||||
|
||||
constructor(callback: (data: number) => void) {
|
||||
this._socket = new ReconnectingWebSocket("wss://app.hyperate.io/socket/websocket?token=wv39nM6iyrNJulvpmMQrimYPIXy2dVrYRjkuHpbRapKT2VSh65ngDGHdCdCtmEN9")
|
||||
this._keepAlive = null;
|
||||
this._interval = null;
|
||||
this._callback = callback;
|
||||
|
||||
this._socket.binaryType = "arraybuffer";
|
||||
|
||||
this._socket.onopen = () => {
|
||||
console.log("Hyperate socket opened")
|
||||
|
||||
this._socket.send(
|
||||
JSON.stringify({
|
||||
topic: "hr:84aa0f",
|
||||
event: "phx_join",
|
||||
payload: {},
|
||||
ref: 0,
|
||||
}),
|
||||
);
|
||||
|
||||
this._keepAlive = setInterval(() => {
|
||||
this._socket.send(
|
||||
JSON.stringify({
|
||||
topic: "phoenix",
|
||||
event: "heartbeat",
|
||||
payload: {},
|
||||
ref: 0,
|
||||
}),
|
||||
);
|
||||
}, 10000);
|
||||
}
|
||||
|
||||
this._socket.onmessage = ({ data }: MessageEvent) => {
|
||||
data = JSON.parse(data);
|
||||
|
||||
switch (data.event) {
|
||||
case "hr_update": {
|
||||
this._callback(data.payload.hr);
|
||||
this.heartbeat();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this._socket.onerror = () => {
|
||||
console.error("Hyperate socket error");
|
||||
if (this._keepAlive) {
|
||||
clearInterval(this._keepAlive);
|
||||
this._keepAlive = null;
|
||||
}
|
||||
if (this._interval) {
|
||||
clearInterval(this._interval);
|
||||
this._interval = null;
|
||||
}
|
||||
}
|
||||
|
||||
this._socket.onclose = () => {
|
||||
console.log("Hyperate socket closed");
|
||||
if (this._keepAlive) {
|
||||
clearInterval(this._keepAlive);
|
||||
this._keepAlive = null;
|
||||
}
|
||||
if (this._interval) {
|
||||
clearInterval(this._interval);
|
||||
this._interval = null;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private heartbeat() {
|
||||
if (this._interval) {
|
||||
clearTimeout(this._interval);
|
||||
this._interval = null;
|
||||
}
|
||||
this._interval = setTimeout(() => {
|
||||
this._callback(0);
|
||||
}, 6000);
|
||||
}
|
||||
}
|
61
src/back/Sockets/Lanyard.ts
Normal file
61
src/back/Sockets/Lanyard.ts
Normal file
|
@ -0,0 +1,61 @@
|
|||
import ReconnectingWebSocket from 'reconnecting-websocket';
|
||||
|
||||
export default class {
|
||||
private _socket: ReconnectingWebSocket;
|
||||
private _keepAlive: NodeJS.Timeout | null;
|
||||
private _callback: (data: { [key: string]: string }) => void;
|
||||
|
||||
constructor(callback: (data: { [key: string]: string }) => void) {
|
||||
this._socket = new ReconnectingWebSocket("wss://lanyard.creations.works/socket")
|
||||
this._keepAlive = null;
|
||||
this._callback = callback;
|
||||
|
||||
this._socket.binaryType = "arraybuffer";
|
||||
|
||||
this._socket.onopen = () => {
|
||||
console.log("Lanyard socket opened")
|
||||
}
|
||||
|
||||
this._socket.onmessage = ({ data }: MessageEvent) => {
|
||||
data = JSON.parse(data);
|
||||
|
||||
switch (data.op) {
|
||||
case 0: {
|
||||
this._callback(data.d)
|
||||
break;
|
||||
}
|
||||
case 1: {
|
||||
this._socket.send(JSON.stringify({
|
||||
op: 2,
|
||||
d: {
|
||||
subscribe_to_id: "1273447359417942128"
|
||||
}
|
||||
}))
|
||||
this._keepAlive = setInterval(() => {
|
||||
this._socket.send(JSON.stringify({
|
||||
op: 3
|
||||
}))
|
||||
}, data.d.heartbeat_interval)
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this._socket.onerror = () => {
|
||||
console.error("Lanyard socket error");
|
||||
if (this._keepAlive) {
|
||||
clearInterval(this._keepAlive);
|
||||
this._keepAlive = null;
|
||||
}
|
||||
}
|
||||
|
||||
this._socket.onclose = () => {
|
||||
console.log("Lanyard socket closed");
|
||||
if (this._keepAlive) {
|
||||
clearInterval(this._keepAlive);
|
||||
this._keepAlive = null;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
74
src/back/index.ts
Normal file
74
src/back/index.ts
Normal file
|
@ -0,0 +1,74 @@
|
|||
import Hyperate from "./Sockets/Hyperate";
|
||||
import Lanyard from "./Sockets/Lanyard";
|
||||
|
||||
const development = process.env.NODE_ENV === "development";
|
||||
|
||||
const build = async () => {
|
||||
return await Bun.build({
|
||||
entrypoints: ['./src/front/index.html'],
|
||||
outdir: './dist',
|
||||
minify: !development,
|
||||
sourcemap: (development ? "inline" : "none"),
|
||||
splitting: true,
|
||||
publicPath: "/assets/",
|
||||
})
|
||||
}
|
||||
|
||||
const respOptions = {
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
"Cache-Control": "no-cache",
|
||||
"Content-Encoding": "gzip",
|
||||
}
|
||||
}
|
||||
const okResp = new Response(Bun.gzipSync(JSON.stringify({ data: "ok" })), respOptions)
|
||||
const Responses = {
|
||||
ok: () => {
|
||||
return okResp.clone();
|
||||
},
|
||||
json: (data: { [key: string]: string }) => {
|
||||
return new Response(Bun.gzipSync(JSON.stringify(data)), respOptions);
|
||||
},
|
||||
file: async (file: Bun.BunFile) => {
|
||||
return new Response(Bun.gzipSync(await file.arrayBuffer()), {
|
||||
headers: {
|
||||
"Content-Type": file.type,
|
||||
"Cache-Control": "public, max-age=31536000",
|
||||
"Content-Encoding": "gzip",
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
const postAnalytics = async (req: Request | Bun.BunRequest, server: Bun.Server) => {
|
||||
return await fetch("https://plausible.creations.works/api/event", {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
"User-Agent": req.headers.get("user-agent") || "",
|
||||
"X-Forwarded-For": String(
|
||||
req.headers.get("CF-Connecting-IP") ||
|
||||
req.headers.get("X-Real-IP") ||
|
||||
req.headers.get("X-Forwarded-For")?.split(",")[0] ||
|
||||
(typeof server.requestIP(req) === "string" ? server.requestIP(req) : (server.requestIP(req)?.address || ""))
|
||||
),
|
||||
},
|
||||
body: JSON.stringify({
|
||||
domain: "ipv4.army",
|
||||
name: "pageview",
|
||||
url: req.url,
|
||||
referrer: req.headers.get("referer") || "",
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
export default {
|
||||
Sockets: {
|
||||
Hyperate,
|
||||
Lanyard
|
||||
},
|
||||
Responses,
|
||||
build,
|
||||
development,
|
||||
postAnalytics,
|
||||
};
|
|
@ -1,40 +0,0 @@
|
|||
import { createRef } from "tsx-dom";
|
||||
import microlight from "microlight";
|
||||
|
||||
import socket from "../../Socket";
|
||||
|
||||
const statusTypes: { [key: string]: string } = {
|
||||
online: "green",
|
||||
idle: "yellow",
|
||||
dnd: "red",
|
||||
invisible: "inherent",
|
||||
offline: "inherent",
|
||||
}
|
||||
|
||||
const activityTypes: { [key: number]: string } = {
|
||||
0: "Playing",
|
||||
1: "Streaming",
|
||||
2: "Listening to",
|
||||
3: "Watching",
|
||||
4: "Custom",
|
||||
5: "Competing in",
|
||||
}
|
||||
|
||||
export default () => {
|
||||
const paragraph = createRef<HTMLParagraphElement>();
|
||||
|
||||
socket.addEventListener('lanyard', (event: Event) => {
|
||||
const lanyard = (event as CustomEvent).detail;
|
||||
if (paragraph.current) {
|
||||
paragraph.current.style = `--status-color: ${statusTypes[lanyard.discord_status]};`;
|
||||
paragraph.current.innerText = JSON.stringify({
|
||||
status: lanyard.discord_status,
|
||||
activities: lanyard.activities.map((act: { type: number, name: string }) => { return `${activityTypes[act.type]} ${act.name}` }),
|
||||
}, null, 1);
|
||||
}
|
||||
microlight.reset();
|
||||
});
|
||||
return <div>
|
||||
<p class="microlight" ref={paragraph}>{JSON.stringify({})}</p>
|
||||
</div>;
|
||||
}
|
|
@ -4,7 +4,7 @@
|
|||
|
||||
.scanlines:before,
|
||||
.scanlines:after {
|
||||
display: block;
|
||||
display: inherit;
|
||||
pointer-events: none;
|
||||
content: "";
|
||||
position: absolute;
|
||||
|
@ -28,8 +28,8 @@
|
|||
background: linear-gradient(to bottom,
|
||||
transparent 50%,
|
||||
rgba(0, 0, 0, 0.3) 51%);
|
||||
background-size: 100% 4px;
|
||||
animation: scanlines 1s steps(60) infinite;
|
||||
background-size: 100% 6px;
|
||||
animation: scanlines 2s steps(30) infinite;
|
||||
}
|
||||
|
||||
/* ANIMATE UNIQUE SCANLINE */
|
||||
|
@ -45,15 +45,15 @@
|
|||
}
|
||||
}
|
||||
|
||||
div {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
span.shj-syn-str:nth-child(2) {
|
||||
color: var(--status-color, rgba(150, 150, 150, 0.1));
|
||||
}
|
||||
|
||||
div.scanlines {
|
||||
position: absolute;
|
||||
.shj-numbers {
|
||||
padding: 0px;
|
||||
}
|
||||
|
||||
.microlight>span:nth-child(6) {
|
||||
color: var(--status-color);
|
||||
.shj-lang-json {
|
||||
padding: 0px;
|
||||
background-color: transparent;
|
||||
}
|
|
@ -2,9 +2,9 @@ import Lanyard from './components/Lanyard';
|
|||
import Hyperate from './components/Hyperate';
|
||||
|
||||
export default () => {
|
||||
return <div>
|
||||
return <div class="app">
|
||||
<p>seth> cat ./about.txt</p>
|
||||
<p>A Dedicated Backend Developer, with a passion for high-fidelity audio, gaming, and web development.</p>
|
||||
<p>A Dedicated Backend Developer,<br />with a passion for high-fidelity audio,<br />gaming, and web development.</p>
|
||||
|
||||
<p>seth> curl /tmp/discord-ipc</p>
|
||||
<p><Lanyard /></p>
|
|
@ -19,12 +19,24 @@ class Socket extends EventTarget {
|
|||
this.emitHyperate(data.hr);
|
||||
break;
|
||||
}
|
||||
case "echo": {
|
||||
console.log("Echo: ", data);
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
console.error("Unknown message type: ", type, data);
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
this._socket.onclose = () => {
|
||||
location.reload();
|
||||
};
|
||||
|
||||
setInterval(() => {
|
||||
this._socket.send("ping");
|
||||
}, 10000);
|
||||
}, 30 * 1000);
|
||||
}
|
||||
|
||||
emitLanyard(lanyard: object) {
|
|
@ -1,5 +1,4 @@
|
|||
import { createRef } from "tsx-dom";
|
||||
import microlight from "microlight";
|
||||
|
||||
import socket from "../../Socket";
|
||||
|
||||
|
@ -11,9 +10,8 @@ export default () => {
|
|||
if (paragraph.current) {
|
||||
paragraph.current.innerText = `${heartRate} BPM`;
|
||||
}
|
||||
microlight.reset();
|
||||
});
|
||||
return <div>
|
||||
<p class="microlight" ref={paragraph}>0 BPM</p>
|
||||
<p ref={paragraph}>0 BPM</p>
|
||||
</div>;
|
||||
}
|
59
src/front/components/Lanyard/index.tsx
Normal file
59
src/front/components/Lanyard/index.tsx
Normal file
|
@ -0,0 +1,59 @@
|
|||
import { createRef } from "tsx-dom";
|
||||
import { highlightAll } from "@speed-highlight/core";
|
||||
|
||||
import socket from "../../Socket";
|
||||
|
||||
const statusTypes: { [key: string]: string } = {
|
||||
online: "rgb(0, 150, 0)",
|
||||
idle: "rgb(150, 150, 0)",
|
||||
dnd: "rgb(150, 0, 0)",
|
||||
offline: "rgb(150, 150, 150)",
|
||||
}
|
||||
|
||||
const gradientTypes: { [key: string]: string } = {
|
||||
online: "rgba(0, 150, 0, 0.1)",
|
||||
idle: "rgba(150, 150, 0, 0.1)",
|
||||
dnd: "rgba(150, 0, 0, 0.1)",
|
||||
offline: "rgba(150, 150, 150, 0.1)",
|
||||
}
|
||||
const activityTypes: { [key: number]: string } = {
|
||||
0: "Playing",
|
||||
1: "Streaming",
|
||||
2: "Listening to",
|
||||
3: "Watching",
|
||||
4: "Custom Status",
|
||||
5: "Competing in",
|
||||
}
|
||||
|
||||
const stringify = (data: { [key: string]: string }) => {
|
||||
return JSON.stringify(data, null, 2)
|
||||
}
|
||||
|
||||
export default () => {
|
||||
const code = createRef<HTMLDivElement>();
|
||||
|
||||
socket.addEventListener('lanyard', (event: Event) => {
|
||||
const lanyard = (event as CustomEvent).detail;
|
||||
document.body.style = `--status-color: ${statusTypes[lanyard.discord_status]}; --gradient-color: ${gradientTypes[lanyard.discord_status]};`;
|
||||
if (code.current) {
|
||||
code.current.innerHTML = stringify({
|
||||
status: lanyard.discord_status,
|
||||
activities: lanyard.activities.map((act: {
|
||||
type: number, name: string, details: string, state: string
|
||||
}) => {
|
||||
return [
|
||||
... new Set([
|
||||
activityTypes[act.type],
|
||||
act.name,
|
||||
act.details,
|
||||
act.state
|
||||
])
|
||||
].filter(n => n)
|
||||
}),
|
||||
});
|
||||
}
|
||||
highlightAll();
|
||||
});
|
||||
|
||||
return <div class="shj-lang-json" ref={code}>{"{}"}</div>
|
||||
}
|
20
src/front/index.css
Normal file
20
src/front/index.css
Normal file
|
@ -0,0 +1,20 @@
|
|||
@import "../../node_modules/@speed-highlight/core/dist/themes/dark.css";
|
||||
|
||||
@import "./App.css";
|
||||
|
||||
html,
|
||||
head,
|
||||
body {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
font: 2vh monospace;
|
||||
height: 100vh;
|
||||
width: 100vw;
|
||||
}
|
||||
|
||||
body {
|
||||
color: #DEDEDE;
|
||||
text-shadow: 0 0 5px #C8C8C8;
|
||||
background: radial-gradient(at bottom right, var(--gradient-color, rgba(150, 150, 150, 0.1)) 0%, rgba(0, 0, 0, 1) 100%);
|
||||
display: flex;
|
||||
}
|
|
@ -4,21 +4,19 @@
|
|||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta name="theme-color" content="#1a1d1f">
|
||||
<meta name="theme-color" content="#000000">
|
||||
<meta name="description"
|
||||
content="A Dedicated Backend Developer, with a passion for high-fidelity audio, gaming, and web development.">
|
||||
<meta name="keywords" content="Seth, IPv4, Army, Seth@IPv4, web development, audio, gaming">
|
||||
<meta name="author" content="Seth">
|
||||
<title>Seth @ IPv4 dot Army</title>
|
||||
<link rel="icon" href="/public/favicon.svg" />
|
||||
<link rel="icon" href="/public/favicon.svg" />
|
||||
<meta name="color-scheme" content="dark" />
|
||||
<link rel="stylesheet" href="index.css" />
|
||||
<style id="font"></style>
|
||||
</head>
|
||||
|
||||
<body class="scanlines">
|
||||
<script src="index.tsx"></script>
|
||||
<script defer data-domain="yourdomain.com" data-api="/api/script" src="https://ipv4.army/api/script.js"></script>
|
||||
</body>
|
||||
|
||||
</html>
|
8
src/front/index.tsx
Normal file
8
src/front/index.tsx
Normal file
|
@ -0,0 +1,8 @@
|
|||
import "tsx-dom";
|
||||
|
||||
import App from './App';
|
||||
|
||||
document.body.appendChild(<App />);
|
||||
|
||||
// You're garbage, let me collect you.
|
||||
fetch("/api/gc")
|
|
@ -1,18 +0,0 @@
|
|||
@import "./App.css";
|
||||
|
||||
html,
|
||||
head,
|
||||
body {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
font-family: 'Circular Std', sans-serif;
|
||||
height: 100vh;
|
||||
width: 100vw;
|
||||
}
|
||||
|
||||
body {
|
||||
color: #DEDEDE;
|
||||
font: 2vh Inconsolata, monospace;
|
||||
text-shadow: 0 0 5px #C8C8C8;
|
||||
background: radial-gradient(at bottom right, rgba(0, 150, 0, 0.1) 0%, rgba(0, 0, 0, 1) 100%);
|
||||
}
|
|
@ -1,74 +0,0 @@
|
|||
import "tsx-dom";
|
||||
|
||||
import App from './App';
|
||||
|
||||
const font = document.getElementById("font")
|
||||
if (font) {
|
||||
font.innerText = `@font-face {
|
||||
font-family: 'Circular Std';
|
||||
src: url('/public/font/Black.woff2') format('woff2');
|
||||
font-weight: black;
|
||||
font-style: normal;
|
||||
font-display: swap
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'Circular Std';
|
||||
src: url('/public/font/BlackItalic.woff2') format('woff2');
|
||||
font-weight: black;
|
||||
font-style: italic;
|
||||
font-display: swap
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'Circular Std';
|
||||
src: url('/public/font/Bold.woff2') format('woff2');
|
||||
font-weight: bold;
|
||||
font-style: normal;
|
||||
font-display: swap
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'Circular Std';
|
||||
src: url('/public/font/BoldItalic.woff2') format('woff2');
|
||||
font-weight: bold;
|
||||
font-style: italic;
|
||||
font-display: swap
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'Circular Std';
|
||||
src: url('/public/font/Book.woff2') format('woff2');
|
||||
font-weight: normal;
|
||||
font-style: normal;
|
||||
font-display: swap
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'Circular Std';
|
||||
src: url('/public/font/BookItalic.woff2') format('woff2');
|
||||
font-weight: normal;
|
||||
font-style: italic;
|
||||
font-display: swap
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'Circular Std';
|
||||
src: url('/public/font/Medium.woff2') format('woff2');
|
||||
font-weight: 500;
|
||||
font-style: normal;
|
||||
font-display: swap
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'Circular Std';
|
||||
src: url('/public/font/MediumItalic.woff2') format('woff2');
|
||||
font-weight: 500;
|
||||
font-style: italic;
|
||||
font-display: swap
|
||||
}`
|
||||
}
|
||||
document.body.appendChild(<App />);
|
||||
|
||||
// You're garbage, let me collect you.
|
||||
fetch("/api/gc")
|
Loading…
Add table
Add a link
Reference in a new issue