import { websocket, http, authenication } from "figura"; import { createServer } from "http"; import { pack_image } from "./lib/pack.js"; import { imageToJson } from "./lib/image2json.js"; import "dotenv/config"; let [___, token] = await authenication.getToken(); if (!(await http.checkAuth(token))) { await authenication.invalidateCache(); let [u, t] = await authenication.getToken(); uuid = u; token = t; } const ws = new websocket.WebsocketClient("wss://" + http.host + "/ws"); ws.addListener("connect", () => { console.log("[WS] WS connection made"); }); ws.addListener("auth", () => { console.log("[WS] WS successfully authenticated!"); ["21f7143a-45cd-4995-b1e3-6c3c8602ef7c"].forEach((z) => { ws.sub(z); }); }); function sendChunkedResponse(url, status, body) { if (body.length <= 600) { ws.ping(true, "httpResponse", [{ url, status, body }]); } else { const parts = []; for (let i = 0; i < body.length; i += 600) { parts.push(body.slice(i, i + 600)); } const amount = parts.length; ws.ping(true, "httpResponse", [{ url, status, body_amount: amount }]); parts.forEach((chunk, index) => { setTimeout( () => { ws.ping(true, "httpResponse", [ { url, status, body_id: index + 1, body_text: chunk }, ]); }, 1600 * (index + 1), ); }); } } function sendChunkedImageResponse(url, status, imageBuffer) { const CHUNK_SIZE = 600; if (status !== 200 || !imageBuffer) { ws.ping(true, "imageResponse", [{ url, status }]); return; } const totalLength = imageBuffer.length || imageBuffer.byteLength; if (totalLength <= CHUNK_SIZE) { ws.ping(true, "imageResponse", [ { url, status, image: Buffer.from(imageBuffer).toString("base64") }, ]); } else { const parts = []; for (let i = 0; i < totalLength; i += CHUNK_SIZE) { const chunk = Buffer.from(imageBuffer).slice(i, i + CHUNK_SIZE); parts.push(chunk.toString("base64")); } const amount = parts.length; ws.ping(true, "imageResponse", [{ url, status, image_amount: amount }]); parts.forEach((chunk, index) => { setTimeout( () => { ws.ping(true, "imageResponse", [ { url, status, image_id: index + 1, image_chunk: chunk }, ]); }, 1600 * (index + 1), ); }); } } ws.addListener("ping", async (id, uuid, args) => { try { if (id === http.hashFiguraString("httpGet")) { const url = args[0]; const res = await fetch(url); const text = await res.text(); sendChunkedResponse(url, res.status, text); } if (id === http.hashFiguraString("httpPost")) { const [url, payload] = args; const res = await fetch(url, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify(payload), }); const text = await res.text(); sendChunkedResponse(url, res.status, text); } } catch (err) { ws.ping(true, "httpResponse", [{ error: err.message }]); } try { if (id === http.hashFiguraString("evilAssImageGet")) { let [url, width, height] = args; const res = await fetch(url); if (!res.ok) { ws.ping(true, "imageResponse", [{ url, status: res.status }]); return; } const blob = await res.blob(); const arrayBuffer = await blob.arrayBuffer(); const imageJson = await imageToJson(new Uint8Array(arrayBuffer), { width: 20, height: 20, keepRatio: false, }); const packedImage = pack_image(imageJson.json); sendChunkedImageResponse(url, 200, packedImage.toString("utf8")); } } catch (err) { ws.ping(true, "imageResponse", [{ error: err.toString().slice(0, 256) }]); } }); ws.connect(); const server = createServer(async (req, res) => { if (req.method === "POST" && req.url === "/data") { const authHeader = req.headers["authorization"]; if (!authHeader || !authHeader.startsWith("Bearer ")) { res.writeHead(401, { "Content-Type": "application/json" }); res.end(JSON.stringify({ error: "Missing or invalid auth header" })); return; } const token = authHeader.substring("Bearer ".length).trim(); if (token !== process.env.PASSWORD) { res.writeHead(403, { "Content-Type": "application/json" }); res.end(JSON.stringify({ error: "Forbidden" })); return; } let body = ""; req.on("data", (chunk) => (body += chunk)); req.on("end", () => { try { const json = JSON.parse(body); ws.ping(true, "data", [json]); res.writeHead(200, { "Content-Type": "application/json" }); res.end(JSON.stringify({ ok: true })); } catch { res.writeHead(400, { "Content-Type": "application/json" }); res.end(JSON.stringify({ error: "Invalid JSON" })); } }); } else { res.writeHead(404, { "Content-Type": "application/json" }); res.end(JSON.stringify({ error: "Not found" })); } }); server.listen(+process.env.PORT, process.env.HOST, () => { console.log( `[HTTP] Listening on http://${process.env.HOST}:${process.env.PORT} (POST /data)`, ); console.log( `[HTTP] Use header: Authorization: Bearer ${process.env.PASSWORD}`, ); });