move index to src, add .env add types, fix > to actual bash like input and history #1
11 changed files with 339 additions and 180 deletions
2
.env.example
Normal file
2
.env.example
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
HOSTNAME=localhost
|
||||||
|
PORT=2056
|
119
index.ts
119
index.ts
|
@ -1,119 +0,0 @@
|
||||||
import { file, gc, serve } from "bun";
|
|
||||||
|
|
||||||
import Backend from "./src/back";
|
|
||||||
|
|
||||||
import pkg from "./package.json";
|
|
||||||
|
|
||||||
let heartrate = 0;
|
|
||||||
let lanyard = {};
|
|
||||||
|
|
||||||
require("node:fs/promises")
|
|
||||||
.rm("./dist", { recursive: true, force: true })
|
|
||||||
.catch(() => {
|
|
||||||
// ignore
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!Backend.development) {
|
|
||||||
await Backend.build();
|
|
||||||
}
|
|
||||||
|
|
||||||
const server = serve({
|
|
||||||
routes: {
|
|
||||||
"/": async (req: Bun.BunRequest, server: Bun.Server) => {
|
|
||||||
await Backend.postAnalytics(req, server);
|
|
||||||
|
|
||||||
if (Backend.development) {
|
|
||||||
await Backend.build();
|
|
||||||
}
|
|
||||||
|
|
||||||
return await Backend.Responses.file(file("./dist/index.html"));
|
|
||||||
},
|
|
||||||
|
|
||||||
"/assets/:file": async (req: Bun.BunRequest<"/assets/:file">) => {
|
|
||||||
return await Backend.Responses.file(file(`./dist/${req.params.file}`));
|
|
||||||
},
|
|
||||||
|
|
||||||
"/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 data = JSON.parse(string);
|
|
||||||
|
|
||||||
// clear possibly data that could be sensitive
|
|
||||||
data.env = {};
|
|
||||||
|
|
||||||
data.availableMemory = process.availableMemory();
|
|
||||||
data.constrainedMemory = process.constrainedMemory();
|
|
||||||
data.cpuUsage = process.cpuUsage();
|
|
||||||
data.memoryUsage = process.memoryUsage();
|
|
||||||
data.uptime = process.uptime();
|
|
||||||
data.package = pkg;
|
|
||||||
|
|
||||||
return Backend.Responses.json({ data });
|
|
||||||
},
|
|
||||||
"/api/health": () => {
|
|
||||||
return Backend.Responses.ok();
|
|
||||||
},
|
|
||||||
"/api/ws": async (req, server) => {
|
|
||||||
if (server.upgrade(req)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
await Backend.postAnalytics(req, server);
|
|
||||||
return Response.redirect("/");
|
|
||||||
},
|
|
||||||
"/api/gc": async () => {
|
|
||||||
gc(true);
|
|
||||||
|
|
||||||
return Backend.Responses.ok();
|
|
||||||
},
|
|
||||||
"/api/headers": async (req) => {
|
|
||||||
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);
|
|
||||||
|
|
||||||
ws.subscribe("hyperate");
|
|
||||||
ws.send(
|
|
||||||
JSON.stringify({ type: "hyperate", data: { hr: heartrate } }),
|
|
||||||
true,
|
|
||||||
);
|
|
||||||
},
|
|
||||||
message: async (ws, message) => {
|
|
||||||
ws.send(JSON.stringify({ type: "echo", data: message }), true);
|
|
||||||
},
|
|
||||||
},
|
|
||||||
development: Backend.development,
|
|
||||||
port: 2056,
|
|
||||||
});
|
|
||||||
|
|
||||||
new Backend.Sockets.Hyperate((data) => {
|
|
||||||
heartrate = data;
|
|
||||||
server.publish(
|
|
||||||
"hyperate",
|
|
||||||
JSON.stringify({ type: "hyperate", data: { hr: heartrate } }),
|
|
||||||
true,
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
new Backend.Sockets.Lanyard((data) => {
|
|
||||||
lanyard = data;
|
|
||||||
server.publish(
|
|
||||||
"lanyard",
|
|
||||||
JSON.stringify({ type: "lanyard", data: lanyard }),
|
|
||||||
true,
|
|
||||||
);
|
|
||||||
});
|
|
|
@ -2,8 +2,8 @@
|
||||||
"name": "ipv4.army",
|
"name": "ipv4.army",
|
||||||
"module": "index.ts",
|
"module": "index.ts",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "NODE_ENV=development bun run --hot . --watch",
|
"dev": "NODE_ENV=development bun run --hot src/index.ts",
|
||||||
"start": "bun run .",
|
"start": "bun run src/index.ts",
|
||||||
"lint": "bunx biome ci . --verbose",
|
"lint": "bunx biome ci . --verbose",
|
||||||
"lint:fix": "bunx biome check --fix"
|
"lint:fix": "bunx biome check --fix"
|
||||||
},
|
},
|
||||||
|
|
|
@ -3,9 +3,9 @@ import ReconnectingWebSocket from "reconnecting-websocket";
|
||||||
export default class {
|
export default class {
|
||||||
private _socket: ReconnectingWebSocket;
|
private _socket: ReconnectingWebSocket;
|
||||||
private _keepAlive: NodeJS.Timeout | null;
|
private _keepAlive: NodeJS.Timeout | null;
|
||||||
private _callback: (data: { [key: string]: string }) => void;
|
private _callback: (data: LanyardData) => void;
|
||||||
|
|
||||||
constructor(callback: (data: { [key: string]: string }) => void) {
|
constructor(callback: (data: LanyardData) => void) {
|
||||||
this._socket = new ReconnectingWebSocket(
|
this._socket = new ReconnectingWebSocket(
|
||||||
"wss://lanyard.creations.works/socket",
|
"wss://lanyard.creations.works/socket",
|
||||||
);
|
);
|
||||||
|
|
|
@ -1,27 +1,145 @@
|
||||||
import Hyperate from "./components/Hyperate";
|
import Hyperate from "./components/Hyperate";
|
||||||
import Lanyard from "./components/Lanyard";
|
import Lanyard from "./components/Lanyard";
|
||||||
|
|
||||||
|
let latestLanyard: LanyardData | null = null;
|
||||||
|
|
||||||
|
window.addEventListener("lanyard-update", (e) => {
|
||||||
|
latestLanyard = (e as CustomEvent<LanyardData>).detail;
|
||||||
|
});
|
||||||
|
|
||||||
export default () => {
|
export default () => {
|
||||||
return (
|
const container = document.createElement("div");
|
||||||
<div class="app">
|
container.className = "app terminal";
|
||||||
<p>seth> cat ./about.txt</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>
|
const renderElement = (content: string | Node) => {
|
||||||
<p>
|
const p = document.createElement("p");
|
||||||
<Lanyard />
|
if (typeof content === "string") {
|
||||||
</p>
|
p.textContent = content;
|
||||||
|
} else {
|
||||||
<p>seth> cat /tmp/heartrate</p>
|
p.appendChild(content);
|
||||||
<p>
|
}
|
||||||
<Hyperate />
|
return p;
|
||||||
</p>
|
};
|
||||||
</div>
|
|
||||||
);
|
const prompt = "[seth@ipv4 ~]$";
|
||||||
|
|
||||||
|
const staticLines: (string | (() => Node))[] = [
|
||||||
|
`${prompt} cat ./about.txt`,
|
||||||
|
() =>
|
||||||
|
document
|
||||||
|
.createRange()
|
||||||
|
.createContextualFragment(
|
||||||
|
"A Dedicated Backend Developer,<br />with a passion for high-fidelity audio,<br />gaming, and web development.",
|
||||||
|
),
|
||||||
|
`${prompt} cat /tmp/discord-ipc`,
|
||||||
|
() => Lanyard(),
|
||||||
|
`${prompt} cat /tmp/heartrate`,
|
||||||
|
() => Hyperate(),
|
||||||
|
];
|
||||||
|
|
||||||
|
const renderStatic = () => {
|
||||||
|
for (const line of staticLines) {
|
||||||
|
const content = typeof line === "function" ? line() : line;
|
||||||
|
container.appendChild(renderElement(content));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
renderStatic();
|
||||||
|
|
||||||
|
const lanyardInstance = Lanyard();
|
||||||
|
const files: Record<string, () => Node> = {
|
||||||
|
"./about.txt": () =>
|
||||||
|
document
|
||||||
|
.createRange()
|
||||||
|
.createContextualFragment(
|
||||||
|
"A Dedicated Backend Developer,<br />with a passion for high-fidelity audio,<br />gaming, and web development.",
|
||||||
|
),
|
||||||
|
"/tmp/discord-ipc": () => lanyardInstance,
|
||||||
|
"/tmp/heartrate": () => Hyperate(),
|
||||||
|
};
|
||||||
|
|
||||||
|
const history: string[] = [];
|
||||||
|
let historyIndex = -1;
|
||||||
|
|
||||||
|
const inputBox = document.createElement("input");
|
||||||
|
inputBox.className = "terminal-input";
|
||||||
|
inputBox.autofocus = true;
|
||||||
|
|
||||||
|
const inputLine = document.createElement("div");
|
||||||
|
inputLine.className = "terminal-line";
|
||||||
|
|
||||||
|
const promptSpan = document.createElement("span");
|
||||||
|
promptSpan.textContent = `${prompt} `;
|
||||||
|
|
||||||
|
inputLine.appendChild(promptSpan);
|
||||||
|
inputLine.appendChild(inputBox);
|
||||||
|
container.appendChild(inputLine);
|
||||||
|
|
||||||
|
const appendLine = (line: string | Node) => {
|
||||||
|
container.insertBefore(renderElement(line), inputLine);
|
||||||
|
};
|
||||||
|
|
||||||
|
inputBox.addEventListener("keydown", (e) => {
|
||||||
|
if (e.key === "Enter") {
|
||||||
|
const cmd = inputBox.value.trim();
|
||||||
|
if (!cmd) return;
|
||||||
|
|
||||||
|
history.push(cmd);
|
||||||
|
historyIndex = history.length;
|
||||||
|
|
||||||
|
appendLine(`${prompt} ${cmd}`);
|
||||||
|
|
||||||
|
let out: string | Node;
|
||||||
|
|
||||||
|
if (cmd.startsWith("cat ")) {
|
||||||
|
const file = cmd.slice(4).trim();
|
||||||
|
out = files[file]?.() ?? `cat: ${file}: No such file`;
|
||||||
|
} else if (cmd === "ls") {
|
||||||
|
out = Object.keys(files)
|
||||||
|
.filter((f) => f.startsWith("./"))
|
||||||
|
.map((f) => f.slice(2))
|
||||||
|
.join("\n");
|
||||||
|
} else if (cmd.startsWith("ls ")) {
|
||||||
|
const dir = cmd.slice(3).trim();
|
||||||
|
if (dir === "/tmp") {
|
||||||
|
out = Object.keys(files)
|
||||||
|
.filter((f) => f.startsWith("/tmp/"))
|
||||||
|
.map((f) => f.slice("/tmp/".length))
|
||||||
|
.join("\n");
|
||||||
|
} else {
|
||||||
|
out = `ls: cannot access '${dir}': No such file or directory`;
|
||||||
|
}
|
||||||
|
} else if (cmd === "help") {
|
||||||
|
out = [
|
||||||
|
"Available commands:",
|
||||||
|
" cat [file] View contents of a file",
|
||||||
|
" ls List files in current directory",
|
||||||
|
" ls /tmp List files in /tmp directory",
|
||||||
|
" help Show this message",
|
||||||
|
].join("\n");
|
||||||
|
} else {
|
||||||
|
out = `bash: ${cmd}: command not found`;
|
||||||
|
}
|
||||||
|
|
||||||
|
appendLine(out);
|
||||||
|
inputBox.value = "";
|
||||||
|
} else if (e.key === "ArrowUp") {
|
||||||
|
if (historyIndex > 0) {
|
||||||
|
historyIndex--;
|
||||||
|
inputBox.value = history[historyIndex] || "";
|
||||||
|
}
|
||||||
|
e.preventDefault();
|
||||||
|
} else if (e.key === "ArrowDown") {
|
||||||
|
if (historyIndex < history.length - 1) {
|
||||||
|
historyIndex++;
|
||||||
|
inputBox.value = history[historyIndex] || "";
|
||||||
|
} else {
|
||||||
|
historyIndex = history.length;
|
||||||
|
inputBox.value = "";
|
||||||
|
}
|
||||||
|
e.preventDefault();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return container;
|
||||||
};
|
};
|
||||||
|
|
|
@ -39,8 +39,11 @@ class Socket extends EventTarget {
|
||||||
}, 30 * 1000);
|
}, 30 * 1000);
|
||||||
}
|
}
|
||||||
|
|
||||||
emitLanyard(lanyard: object) {
|
emitLanyard(lanyard: LanyardData) {
|
||||||
this.dispatchEvent(new CustomEvent("lanyard", { detail: lanyard }));
|
this.dispatchEvent(new CustomEvent("lanyard", { detail: lanyard }));
|
||||||
|
window.dispatchEvent(
|
||||||
|
new CustomEvent("lanyard-update", { detail: lanyard }),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
emitHyperate(heartRate: number) {
|
emitHyperate(heartRate: number) {
|
||||||
this.dispatchEvent(new CustomEvent("hyperate", { detail: heartRate }));
|
this.dispatchEvent(new CustomEvent("hyperate", { detail: heartRate }));
|
||||||
|
|
|
@ -1,22 +1,22 @@
|
||||||
import { highlightAll } from "@speed-highlight/core";
|
import { highlightElement } from "@speed-highlight/core";
|
||||||
import { createRef } from "tsx-dom";
|
import { createRef } from "tsx-dom";
|
||||||
|
|
||||||
import socket from "../../Socket";
|
import socket from "../../Socket";
|
||||||
|
|
||||||
const statusTypes: { [key: string]: string } = {
|
const statusTypes = {
|
||||||
online: "rgb(0, 150, 0)",
|
online: "rgb(0, 150, 0)",
|
||||||
idle: "rgb(150, 150, 0)",
|
idle: "rgb(150, 150, 0)",
|
||||||
dnd: "rgb(150, 0, 0)",
|
dnd: "rgb(150, 0, 0)",
|
||||||
offline: "rgb(150, 150, 150)",
|
offline: "rgb(150, 150, 150)",
|
||||||
};
|
};
|
||||||
|
|
||||||
const gradientTypes: { [key: string]: string } = {
|
const gradientTypes = {
|
||||||
online: "rgba(0, 150, 0, 0.1)",
|
online: "rgba(0, 150, 0, 0.1)",
|
||||||
idle: "rgba(150, 150, 0, 0.1)",
|
idle: "rgba(150, 150, 0, 0.1)",
|
||||||
dnd: "rgba(150, 0, 0, 0.1)",
|
dnd: "rgba(150, 0, 0, 0.1)",
|
||||||
offline: "rgba(150, 150, 150, 0.1)",
|
offline: "rgba(150, 150, 150, 0.1)",
|
||||||
};
|
};
|
||||||
const activityTypes: { [key: number]: string } = {
|
|
||||||
|
const activityTypes: Record<number, string> = {
|
||||||
0: "Playing",
|
0: "Playing",
|
||||||
1: "Streaming",
|
1: "Streaming",
|
||||||
2: "Listening to",
|
2: "Listening to",
|
||||||
|
@ -25,43 +25,37 @@ const activityTypes: { [key: number]: string } = {
|
||||||
5: "Competing in",
|
5: "Competing in",
|
||||||
};
|
};
|
||||||
|
|
||||||
const stringify = (data: { [key: string]: string }) => {
|
|
||||||
return JSON.stringify(data, null, 2);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default () => {
|
export default () => {
|
||||||
const code = createRef<HTMLDivElement>();
|
const container = createRef<HTMLDivElement>();
|
||||||
|
|
||||||
socket.addEventListener("lanyard", (event: Event) => {
|
socket.addEventListener("lanyard", (event: Event) => {
|
||||||
const lanyard = (event as CustomEvent).detail;
|
const lanyard = (event as CustomEvent<LanyardData>).detail;
|
||||||
|
|
||||||
document.body.style = `--status-color: ${statusTypes[lanyard.discord_status]}; --gradient-color: ${gradientTypes[lanyard.discord_status]};`;
|
document.body.style = `--status-color: ${statusTypes[lanyard.discord_status]}; --gradient-color: ${gradientTypes[lanyard.discord_status]};`;
|
||||||
if (code.current) {
|
|
||||||
code.current.innerHTML = stringify({
|
if (container.current) {
|
||||||
|
container.current.className = "shj-lang-json";
|
||||||
|
container.current.textContent = JSON.stringify(
|
||||||
|
{
|
||||||
status: lanyard.discord_status,
|
status: lanyard.discord_status,
|
||||||
activities: lanyard.activities.map(
|
activities: lanyard.activities.map((act) => {
|
||||||
(act: {
|
const type = activityTypes[act.type];
|
||||||
type: number;
|
const parts = [type];
|
||||||
name: string;
|
if (act.name !== type) parts.push(act.name);
|
||||||
details: string;
|
if (act.details) parts.push(act.details);
|
||||||
state: string;
|
if (act.state) parts.push(act.state);
|
||||||
}) => {
|
return parts;
|
||||||
return [
|
}),
|
||||||
...new Set([
|
|
||||||
activityTypes[act.type],
|
|
||||||
act.name,
|
|
||||||
act.details,
|
|
||||||
act.state,
|
|
||||||
]),
|
|
||||||
].filter((n) => n);
|
|
||||||
},
|
},
|
||||||
),
|
null,
|
||||||
});
|
2
|
||||||
|
);
|
||||||
|
highlightElement(container.current);
|
||||||
}
|
}
|
||||||
highlightAll();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div class="shj-lang-json" ref={code}>
|
<div class="shj-lang-json" ref={container}>
|
||||||
{"{}"}
|
{"{}"}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
@import "../../node_modules/@speed-highlight/core/dist/themes/dark.css";
|
@import "../../node_modules/@speed-highlight/core/dist/themes/dark.css";
|
||||||
|
|
||||||
@import "./App.css";
|
@import "./App.css";
|
||||||
|
|
||||||
html,
|
html,
|
||||||
|
@ -21,4 +20,47 @@ body {
|
||||||
rgba(0, 0, 0, 1) 100%
|
rgba(0, 0, 0, 1) 100%
|
||||||
);
|
);
|
||||||
display: flex;
|
display: flex;
|
||||||
|
height: 100vh;
|
||||||
|
width: 100vw;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
p {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
line-height: 1.4em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.terminal {
|
||||||
|
white-space: pre-wrap;
|
||||||
|
font-family: monospace;
|
||||||
|
width: 100vw;
|
||||||
|
height: 100vh;
|
||||||
|
overflow-y: auto;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
box-sizing: border-box;
|
||||||
|
|
||||||
|
gap: 0.4em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.terminal-input {
|
||||||
|
background: transparent;
|
||||||
|
border: none;
|
||||||
|
color: inherit;
|
||||||
|
font: inherit;
|
||||||
|
outline: none;
|
||||||
|
display: inline-block;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.terminal-line {
|
||||||
|
display: flex;
|
||||||
|
align-items: baseline;
|
||||||
|
flex-direction: row;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.terminal-line > span {
|
||||||
|
white-space: pre;
|
||||||
}
|
}
|
||||||
|
|
105
src/index.ts
Normal file
105
src/index.ts
Normal file
|
@ -0,0 +1,105 @@
|
||||||
|
import fs from "node:fs/promises";
|
||||||
|
import { file, gc, serve } from "bun";
|
||||||
|
import pkg from "../package.json";
|
||||||
|
import Backend from "./back";
|
||||||
|
|
||||||
|
let heartrate = 0;
|
||||||
|
let lanyard: LanyardData = {
|
||||||
|
discord_status: "online",
|
||||||
|
activities: [],
|
||||||
|
};
|
||||||
|
|
||||||
|
await fs.rm("./dist", { recursive: true, force: true }).catch(() => {});
|
||||||
|
|
||||||
|
if (!Backend.development) {
|
||||||
|
await Backend.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
const server = serve({
|
||||||
|
port: process.env.PORT || 3000,
|
||||||
|
hostname: process.env.HOSTNAME || "localhost",
|
||||||
|
development: Backend.development,
|
||||||
|
|
||||||
|
routes: {
|
||||||
|
"/": async (req, server) => {
|
||||||
|
await Backend.postAnalytics(req, server);
|
||||||
|
if (Backend.development) await Backend.build();
|
||||||
|
return Backend.Responses.file(file("./dist/index.html"));
|
||||||
|
},
|
||||||
|
|
||||||
|
"/assets/:file": async (req) =>
|
||||||
|
Backend.Responses.file(file(`./dist/${req.params.file}`)),
|
||||||
|
|
||||||
|
"/public/:file": async (req) =>
|
||||||
|
Backend.Responses.file(file(`./public/${req.params.file}`)),
|
||||||
|
|
||||||
|
"/api/server": () => {
|
||||||
|
const safeProcess = JSON.parse(JSON.stringify(process));
|
||||||
|
safeProcess.env = {};
|
||||||
|
safeProcess.availableMemory = process.availableMemory();
|
||||||
|
safeProcess.constrainedMemory = process.constrainedMemory();
|
||||||
|
safeProcess.cpuUsage = process.cpuUsage();
|
||||||
|
safeProcess.memoryUsage = process.memoryUsage();
|
||||||
|
safeProcess.uptime = process.uptime();
|
||||||
|
safeProcess.package = pkg;
|
||||||
|
|
||||||
|
return Backend.Responses.json({ data: safeProcess });
|
||||||
|
},
|
||||||
|
|
||||||
|
"/api/health": () => Backend.Responses.ok(),
|
||||||
|
|
||||||
|
"/api/ws": async (req, server) => {
|
||||||
|
if (!server.upgrade(req)) {
|
||||||
|
await Backend.postAnalytics(req, server);
|
||||||
|
return Response.redirect("/");
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
"/api/gc": async () => {
|
||||||
|
gc(true);
|
||||||
|
return Backend.Responses.ok();
|
||||||
|
},
|
||||||
|
|
||||||
|
"/api/headers": (req) => Backend.Responses.json(req.headers.toJSON()),
|
||||||
|
},
|
||||||
|
|
||||||
|
fetch: async (req, server) => {
|
||||||
|
await Backend.postAnalytics(req, server);
|
||||||
|
return Response.redirect("/");
|
||||||
|
},
|
||||||
|
|
||||||
|
websocket: {
|
||||||
|
idleTimeout: 1,
|
||||||
|
open: (ws) => {
|
||||||
|
ws.subscribe("lanyard");
|
||||||
|
ws.send(JSON.stringify({ type: "lanyard", data: lanyard }), true);
|
||||||
|
|
||||||
|
ws.subscribe("hyperate");
|
||||||
|
ws.send(
|
||||||
|
JSON.stringify({ type: "hyperate", data: { hr: heartrate } }),
|
||||||
|
true,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
message: (ws, msg) => {
|
||||||
|
ws.send(JSON.stringify({ type: "echo", data: msg }), true);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
new Backend.Sockets.Hyperate((data) => {
|
||||||
|
heartrate = data;
|
||||||
|
server.publish(
|
||||||
|
"hyperate",
|
||||||
|
JSON.stringify({ type: "hyperate", data: { hr: heartrate } }),
|
||||||
|
true,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
new Backend.Sockets.Lanyard((data) => {
|
||||||
|
lanyard = data;
|
||||||
|
server.publish(
|
||||||
|
"lanyard",
|
||||||
|
JSON.stringify({ type: "lanyard", data: lanyard }),
|
||||||
|
true,
|
||||||
|
);
|
||||||
|
});
|
|
@ -21,6 +21,7 @@
|
||||||
// Some stricter flags (disabled by default)
|
// Some stricter flags (disabled by default)
|
||||||
"noUnusedLocals": false,
|
"noUnusedLocals": false,
|
||||||
"noUnusedParameters": false,
|
"noUnusedParameters": false,
|
||||||
"noPropertyAccessFromIndexSignature": false
|
"noPropertyAccessFromIndexSignature": false,
|
||||||
|
"typeRoots": ["./types"]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
13
types/lanyard.d.ts
vendored
Normal file
13
types/lanyard.d.ts
vendored
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
type LanyardActivity = {
|
||||||
|
type: number;
|
||||||
|
name: string;
|
||||||
|
details?: string;
|
||||||
|
state?: string;
|
||||||
|
[key: string]: unknown;
|
||||||
|
};
|
||||||
|
|
||||||
|
type LanyardData = {
|
||||||
|
discord_status: "online" | "idle" | "dnd" | "offline";
|
||||||
|
activities: LanyardActivity[];
|
||||||
|
[key: string]: unknown;
|
||||||
|
};
|
Loading…
Add table
Reference in a new issue