summary refs log tree commit diff
path: root/src/events
diff options
context:
space:
mode:
authorFlam3rboy <34555296+Flam3rboy@users.noreply.github.com>2021-02-06 17:08:08 +0100
committerFlam3rboy <34555296+Flam3rboy@users.noreply.github.com>2021-02-06 17:08:08 +0100
commit471d1d6b28f8a6b62680408756e389e8a0b71be0 (patch)
treef95518dd3e846734feaeee613aa3f37f43dcde62 /src/events
parentuntrack DS_Store (diff)
downloadserver-471d1d6b28f8a6b62680408756e389e8a0b71be0.tar.xz
:sparkles: Base Server
Diffstat (limited to 'src/events')
-rw-r--r--src/events/Close.ts6
-rw-r--r--src/events/Connection.ts46
-rw-r--r--src/events/Message.ts36
3 files changed, 88 insertions, 0 deletions
diff --git a/src/events/Close.ts b/src/events/Close.ts
new file mode 100644

index 00000000..f819b064 --- /dev/null +++ b/src/events/Close.ts
@@ -0,0 +1,6 @@ +import WebSocket from "ws"; +import { Message } from "./Message"; + +export function Close(this: WebSocket, code: number, reason: string) { + this.off("message", Message); +} diff --git a/src/events/Connection.ts b/src/events/Connection.ts new file mode 100644
index 00000000..815d84cf --- /dev/null +++ b/src/events/Connection.ts
@@ -0,0 +1,46 @@ +import WebSocket, { Server } from "../util/WebSocket"; +import { IncomingMessage } from "http"; +import { Close } from "./Close"; +import { Message } from "./Message"; +import { setHeartbeat } from "../util/setHeartbeat"; +import { Send } from "../util/Send"; +import { CLOSECODES, OPCODES } from "../util/Constants"; + +// TODO: check rate limit +// TODO: specify rate limit in config + +export function Connection(this: Server, socket: WebSocket, request: IncomingMessage) { + try { + socket.on("close", Close); + socket.on("message", Message); + + const { searchParams } = new URL(`http://localhost${request.url}`); + // @ts-ignore + socket.encoding = searchParams.get("encoding") || "json"; + if (!["json", "etf"].includes(socket.encoding)) return socket.close(CLOSECODES.Decode_error); + + // @ts-ignore + socket.version = Number(searchParams.get("version")) || 8; + if (socket.version != 8) return socket.close(CLOSECODES.Invalid_API_version); + + // @ts-ignore + socket.compression = searchParams.get("compress") || ""; + // TODO: compression + + setHeartbeat(socket); + + Send(socket, { + op: OPCODES.Hello, + d: { + heartbeat_interval: 1000 * 30, + }, + }); + + socket.readyTimeout = setTimeout(() => { + return socket.close(CLOSECODES.Session_timed_out); + }, 1000 * 30); + } catch (error) { + console.error(error); + return socket.close(CLOSECODES.Unknown_error); + } +} diff --git a/src/events/Message.ts b/src/events/Message.ts new file mode 100644
index 00000000..bc497e94 --- /dev/null +++ b/src/events/Message.ts
@@ -0,0 +1,36 @@ +import WebSocket, { Data } from "../util/WebSocket"; +import erlpack from "erlpack"; +import OPCodeHandlers from "../opcodes"; +import { Payload, CLOSECODES } from "../util/Constants"; +import { instanceOf } from "lambert-server"; + +const PayloadSchema = { + op: Number, + $d: Object, + $s: Number, + $t: String, +}; + +export async function Message(this: WebSocket, buffer: Data) { + // TODO: compression + var data: Payload; + + try { + if (this.encoding === "etf" && buffer instanceof Buffer) data = erlpack.unpack(buffer); + else if (this.encoding === "json" && typeof buffer === "string") data = JSON.parse(buffer); + if (!instanceOf(PayloadSchema, data)) throw "invalid data"; + } catch (error) { + return this.close(CLOSECODES.Decode_error); + } + + // @ts-ignore + const OPCodeHandler = OPCodeHandlers[data.op]; + if (!OPCodeHandler) return this.close(CLOSECODES.Unknown_opcode); + + try { + return await OPCodeHandler.call(this, data); + } catch (error) { + console.error(error); + return this.close(CLOSECODES.Unknown_error); + } +}