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>;
}
|