summary refs log tree commit diff
path: root/gateway/src/util
diff options
context:
space:
mode:
authorFlam3rboy <34555296+Flam3rboy@users.noreply.github.com>2021-08-12 20:18:05 +0200
committerFlam3rboy <34555296+Flam3rboy@users.noreply.github.com>2021-08-12 20:18:05 +0200
commitd24348ef0f53c80ad618056c45eda6c147525133 (patch)
tree7cf427eb871c2127aef1fdd6c9659452415cd0d6 /gateway/src/util
parentMerge branch 'master' into gateway (diff)
downloadserver-d24348ef0f53c80ad618056c45eda6c147525133.tar.xz
:sparkles: gateway
Diffstat (limited to 'gateway/src/util')
-rw-r--r--gateway/src/util/Config.ts41
-rw-r--r--gateway/src/util/Constants.ts50
-rw-r--r--gateway/src/util/Send.ts28
-rw-r--r--gateway/src/util/WebSocket.ts23
-rw-r--r--gateway/src/util/setHeartbeat.ts11
5 files changed, 153 insertions, 0 deletions
diff --git a/gateway/src/util/Config.ts b/gateway/src/util/Config.ts
new file mode 100644
index 00000000..9ceb8cd5
--- /dev/null
+++ b/gateway/src/util/Config.ts
@@ -0,0 +1,41 @@
+// @ts-nocheck
+import { Config } from "@fosscord/server-util";
+import { getConfigPathForFile } from "@fosscord/server-util/dist/util/Config";
+import Ajv, { JSONSchemaType } from "ajv";
+
+export interface DefaultOptions {
+	endpoint?: string;
+	security: {
+		jwtSecret: string;
+	};
+}
+
+const schema: JSONSchemaType<DefaultOptions> = {
+	type: "object",
+	properties: {
+		endpoint: {
+			type: "string",
+			nullable: true,
+		},
+		security: {
+			type: "object",
+			properties: {
+				jwtSecret: {
+					type: "string",
+				},
+			},
+			required: ["jwtSecret"],
+		},
+	},
+	required: ["security"],
+};
+
+const ajv = new Ajv();
+const validator = ajv.compile(schema);
+
+const configPath = getConfigPathForFile("fosscord", "gateway", ".json");
+export const gatewayConfig = new Config<DefaultOptions>({
+	path: configPath,
+	schemaValidator: validator,
+	schema: schema,
+});
diff --git a/gateway/src/util/Constants.ts b/gateway/src/util/Constants.ts
new file mode 100644
index 00000000..692f9028
--- /dev/null
+++ b/gateway/src/util/Constants.ts
@@ -0,0 +1,50 @@
+export enum OPCODES {
+	Dispatch = 0,
+	Heartbeat = 1,
+	Identify = 2,
+	Presence_Update = 3,
+	Voice_State_Update = 4,
+	Voice_Server_Ping = 5, // ? What is opcode 5?
+	Resume = 6,
+	Reconnect = 7,
+	Request_Guild_Members = 8,
+	Invalid_Session = 9,
+	Hello = 10,
+	Heartbeat_ACK = 11,
+	Guild_Sync = 12,
+	DM_Update = 13,
+	Lazy_Request = 14,
+	Lobby_Connect = 15,
+	Lobby_Disconnect = 16,
+	Lobby_Voice_States_Update = 17,
+	Stream_Create = 18,
+	Stream_Delete = 19,
+	Stream_Watch = 20,
+	Stream_Ping = 21,
+	Stream_Set_Paused = 22,
+	Request_Application_Commands = 24,
+}
+export enum CLOSECODES {
+	Unknown_error = 4000,
+	Unknown_opcode,
+	Decode_error,
+	Not_authenticated,
+	Authentication_failed,
+	Already_authenticated,
+	Invalid_session,
+	Invalid_seq,
+	Rate_limited,
+	Session_timed_out,
+	Invalid_shard,
+	Sharding_required,
+	Invalid_API_version,
+	Invalid_intent,
+	Disallowed_intent,
+}
+
+export interface Payload {
+	op: OPCODES;
+	d?: any;
+	s?: number;
+	t?: string;
+}
diff --git a/gateway/src/util/Send.ts b/gateway/src/util/Send.ts
new file mode 100644
index 00000000..be25ac4f
--- /dev/null
+++ b/gateway/src/util/Send.ts
@@ -0,0 +1,28 @@
+var erlpack: any;
+try {
+	erlpack = require("erlpack");
+} catch (error) {}
+import { Payload } from "../util/Constants";
+
+import WebSocket from "./WebSocket";
+
+export async function Send(socket: WebSocket, data: Payload) {
+	let buffer: Buffer | string;
+	if (socket.encoding === "etf") buffer = erlpack.pack(data);
+	// TODO: encode circular object
+	else if (socket.encoding === "json") buffer = JSON.stringify(data);
+	else return;
+	// TODO: compression
+	if (socket.deflate) {
+		socket.deflate.write(buffer);
+		socket.deflate.flush();
+		return;
+	}
+
+	return new Promise((res, rej) => {
+		socket.send(buffer, (err) => {
+			if (err) return rej(err);
+			return res(null);
+		});
+	});
+}
diff --git a/gateway/src/util/WebSocket.ts b/gateway/src/util/WebSocket.ts
new file mode 100644
index 00000000..1bd0ff2f
--- /dev/null
+++ b/gateway/src/util/WebSocket.ts
@@ -0,0 +1,23 @@
+import { Intents, Permissions } from "@fosscord/server-util";
+import WS, { Server, Data } from "ws";
+import { Deflate } from "zlib";
+import { Channel } from "amqplib";
+
+interface WebSocket extends WS {
+	version: number;
+	user_id: string;
+	encoding: "etf" | "json";
+	compress?: "zlib-stream";
+	shard_count?: bigint;
+	shard_id?: bigint;
+	deflate?: Deflate;
+	heartbeatTimeout: NodeJS.Timeout;
+	readyTimeout: NodeJS.Timeout;
+	intents: Intents;
+	sequence: number;
+	rabbitCh?: Channel & { queues: Record<string, string> };
+	permissions: Record<string, Permissions>;
+}
+
+export default WebSocket;
+export { Server, Data };
diff --git a/gateway/src/util/setHeartbeat.ts b/gateway/src/util/setHeartbeat.ts
new file mode 100644
index 00000000..9f88b481
--- /dev/null
+++ b/gateway/src/util/setHeartbeat.ts
@@ -0,0 +1,11 @@
+import { CLOSECODES } from "./Constants";
+import WebSocket from "./WebSocket";
+
+// TODO: make heartbeat timeout configurable
+export function setHeartbeat(socket: WebSocket) {
+	if (socket.heartbeatTimeout) clearTimeout(socket.heartbeatTimeout);
+
+	socket.heartbeatTimeout = setTimeout(() => {
+		return socket.close(CLOSECODES.Session_timed_out);
+	}, 1000 * 45);
+}