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
10
bun.lock
10
bun.lock
|
@ -4,7 +4,9 @@
|
|||
"": {
|
||||
"name": "ipv4.army",
|
||||
"dependencies": {
|
||||
"@speed-highlight/core": "^1.2.7",
|
||||
"microlight": "^0.0.7",
|
||||
"reconnecting-websocket": "^4.4.0",
|
||||
"tsx-dom": "^3.1.0",
|
||||
},
|
||||
"devDependencies": {
|
||||
|
@ -35,14 +37,18 @@
|
|||
|
||||
"@biomejs/cli-win32-x64": ["@biomejs/cli-win32-x64@1.9.4", "", { "os": "win32", "cpu": "x64" }, "sha512-8Y5wMhVIPaWe6jw2H+KlEm4wP/f7EW3810ZLmDlrEEy5KvBsb9ECEfu/kMWD484ijfQ8+nIi0giMgu9g1UAuuA=="],
|
||||
|
||||
"@types/bun": ["@types/bun@1.2.10", "", { "dependencies": { "bun-types": "1.2.10" } }, "sha512-eilv6WFM3M0c9ztJt7/g80BDusK98z/FrFwseZgT4bXCq2vPhXD4z8R3oddmAn+R/Nmz9vBn4kweJKmGTZj+lg=="],
|
||||
"@speed-highlight/core": ["@speed-highlight/core@1.2.7", "", {}, "sha512-0dxmVj4gxg3Jg879kvFS/msl4s9F3T9UXC1InxgOf7t5NvcPD97u/WTA5vL/IxWHMn7qSxBozqrnnE2wvl1m8g=="],
|
||||
|
||||
"@types/bun": ["@types/bun@1.2.12", "", { "dependencies": { "bun-types": "1.2.12" } }, "sha512-lY/GQTXDGsolT/TiH72p1tuyUORuRrdV7VwOTOjDOt8uTBJQOJc5zz3ufwwDl0VBaoxotSk4LdP0hhjLJ6ypIQ=="],
|
||||
|
||||
"@types/node": ["@types/node@22.14.1", "", { "dependencies": { "undici-types": "~6.21.0" } }, "sha512-u0HuPQwe/dHrItgHHpmw3N2fYCR6x4ivMNbPHRkBVP4CvN+kiRrKHWk3i8tXiO/joPwXLMYvF9TTF0eqgHIuOw=="],
|
||||
|
||||
"bun-types": ["bun-types@1.2.10", "", { "dependencies": { "@types/node": "*" } }, "sha512-b5ITZMnVdf3m1gMvJHG+gIfeJHiQPJak0f7925Hxu6ZN5VKA8AGy4GZ4lM+Xkn6jtWxg5S3ldWvfmXdvnkp3GQ=="],
|
||||
"bun-types": ["bun-types@1.2.12", "", { "dependencies": { "@types/node": "*" } }, "sha512-tvWMx5vPqbRXgE8WUZI94iS1xAYs8bkqESR9cxBB1Wi+urvfTrF1uzuDgBHFAdO0+d2lmsbG3HmeKMvUyj6pWA=="],
|
||||
|
||||
"microlight": ["microlight@0.0.7", "", {}, "sha512-kigwsJYoy4mAMkGZpS839/KZ5WWQQm4TzD+eIjR5leS5H0j+EhExvK0Z2Or2ewkBR/t7/AHHhxRyeXi1kurG0g=="],
|
||||
|
||||
"reconnecting-websocket": ["reconnecting-websocket@4.4.0", "", {}, "sha512-D2E33ceRPga0NvTDhJmphEgJ7FUYF0v4lr1ki0csq06OdlxKfugGzN0dSkxM/NfqCxYELK4KcaTOUOjTV6Dcng=="],
|
||||
|
||||
"tsx-dom": ["tsx-dom@3.1.0", "", { "dependencies": { "tsx-dom-types": "2.1.0" } }, "sha512-PGN7iL6zNC4Jj7bA1groSIz5mFB3Rr+SeoywZk2g4+c9uV8wwzCf+5tFQ8SyZxQIBHech3ueB0KxV3OFieqhOA=="],
|
||||
|
||||
"tsx-dom-types": ["tsx-dom-types@2.1.0", "", {}, "sha512-pZaMTrMRNom+D1b82K+1cWVMuogXrD/ANI42UYxilw27tF+tDCgj7GrD1XLmCxbHPDO2zxfmFuaz04KIEfWydQ=="],
|
||||
|
|
4
hyperate.json
Normal file
4
hyperate.json
Normal file
|
@ -0,0 +1,4 @@
|
|||
{
|
||||
"5338": 18153,
|
||||
"null": 893
|
||||
}
|
259
index.ts
259
index.ts
|
@ -1,8 +1,9 @@
|
|||
import { build, serve, gzipSync, file, type BunRequest, gc } from "bun";
|
||||
import { build, serve, gzipSync, file, gc } from "bun";
|
||||
|
||||
import Backend from "./src/back"
|
||||
|
||||
import pkg from "./package.json";
|
||||
|
||||
const development = process.env.NODE_ENV === "development";
|
||||
|
||||
let heartrate = 0;
|
||||
let lanyard = {};
|
||||
|
@ -11,162 +12,75 @@ require("node:fs/promises").rm("./dist", { recursive: true, force: true }).catch
|
|||
// ignore
|
||||
});
|
||||
|
||||
const buildWeb = async () => {
|
||||
return await build({
|
||||
entrypoints: ['./src/index.html'],
|
||||
outdir: './dist',
|
||||
minify: !development,
|
||||
sourcemap: (development ? "inline" : "none"),
|
||||
splitting: true,
|
||||
publicPath: "/assets/",
|
||||
loader: {
|
||||
".woff2": "file"
|
||||
},
|
||||
})
|
||||
if (!Backend.development) {
|
||||
await Backend.build()
|
||||
}
|
||||
|
||||
if (!development) {
|
||||
await buildWeb()
|
||||
}
|
||||
|
||||
const webserver = serve({
|
||||
const server = serve({
|
||||
routes: {
|
||||
"/": async () => {
|
||||
if (development) {
|
||||
await buildWeb()
|
||||
"/": async (req: Bun.BunRequest, server: Bun.Server) => {
|
||||
await Backend.postAnalytics(req, server);
|
||||
|
||||
if (Backend.development) {
|
||||
await Backend.build()
|
||||
}
|
||||
return new Response(gzipSync(await file("./dist/index.html").arrayBuffer()), {
|
||||
headers: {
|
||||
"Content-Type": "text/html",
|
||||
"Cache-Control": "no-cache",
|
||||
"Content-Encoding": "gzip",
|
||||
}
|
||||
})
|
||||
|
||||
return await Backend.Responses.file(file("./dist/index.html"));
|
||||
},
|
||||
|
||||
"/assets/:file": async (req: BunRequest<"/assets/:file">) => {
|
||||
const reqFile = file(`./dist/${req.params.file}`)
|
||||
return new Response(gzipSync(await reqFile.arrayBuffer()), {
|
||||
headers: {
|
||||
"Content-Type": reqFile.type,
|
||||
"Cache-Control": "public, max-age=31536000",
|
||||
"Content-Encoding": "gzip",
|
||||
}
|
||||
})
|
||||
"/assets/:file": async (req: Bun.BunRequest<"/assets/:file">) => {
|
||||
return await Backend.Responses.file(file(`./dist/${req.params.file}`));
|
||||
},
|
||||
|
||||
"/public/:file": async (req: BunRequest<"/public/:file">) => {
|
||||
const reqFile = file(`./public/${req.params.file}`)
|
||||
let fileRes = await reqFile.text()
|
||||
|
||||
fileRes = fileRes.replace("{{LANYARD}}", `${JSON.stringify({ example: "lanyard data" })}`)
|
||||
fileRes = fileRes.replace("{{HYPERATE}}", `${JSON.stringify({ example: "hyperate data" })}`)
|
||||
|
||||
return new Response(gzipSync(fileRes), {
|
||||
headers: {
|
||||
"Content-Type": reqFile.type,
|
||||
"Cache-Control": "public, max-age=31536000",
|
||||
"Content-Encoding": "gzip",
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
"/public/font/:file": async (req: BunRequest<"/public/font/:file">) => {
|
||||
const reqFile = file(`./public/font/${req.params.file}`)
|
||||
return new Response(gzipSync(await reqFile.arrayBuffer()), {
|
||||
headers: {
|
||||
"Content-Type": reqFile.type,
|
||||
"Cache-Control": "public, max-age=31536000",
|
||||
"Content-Encoding": "gzip",
|
||||
}
|
||||
})
|
||||
"/public/:file": async (req: Bun.BunRequest<"/public/:file">) => {
|
||||
return await Backend.Responses.file(file(`./public/${req.params.file}`));
|
||||
},
|
||||
|
||||
"/api/server": () => {
|
||||
const string = JSON.stringify(process)
|
||||
const json = JSON.parse(string)
|
||||
const data = JSON.parse(string)
|
||||
|
||||
// clear possibly data that could be sensitive
|
||||
json.argv = {}
|
||||
json.debugPort = 0
|
||||
json.env = {}
|
||||
json.execArgv = []
|
||||
json.execPath = ""
|
||||
json.stderr = {}
|
||||
json.stdin = {}
|
||||
json.stdout = {}
|
||||
json.title = ""
|
||||
data.env = {}
|
||||
|
||||
json.availableMemory = process.availableMemory()
|
||||
json.constrainedMemory = process.constrainedMemory()
|
||||
json.cpuUsage = process.cpuUsage()
|
||||
json.memoryUsage = process.memoryUsage()
|
||||
json.uptime = process.uptime()
|
||||
json.package = pkg
|
||||
data.availableMemory = process.availableMemory()
|
||||
data.constrainedMemory = process.constrainedMemory()
|
||||
data.cpuUsage = process.cpuUsage()
|
||||
data.memoryUsage = process.memoryUsage()
|
||||
data.uptime = process.uptime()
|
||||
data.package = pkg
|
||||
|
||||
return new Response(gzipSync(JSON.stringify({ data: json })), {
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
"Cache-Control": "no-cache",
|
||||
"Content-Encoding": "gzip",
|
||||
}
|
||||
})
|
||||
return Backend.Responses.json({ data });
|
||||
},
|
||||
"/api/health": () => {
|
||||
return new Response(gzipSync(JSON.stringify({ data: "ok" })), {
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
"Cache-Control": "no-cache",
|
||||
"Content-Encoding": "gzip",
|
||||
}
|
||||
})
|
||||
return Backend.Responses.ok();
|
||||
},
|
||||
"/api/ws": (req, server) => {
|
||||
"/api/ws": async (req, server) => {
|
||||
if (server.upgrade(req)) {
|
||||
return;
|
||||
}
|
||||
|
||||
return new Response("Upgrade failed", { status: 500 });
|
||||
await Backend.postAnalytics(req, server);
|
||||
return Response.redirect("/");
|
||||
},
|
||||
"/api/gc": async (req, server) => {
|
||||
"/api/gc": async () => {
|
||||
gc(true)
|
||||
|
||||
return new Response(gzipSync(JSON.stringify({ data: "triggered" })), {
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
"Cache-Control": "no-cache",
|
||||
"Content-Encoding": "gzip",
|
||||
}
|
||||
})
|
||||
},
|
||||
"/api/script.js": async () => {
|
||||
const req = await fetch("https://plausible.creations.works/js/script.js")
|
||||
const script = await req.text()
|
||||
|
||||
return new Response(gzipSync(script), {
|
||||
headers: {
|
||||
"Content-Type": "application/javascript",
|
||||
"Content-Encoding": "gzip",
|
||||
"Cache-Control": "public, max-age=31536000",
|
||||
}
|
||||
})
|
||||
},
|
||||
"/api/script": async (req) => {
|
||||
const request = new Request(req);
|
||||
request.headers.delete('cookie');
|
||||
return await fetch("https://plausible.creations.works/api/event", request);
|
||||
return Backend.Responses.ok();
|
||||
},
|
||||
"/api/headers": async (req) => {
|
||||
return new Response(gzipSync(JSON.stringify({ headers: req.headers })), {
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
"Content-Encoding": "gzip",
|
||||
"Cache-Control": "no-cache",
|
||||
}
|
||||
})
|
||||
return Backend.Responses.json({ ...req.headers.toJSON() });
|
||||
}
|
||||
},
|
||||
|
||||
fetch: async (request, server) => {
|
||||
await Backend.postAnalytics(request, server);
|
||||
|
||||
return Response.redirect("/");
|
||||
},
|
||||
|
||||
websocket: {
|
||||
idleTimeout: 1,
|
||||
open: async (ws) => {
|
||||
ws.subscribe("lanyard");
|
||||
ws.send(JSON.stringify({ type: "lanyard", data: lanyard }), true);
|
||||
|
@ -178,91 +92,16 @@ const webserver = serve({
|
|||
ws.send(JSON.stringify({ type: "echo", data: message }), true)
|
||||
}
|
||||
},
|
||||
development,
|
||||
development: Backend.development,
|
||||
port: 2056
|
||||
});
|
||||
|
||||
const lanyardSocket = new WebSocket("wss://lanyard.creations.works/socket");
|
||||
new Backend.Sockets.Hyperate((data) => {
|
||||
heartrate = data;
|
||||
server.publish("hyperate", JSON.stringify({ type: "hyperate", data: { hr: heartrate } }), true);
|
||||
})
|
||||
|
||||
const setLanyard = (data: object) => {
|
||||
new Backend.Sockets.Lanyard((data) => {
|
||||
lanyard = data;
|
||||
|
||||
return webserver.publish("lanyard", JSON.stringify({ type: "lanyard", data }), true);
|
||||
}
|
||||
|
||||
lanyardSocket.onmessage = ({ data }) => {
|
||||
data = JSON.parse(data);
|
||||
|
||||
switch (data.op) {
|
||||
case 0: {
|
||||
setLanyard(data.d)
|
||||
break;
|
||||
}
|
||||
case 1: {
|
||||
lanyardSocket.send(JSON.stringify({
|
||||
op: 2,
|
||||
d: {
|
||||
subscribe_to_id: "1273447359417942128"
|
||||
}
|
||||
}))
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const hyperate = new WebSocket(
|
||||
"wss://app.hyperate.io/socket/websocket?token=wv39nM6iyrNJulvpmMQrimYPIXy2dVrYRjkuHpbRapKT2VSh65ngDGHdCdCtmEN9",
|
||||
);
|
||||
|
||||
let hrTimeout: ReturnType<typeof setTimeout>;
|
||||
|
||||
const setHeartrate = async (hr: number) => {
|
||||
heartrate = hr;
|
||||
|
||||
return webserver.publish("hyperate", JSON.stringify({ type: "hyperate", data: { hr } }), true);
|
||||
}
|
||||
|
||||
const setHrInterval = () => {
|
||||
hrTimeout = setTimeout(() => {
|
||||
setHeartrate(0);
|
||||
}, 6000);
|
||||
};
|
||||
|
||||
hyperate.onopen = () => {
|
||||
hyperate.send(
|
||||
JSON.stringify({
|
||||
topic: "hr:0BCA",
|
||||
event: "phx_join",
|
||||
payload: {},
|
||||
ref: 0,
|
||||
}),
|
||||
);
|
||||
|
||||
setInterval(() => {
|
||||
hyperate.send(
|
||||
JSON.stringify({
|
||||
topic: "phoenix",
|
||||
event: "heartbeat",
|
||||
payload: {},
|
||||
ref: 0,
|
||||
}),
|
||||
);
|
||||
}, 10000);
|
||||
|
||||
return setHrInterval();
|
||||
};
|
||||
|
||||
hyperate.onmessage = ({ data }) => {
|
||||
const { event, payload } = JSON.parse(data);
|
||||
switch (event) {
|
||||
case "hr_update": {
|
||||
clearTimeout(hrTimeout);
|
||||
setHrInterval();
|
||||
setHeartrate(payload.hr);
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
server.publish("lanyard", JSON.stringify({ type: "lanyard", data: lanyard }), true);
|
||||
});
|
|
@ -15,7 +15,9 @@
|
|||
"private": true,
|
||||
"type": "module",
|
||||
"dependencies": {
|
||||
"@speed-highlight/core": "^1.2.7",
|
||||
"microlight": "^0.0.7",
|
||||
"reconnecting-websocket": "^4.4.0",
|
||||
"tsx-dom": "^3.1.0"
|
||||
}
|
||||
}
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -1,17 +0,0 @@
|
|||
import { Glob } from "bun";
|
||||
|
||||
const woff2 = new Glob("./*.woff2");
|
||||
|
||||
for await (const file of woff2.scan(".")) {
|
||||
const font = Bun.file(file);
|
||||
|
||||
const name = font.name?.split("-")[1];
|
||||
|
||||
await Bun.write(`./${name}`, await font.arrayBuffer());
|
||||
console.log(`Renamed ${file} to ${name}`);
|
||||
|
||||
await font.delete();
|
||||
console.log(`Deleted original font file: ${file}`);
|
||||
}
|
||||
|
||||
console.log("Done")
|
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
Reference in a new issue