mirror of
https://github.com/tinyhumansai/openhuman.git
synced 2026-07-28 05:12:33 +00:00
110 lines
2.7 KiB
JavaScript
110 lines
2.7 KiB
JavaScript
import crypto from "node:crypto";
|
|
|
|
export function sendWsFrame(socket, opcode, payload) {
|
|
if (!socket || socket.destroyed) return;
|
|
|
|
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);
|
|
}
|
|
|
|
try {
|
|
socket.write(header);
|
|
socket.write(payload);
|
|
} catch {
|
|
// noop
|
|
}
|
|
}
|
|
|
|
export function sendWsText(socket, text) {
|
|
sendWsFrame(socket, 0x01, Buffer.from(text, "utf-8"));
|
|
}
|
|
|
|
export function acceptWebSocket(req, socket) {
|
|
const key = req.headers["sec-websocket-key"];
|
|
if (!key) {
|
|
socket.destroy();
|
|
return false;
|
|
}
|
|
const acceptKey = crypto
|
|
.createHash("sha1")
|
|
.update(key + "258EAFA5-E914-47DA-95CA-5AB5DC085B11")
|
|
.digest("base64");
|
|
socket.write(
|
|
"HTTP/1.1 101 Switching Protocols\r\n" +
|
|
"Upgrade: websocket\r\n" +
|
|
"Connection: Upgrade\r\n" +
|
|
`Sec-WebSocket-Accept: ${acceptKey}\r\n` +
|
|
"\r\n",
|
|
);
|
|
return true;
|
|
}
|
|
|
|
export function decodeWebSocketFrames(socket, onText) {
|
|
let buffer = Buffer.alloc(0);
|
|
|
|
socket.on("data", (chunk) => {
|
|
buffer = Buffer.concat([buffer, chunk]);
|
|
while (buffer.length >= 2) {
|
|
const firstByte = buffer[0];
|
|
const opcode = firstByte & 0x0f;
|
|
const secondByte = buffer[1];
|
|
const masked = (secondByte & 0x80) !== 0;
|
|
let payloadLen = secondByte & 0x7f;
|
|
let offset = 2;
|
|
|
|
if (payloadLen === 126) {
|
|
if (buffer.length < 4) return;
|
|
payloadLen = buffer.readUInt16BE(2);
|
|
offset = 4;
|
|
} else if (payloadLen === 127) {
|
|
if (buffer.length < 10) return;
|
|
payloadLen = Number(buffer.readBigUInt64BE(2));
|
|
offset = 10;
|
|
}
|
|
|
|
const maskSize = masked ? 4 : 0;
|
|
const totalLen = offset + maskSize + payloadLen;
|
|
if (buffer.length < totalLen) return;
|
|
|
|
let payload = buffer.subarray(offset + maskSize, totalLen);
|
|
if (masked) {
|
|
const mask = buffer.subarray(offset, offset + 4);
|
|
payload = Buffer.from(payload);
|
|
for (let i = 0; i < payload.length; i += 1) {
|
|
payload[i] ^= mask[i % 4];
|
|
}
|
|
}
|
|
|
|
buffer = buffer.subarray(totalLen);
|
|
|
|
if (opcode === 0x08) {
|
|
socket.end();
|
|
return;
|
|
}
|
|
|
|
if (opcode === 0x09) {
|
|
sendWsFrame(socket, 0x0a, payload);
|
|
continue;
|
|
}
|
|
|
|
if (opcode === 0x01) {
|
|
onText(payload.toString("utf-8"));
|
|
}
|
|
}
|
|
});
|
|
}
|