armcord/src/arrpc/src/transports/websocket.js

131 lines
3.6 KiB
JavaScript

const rgb = (r, g, b, msg) => `\x1b[38;2;${r};${g};${b}m${msg}\x1b[0m`;
const log = (...args) => console.log(`[${rgb(88, 101, 242, "arRPC")} > ${rgb(235, 69, 158, "websocket")}]`, ...args);
const {WebSocketServer} = require("ws");
const {createServer} = require("http");
const {parse} = require("querystring");
const portRange = [6463, 6472]; // ports available/possible: 6463-6472
class WSServer {
constructor(handlers) {
return (async () => {
this.handlers = handlers;
this.onConnection = this.onConnection.bind(this);
this.onMessage = this.onMessage.bind(this);
let port = portRange[0];
let http, wss;
while (port <= portRange[1]) {
log("trying port", port);
if (
await new Promise((res) => {
http = createServer();
http.on("error", (e) => {
// log('http error', e);
if (e.code === "EADDRINUSE") {
log(port, "in use!");
res(false);
}
});
wss = new WebSocketServer({server: http});
wss.on("error", (e) => {
// log('wss error', e);
});
wss.on("connection", this.onConnection);
http.listen(port, "127.0.0.1", () => {
log("listening on", port);
this.http = http;
this.wss = wss;
res(true);
});
})
)
break;
port++;
}
return this;
})();
}
onConnection(socket, req) {
const params = parse(req.url.split("?")[1]);
const ver = parseInt(params.v ?? 1);
const encoding = params.encoding ?? "json"; // json | etf (erlpack)
const clientId = params.client_id ?? "";
const origin = req.headers.origin ?? "";
log(`new connection! origin:`, origin, JSON.parse(JSON.stringify(params)));
if (
origin !== "" &&
!["https://discord.com", "https://ptb.discord.com", "https://canary.discord.com/"].includes(origin)
) {
log("disallowed origin", origin);
socket.close();
return;
}
if (encoding !== "json") {
log("unsupported encoding requested", encoding);
socket.close();
return;
}
if (ver !== 1) {
log("unsupported version requested", ver);
socket.close();
return;
}
/* if (clientId === '') {
log('client id required');
socket.close();
return;
} */
socket.clientId = clientId;
socket.encoding = encoding;
socket.on("error", (e) => {
log("socket error", e);
});
socket.on("close", (e, r) => {
log("socket closed", e, r);
this.handlers.close(socket);
});
socket.on("message", this.onMessage.bind(this, socket));
socket._send = socket.send;
socket.send = (msg) => {
log("sending", msg);
socket._send(JSON.stringify(msg));
};
this.handlers.connection(socket);
}
onMessage(socket, msg) {
log("message", JSON.parse(msg));
this.handlers.message(socket, JSON.parse(msg));
}
}
module.exports = {WSServer};