Download client-services/ace-controller/node_ws_shim.mjs from AIBRUH/miranda-engine: direct link, hf CLI and curl.
- Browser
- Download file 4.95 kB
-
https://huggingface.co/AIBRUH/miranda-engine/resolve/main/client-services/ace-controller/node_ws_shim.mjs
- Command line
-
hf download hf://AIBRUH/miranda-engine/client-services/ace-controller/node_ws_shim.mjs
-
curl -L -o node_ws_shim.mjs https://huggingface.co/AIBRUH/miranda-engine/resolve/main/client-services/ace-controller/node_ws_shim.mjs
4.95 kB
| /** | |
| * Minimal WebSocket server using only Node built-ins (no ws package required). | |
| * Implements enough of RFC6455 for JSON text frames used by EVE ECC. | |
| */ | |
| import { createHash, randomBytes } from "node:crypto"; | |
| import { EventEmitter } from "node:events"; | |
| const GUID = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"; | |
| function acceptKey(key) { | |
| return createHash("sha1").update(key + GUID).digest("base64"); | |
| } | |
| /** Build a single-frame WS header for the given opcode + payload length. */ | |
| function encodeFrame(opcode, payload) { | |
| const len = payload.length; | |
| let header; | |
| if (len < 126) { | |
| header = Buffer.alloc(2); | |
| header[0] = 0x80 | opcode; | |
| header[1] = len; | |
| } else if (len < 65536) { | |
| header = Buffer.alloc(4); | |
| header[0] = 0x80 | opcode; | |
| header[1] = 126; | |
| header.writeUInt16BE(len, 2); | |
| } else { | |
| header = Buffer.alloc(10); | |
| header[0] = 0x80 | opcode; | |
| header[1] = 127; | |
| header.writeBigUInt64BE(BigInt(len), 2); | |
| } | |
| return Buffer.concat([header, payload]); | |
| } | |
| function encodeText(str) { | |
| return encodeFrame(0x1, Buffer.from(str, "utf8")); | |
| } | |
| function encodeBinary(buf) { | |
| return encodeFrame(0x2, buf); | |
| } | |
| function decodeFrames(buffer) { | |
| const messages = []; | |
| let offset = 0; | |
| while (offset + 2 <= buffer.length) { | |
| const b0 = buffer[offset]; | |
| const b1 = buffer[offset + 1]; | |
| const opcode = b0 & 0x0f; | |
| const masked = (b1 & 0x80) !== 0; | |
| let len = b1 & 0x7f; | |
| let pos = offset + 2; | |
| if (len === 126) { | |
| if (pos + 2 > buffer.length) break; | |
| len = buffer.readUInt16BE(pos); | |
| pos += 2; | |
| } else if (len === 127) { | |
| if (pos + 8 > buffer.length) break; | |
| len = Number(buffer.readBigUInt64BE(pos)); | |
| pos += 8; | |
| } | |
| const maskLen = masked ? 4 : 0; | |
| if (pos + maskLen + len > buffer.length) break; | |
| let payload = buffer.subarray(pos + maskLen, pos + maskLen + len); | |
| if (masked) { | |
| const mask = buffer.subarray(pos, pos + 4); | |
| payload = Buffer.from(payload.map((b, i) => b ^ mask[i % 4])); | |
| } | |
| offset = pos + maskLen + len; | |
| if (opcode === 0x8) { | |
| messages.push({ type: "close" }); | |
| } else if (opcode === 0x9) { | |
| messages.push({ type: "ping", data: payload }); | |
| } else if (opcode === 0x1) { | |
| messages.push({ type: "text", data: payload.toString("utf8") }); | |
| } else if (opcode === 0x2) { | |
| // Binary frame — WO-2 T2 uses this for raw PCM audio from the browser. | |
| // Copy out of the shared read buffer since `payload` is a subarray | |
| // view that gets sliced/reused as more data arrives. | |
| messages.push({ type: "binary", data: Buffer.from(payload) }); | |
| } | |
| } | |
| return { messages, rest: buffer.subarray(offset) }; | |
| } | |
| export class WebSocket extends EventEmitter { | |
| constructor(socket) { | |
| super(); | |
| this.socket = socket; | |
| this.readyState = 1; // OPEN | |
| this._buf = Buffer.alloc(0); | |
| socket.on("data", (chunk) => { | |
| this._buf = Buffer.concat([this._buf, chunk]); | |
| const { messages, rest } = decodeFrames(this._buf); | |
| this._buf = rest; | |
| for (const m of messages) { | |
| if (m.type === "text") this.emit("message", m.data); | |
| if (m.type === "binary") this.emit("binary", m.data); | |
| if (m.type === "close") { | |
| this.readyState = 3; | |
| this.emit("close"); | |
| socket.end(); | |
| } | |
| if (m.type === "ping") { | |
| // pong | |
| const pong = Buffer.concat([Buffer.from([0x8a, m.data.length]), m.data]); | |
| socket.write(pong); | |
| } | |
| } | |
| }); | |
| socket.on("close", () => { | |
| this.readyState = 3; | |
| this.emit("close"); | |
| }); | |
| socket.on("error", (err) => this.emit("error", err)); | |
| } | |
| send(data) { | |
| if (this.readyState !== 1) return; | |
| this.socket.write(encodeText(String(data))); | |
| } | |
| sendBinary(buf) { | |
| if (this.readyState !== 1) return; | |
| this.socket.write(encodeBinary(Buffer.isBuffer(buf) ? buf : Buffer.from(buf))); | |
| } | |
| close() { | |
| this.readyState = 3; | |
| try { | |
| this.socket.end(); | |
| } catch { | |
| /* ignore */ | |
| } | |
| } | |
| } | |
| export class WebSocketServer extends EventEmitter { | |
| constructor({ server, path = "/ws" }) { | |
| super(); | |
| this.path = path; | |
| server.on("upgrade", (req, socket, head) => { | |
| const url = new URL(req.url || "/", "http://localhost"); | |
| if (url.pathname !== this.path) { | |
| socket.destroy(); | |
| return; | |
| } | |
| const key = req.headers["sec-websocket-key"]; | |
| if (!key) { | |
| socket.destroy(); | |
| return; | |
| } | |
| const headers = [ | |
| "HTTP/1.1 101 Switching Protocols", | |
| "Upgrade: websocket", | |
| "Connection: Upgrade", | |
| `Sec-WebSocket-Accept: ${acceptKey(key)}`, | |
| "\r\n", | |
| ].join("\r\n"); | |
| socket.write(headers); | |
| if (head?.length) socket.unshift(head); | |
| const ws = new WebSocket(socket); | |
| this.emit("connection", ws, req); | |
| }); | |
| } | |
| } | |
| export function randomId() { | |
| return randomBytes(6).toString("hex"); | |
| } | |