summary refs log tree commit diff
path: root/src/webrtc
diff options
context:
space:
mode:
authorRory& <root@rory.gay>2026-08-15 17:09:40 +0200
committerRory& <root@rory.gay>2026-08-18 12:16:45 +0200
commit6b673a2837153edf8995ea482f2ef0ad3f69efde (patch)
tree4203871a916b0c7608dfe58587f6f5ecc9ba2f37 /src/webrtc
parentFix logout api (diff)
downloadserver-ts-dev/gwsep.tar.xz
Decouple gateway connection state from inner ws object dev/gwsep
Diffstat (limited to 'src/webrtc')
-rw-r--r--src/webrtc/events/Close.ts4
-rw-r--r--src/webrtc/events/Connection.ts15
-rw-r--r--src/webrtc/events/Message.ts6
-rw-r--r--src/webrtc/opcodes/Heartbeat.ts2
-rw-r--r--src/webrtc/opcodes/Identify.ts8
-rw-r--r--src/webrtc/opcodes/SelectProtocol.ts3
-rw-r--r--src/webrtc/util/Send.ts24
-rw-r--r--src/webrtc/util/WebRtcWebSocket.ts2
8 files changed, 42 insertions, 22 deletions
diff --git a/src/webrtc/events/Close.ts b/src/webrtc/events/Close.ts

index e88b29380..bf2b4e22a 100644 --- a/src/webrtc/events/Close.ts +++ b/src/webrtc/events/Close.ts
@@ -18,8 +18,8 @@ import { WebSocket } from "@spacebar/gateway"; -export async function onClose(this: WebSocket, code: number, reason: string) { +export async function onClose(socket: WebSocket, code: number, reason: Buffer) { console.log("[WebRTC] closed", code, reason.toString()); - this.removeAllListeners(); + socket.rawSocket.removeAllListeners(); } diff --git a/src/webrtc/events/Connection.ts b/src/webrtc/events/Connection.ts
index f18083999..2949ea75f 100644 --- a/src/webrtc/events/Connection.ts +++ b/src/webrtc/events/Connection.ts
@@ -28,10 +28,11 @@ import { onMessage } from "./Message"; // TODO: specify rate limit in config // TODO: check msg max size -export async function Connection(this: WS.Server, socket: WebRtcWebSocket, request: IncomingMessage) { +export async function Connection(this: WS.Server, rawSocket: WS, request: IncomingMessage) { + const socket = new WebRtcWebSocket(rawSocket); try { - socket.on("close", onClose.bind(socket)); - socket.on("message", onMessage.bind(socket)); + socket.rawSocket.on("close", (code, reason) => onClose(socket, code, reason)); + socket.rawSocket.on("message", (data, isBinary) => onMessage(socket, data as Buffer)); console.log("[WebRTC] new connection", request.url); if (process.env.WS_LOGEVENTS) { @@ -45,7 +46,7 @@ export async function Connection(this: WS.Server, socket: WebRtcWebSocket, reque "pong", "unexpected-response", ].forEach((x) => { - socket.on(x, (y) => console.log("[WebRTC]", x, y)); + socket.rawSocket.on(x, (y) => console.log("[WebRTC]", x, y)); }); } @@ -53,11 +54,11 @@ export async function Connection(this: WS.Server, socket: WebRtcWebSocket, reque socket.encoding = "json"; socket.version = Number(searchParams.get("v")) || 5; - if (socket.version < 3) return socket.close(CLOSECODES.Unknown_error, "invalid version"); + if (socket.version < 3) return socket.rawSocket.close(CLOSECODES.Unknown_error, "invalid version"); setHeartbeat(socket); - socket.readyTimeout = setTimeout(() => socket.close(CLOSECODES.Session_timed_out), 1000 * 30); + socket.readyTimeout = setTimeout(() => socket.rawSocket.close(CLOSECODES.Session_timed_out), 1000 * 30); await Send(socket, { op: VoiceOPCodes.HELLO, @@ -67,6 +68,6 @@ export async function Connection(this: WS.Server, socket: WebRtcWebSocket, reque }); } catch (error) { console.error("[WebRTC]", error); - return socket.close(CLOSECODES.Unknown_error); + return socket.rawSocket.close(CLOSECODES.Unknown_error); } } diff --git a/src/webrtc/events/Message.ts b/src/webrtc/events/Message.ts
index b5455d977..0ec2108af 100644 --- a/src/webrtc/events/Message.ts +++ b/src/webrtc/events/Message.ts
@@ -20,10 +20,10 @@ import { CLOSECODES } from "@spacebar/gateway"; import OPCodeHandlers from "../opcodes"; import { VoiceOPCodes, VoicePayload, WebRtcWebSocket } from "../util"; -export async function onMessage(this: WebRtcWebSocket, buffer: Buffer) { +export async function onMessage(socket: WebRtcWebSocket, buffer: Buffer) { try { const data: VoicePayload = JSON.parse(buffer.toString()); - if (data.op !== VoiceOPCodes.IDENTIFY && !this.user_id) return this.close(CLOSECODES.Not_authenticated); + if (data.op !== VoiceOPCodes.IDENTIFY && !socket.user_id) return socket.rawSocket.close(CLOSECODES.Not_authenticated); const OPCodeHandler = OPCodeHandlers[data.op]; if (!OPCodeHandler) { @@ -37,7 +37,7 @@ export async function onMessage(this: WebRtcWebSocket, buffer: Buffer) { console.log("[WebRTC] Opcode " + VoiceOPCodes[data.op]); } - return await OPCodeHandler.call(this, data); + return await OPCodeHandler.call(socket, data); } catch (error) { console.error("[WebRTC] error", error); // if (!this.CLOSED && this.CLOSING) return this.close(CloseCodes.Unknown_error); diff --git a/src/webrtc/opcodes/Heartbeat.ts b/src/webrtc/opcodes/Heartbeat.ts
index ee0e72b32..8e38a11aa 100644 --- a/src/webrtc/opcodes/Heartbeat.ts +++ b/src/webrtc/opcodes/Heartbeat.ts
@@ -21,7 +21,7 @@ import { VoiceOPCodes, VoicePayload, WebRtcWebSocket, Send } from "../util"; export async function onHeartbeat(this: WebRtcWebSocket, data: VoicePayload) { setHeartbeat(this); - if (isNaN(data.d)) return this.close(CLOSECODES.Decode_error); + if (isNaN(data.d)) return this.rawSocket.close(CLOSECODES.Decode_error); await Send(this, { op: VoiceOPCodes.HEARTBEAT_ACK, d: data.d }); } diff --git a/src/webrtc/opcodes/Identify.ts b/src/webrtc/opcodes/Identify.ts
index 7d776d9cf..fdf5f4493 100644 --- a/src/webrtc/opcodes/Identify.ts +++ b/src/webrtc/opcodes/Identify.ts
@@ -64,14 +64,14 @@ export async function onIdentify(this: WebRtcWebSocket, data: VoicePayload) { streamSession.used = true; await streamSession.save(); - this.once("close", async () => { + this.rawSocket.once("close", async () => { await streamSession.remove(); }); } } // if it doesnt match any then not valid token - if (!authenticated) return this.close(CLOSECODES.Authentication_failed); + if (!authenticated) return this.rawSocket.close(CLOSECODES.Authentication_failed); this.user_id = user_id; this.session_id = session_id; @@ -82,10 +82,10 @@ export async function onIdentify(this: WebRtcWebSocket, data: VoicePayload) { try { this.webRtcClient = await mediaServer.join(voiceRoomId, this.user_id, this, type!); } catch (e) { - return this.close(4013); + return this.rawSocket.close(4013); } - this.on("close", () => { + this.rawSocket.on("close", () => { // ice-lite media server relies on this to know when the peer went away mediaServer.onClientClose(this.webRtcClient!); }); diff --git a/src/webrtc/opcodes/SelectProtocol.ts b/src/webrtc/opcodes/SelectProtocol.ts
index 6a7339322..c3b61554b 100644 --- a/src/webrtc/opcodes/SelectProtocol.ts +++ b/src/webrtc/opcodes/SelectProtocol.ts
@@ -15,6 +15,7 @@ You should have received a copy of the GNU Affero General Public License along with this program. If not, see <https://www.gnu.org/licenses/>. */ + import { SelectProtocolSchema, validateSchema } from "@spacebar/schemas"; import { VoiceOPCodes, VoicePayload, WebRtcWebSocket, mediaServer, Send } from "@spacebar/webrtc"; @@ -24,7 +25,7 @@ export async function onSelectProtocol(this: WebRtcWebSocket, payload: VoicePayl const data = validateSchema("SelectProtocolSchema", payload.d) as SelectProtocolSchema; // UDP protocol not currently supported. Maybe in the future? - if (data.protocol !== "webrtc") return this.close(4000, "only webrtc protocol supported currently"); + if (data.protocol !== "webrtc") return this.rawSocket.close(4000, "only webrtc protocol supported currently"); const response = await mediaServer.onOffer(this.webRtcClient, data.sdp!, data.codecs ?? []); diff --git a/src/webrtc/util/Send.ts b/src/webrtc/util/Send.ts
index 1d8aa61e4..c3f47bae0 100644 --- a/src/webrtc/util/Send.ts +++ b/src/webrtc/util/Send.ts
@@ -1,3 +1,21 @@ +/* + Spacebar: A FOSS re-implementation and extension of the Discord.com backend. + Copyright (C) 2025 Spacebar and Spacebar Contributors + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published + by the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ + import { JSONReplacer } from "@spacebar/util"; import { VoicePayload } from "./Constants"; import { WebRtcWebSocket } from "./WebRtcWebSocket"; @@ -12,13 +30,13 @@ export function Send(socket: WebRtcWebSocket, data: VoicePayload) { else return; return new Promise((res, rej) => { - if (socket.readyState !== 1) { + if (socket.rawSocket.readyState !== 1) { // return rej("socket not open"); - socket.close(); + socket.rawSocket.close(); return; } - socket.send(buffer, (err) => { + socket.rawSocket.send(buffer, (err) => { if (err) return rej(err); return res(null); }); diff --git a/src/webrtc/util/WebRtcWebSocket.ts b/src/webrtc/util/WebRtcWebSocket.ts
index e36b4f1dc..8d07dfdfb 100644 --- a/src/webrtc/util/WebRtcWebSocket.ts +++ b/src/webrtc/util/WebRtcWebSocket.ts
@@ -1,7 +1,7 @@ import { WebSocket } from "@spacebar/gateway"; import type { WebRtcClient } from "@spacebarchat/spacebar-webrtc-types"; -export interface WebRtcWebSocket extends WebSocket { +export class WebRtcWebSocket extends WebSocket { type: "guild-voice" | "dm-voice" | "stream"; webRtcClient?: WebRtcClient<WebRtcWebSocket>; }