From feca7a5d620362d028c8f31353b0c996693697e3 Mon Sep 17 00:00:00 2001 From: TheArcaneBrony Date: Sat, 27 Aug 2022 07:07:05 +0200 Subject: Merge 'webrtc' into 'dev/staging_webrtc' --- src/Server.ts | 7 +- src/api/util/handlers/Voice.ts | 2 +- src/gateway/Server.ts | 1 + src/gateway/events/Close.ts | 2 +- src/gateway/events/Connection.ts | 22 +- src/gateway/events/Message.ts | 12 +- src/gateway/listener/listener.ts | 6 +- src/gateway/opcodes/Identify.ts | 18 +- src/gateway/opcodes/LazyRequest.ts | 4 +- src/gateway/opcodes/RequestGuildMembers.ts | 2 +- src/gateway/opcodes/Resume.ts | 2 +- src/gateway/opcodes/VoiceStateUpdate.ts | 24 +-- src/gateway/opcodes/instanceOf.ts | 4 +- src/gateway/util/Constants.ts | 69 ++++-- src/gateway/util/Heartbeat.ts | 4 +- src/gateway/util/Send.ts | 2 +- src/gateway/util/WebSocket.ts | 2 + src/util/config/types/RegionConfiguration.ts | 2 +- src/util/entities/Attachment.ts | 6 +- src/util/entities/AuditLog.ts | 7 +- src/util/entities/BackupCodes.ts | 2 +- src/util/entities/Ban.ts | 9 +- src/util/entities/Channel.ts | 21 +- src/util/entities/ConnectedAccount.ts | 5 +- src/util/entities/Emoji.ts | 7 +- src/util/entities/Guild.ts | 52 ++--- src/util/entities/Invite.ts | 6 +- src/util/entities/Member.ts | 10 +- src/util/entities/Message.ts | 24 +-- src/util/entities/Migration.ts | 1 + src/util/entities/Note.ts | 7 +- src/util/entities/RateLimit.ts | 1 + src/util/entities/ReadState.ts | 7 +- src/util/entities/Recipient.ts | 9 +- src/util/entities/Relationship.ts | 7 +- src/util/entities/Role.ts | 5 +- src/util/entities/Session.ts | 2 +- src/util/entities/Sticker.ts | 8 +- src/util/entities/StickerPack.ts | 4 +- src/util/entities/Team.ts | 4 +- src/util/entities/TeamMember.ts | 8 +- src/util/entities/Template.ts | 7 +- src/util/entities/User.ts | 13 +- src/util/entities/VoiceState.ts | 13 +- src/util/entities/Webhook.ts | 13 +- .../mariadb/1660258393551-CodeCleanup3.ts | 231 +++++++++++++++++++++ .../mariadb/1660260587556-CodeCleanup4.ts | 38 ++++ .../mariadb/1660265930624-CodeCleanup5.ts | 52 +++++ src/util/plugin/Plugin.ts | 13 ++ src/util/plugin/PluginLoader.ts | 39 ++++ src/util/plugin/PluginManifest.ts | 9 + src/util/plugin/index.ts | 3 + src/util/schemas/SelectProtocolSchema.ts | 19 ++ src/util/schemas/Validator.ts | 54 +++++ src/util/schemas/VoiceIdentifySchema.ts | 12 ++ src/util/schemas/VoiceVideoSchema.ts | 17 ++ src/util/schemas/index.ts | 4 + src/util/util/Database.ts | 1 + src/util/util/NamingStrategy.ts | 12 ++ src/util/util/imports/TypedEmitter.ts | 41 ++++ src/webrtc/Server.ts | 56 +++++ src/webrtc/events/Close.ts | 9 + src/webrtc/events/Connection.ts | 60 ++++++ src/webrtc/events/Message.ts | 38 ++++ src/webrtc/index.ts | 2 + src/webrtc/opcodes/BackendVersion.ts | 6 + src/webrtc/opcodes/Heartbeat.ts | 9 + src/webrtc/opcodes/Identify.ts | 60 ++++++ src/webrtc/opcodes/SelectProtocol.ts | 44 ++++ src/webrtc/opcodes/Speaking.ts | 22 ++ src/webrtc/opcodes/Video.ts | 117 +++++++++++ src/webrtc/opcodes/index.ts | 19 ++ src/webrtc/start.ts | 13 ++ src/webrtc/util/Constants.ts | 26 +++ src/webrtc/util/MediaServer.ts | 51 +++++ src/webrtc/util/index.ts | 2 + 76 files changed, 1327 insertions(+), 195 deletions(-) create mode 100644 src/util/migrations/mariadb/1660258393551-CodeCleanup3.ts create mode 100644 src/util/migrations/mariadb/1660260587556-CodeCleanup4.ts create mode 100644 src/util/migrations/mariadb/1660265930624-CodeCleanup5.ts create mode 100644 src/util/plugin/Plugin.ts create mode 100644 src/util/plugin/PluginLoader.ts create mode 100644 src/util/plugin/PluginManifest.ts create mode 100644 src/util/plugin/index.ts create mode 100644 src/util/schemas/SelectProtocolSchema.ts create mode 100644 src/util/schemas/Validator.ts create mode 100644 src/util/schemas/VoiceIdentifySchema.ts create mode 100644 src/util/schemas/VoiceVideoSchema.ts create mode 100644 src/util/util/NamingStrategy.ts create mode 100644 src/util/util/imports/TypedEmitter.ts create mode 100644 src/webrtc/Server.ts create mode 100644 src/webrtc/events/Close.ts create mode 100644 src/webrtc/events/Connection.ts create mode 100644 src/webrtc/events/Message.ts create mode 100644 src/webrtc/index.ts create mode 100644 src/webrtc/opcodes/BackendVersion.ts create mode 100644 src/webrtc/opcodes/Heartbeat.ts create mode 100644 src/webrtc/opcodes/Identify.ts create mode 100644 src/webrtc/opcodes/SelectProtocol.ts create mode 100644 src/webrtc/opcodes/Speaking.ts create mode 100644 src/webrtc/opcodes/Video.ts create mode 100644 src/webrtc/opcodes/index.ts create mode 100644 src/webrtc/start.ts create mode 100644 src/webrtc/util/Constants.ts create mode 100644 src/webrtc/util/MediaServer.ts create mode 100644 src/webrtc/util/index.ts (limited to 'src') diff --git a/src/Server.ts b/src/Server.ts index 83e16fa6..f68870d8 100644 --- a/src/Server.ts +++ b/src/Server.ts @@ -5,6 +5,7 @@ import * as Api from "@fosscord/api"; import { CDNServer } from "@fosscord/cdn"; import * as Gateway from "@fosscord/gateway"; import { Config, getOrInitialiseDatabase } from "@fosscord/util"; +import * as WebRTC from "@fosscord/webrtc"; import * as Sentry from "@sentry/node"; import * as Tracing from "@sentry/tracing"; import express from "express"; @@ -18,12 +19,10 @@ const port = Number(process.env.PORT) || 3001; const production = process.env.NODE_ENV == "development" ? false : true; server.on("request", app); -// @ts-ignore const api = new Api.FosscordServer({ server, port, production, app }); -// @ts-ignore const cdn = new CDNServer({ server, port, production, app }); -// @ts-ignore const gateway = new Gateway.Server({ server, port, production }); +const webrtc = new WebRTC.Server({ server, port, production }); //this is what has been added for the /stop API route process.on("SIGTERM", () => { @@ -52,7 +51,7 @@ async function main() { app.use(Sentry.Handlers.requestHandler()); app.use(Sentry.Handlers.tracingHandler()); } - await Promise.all([api.start(), cdn.start(), gateway.start()]); + await Promise.all([api.start(), cdn.start(), gateway.start(), webrtc.start()]); if (Config.get().sentry.enabled) { app.use(Sentry.Handlers.errorHandler()); app.use(function onError(err: any, req: any, res: any, next: any) { diff --git a/src/api/util/handlers/Voice.ts b/src/api/util/handlers/Voice.ts index 4d60eb91..138bd880 100644 --- a/src/api/util/handlers/Voice.ts +++ b/src/api/util/handlers/Voice.ts @@ -13,7 +13,7 @@ export async function getVoiceRegions(ipAddress: string, vip: boolean) { for (let ar of availableRegions) { //TODO the endpoint location should be saved in the database if not already present to prevent IPAnalysis call - const dist = distanceBetweenLocations(clientIpAnalysis, ar.location || (await IPAnalysis(ar.endpoint))); + const dist = distanceBetweenLocations(clientIpAnalysis, ar.location || (await IPAnalysis(ar.endpoint!))); if (dist < min) { min = dist; diff --git a/src/gateway/Server.ts b/src/gateway/Server.ts index 97da3fa0..95fc667a 100644 --- a/src/gateway/Server.ts +++ b/src/gateway/Server.ts @@ -23,6 +23,7 @@ export class Server { } this.server.on("upgrade", (request, socket, head) => { + if (request.url?.includes("voice")) return; // @ts-ignore this.ws.handleUpgrade(request, socket, head, (socket) => { this.ws.emit("connection", socket, request); diff --git a/src/gateway/events/Close.ts b/src/gateway/events/Close.ts index 34831eab..6019ba68 100644 --- a/src/gateway/events/Close.ts +++ b/src/gateway/events/Close.ts @@ -2,7 +2,7 @@ import { WebSocket } from "@fosscord/gateway"; import { emitEvent, PresenceUpdateEvent, PrivateSessionProjection, Session, SessionsReplace, User } from "@fosscord/util"; export async function Close(this: WebSocket, code: number, reason: string) { - console.log("[WebSocket] closed", code, reason); + console.log("[Gateway] closed", code, reason); if (this.heartbeatTimeout) clearTimeout(this.heartbeatTimeout); if (this.readyTimeout) clearTimeout(this.readyTimeout); this.deflate?.close(); diff --git a/src/gateway/events/Connection.ts b/src/gateway/events/Connection.ts index 5a5ce48f..60b479a8 100644 --- a/src/gateway/events/Connection.ts +++ b/src/gateway/events/Connection.ts @@ -3,7 +3,7 @@ import { IncomingMessage } from "http"; import { URL } from "url"; import WS from "ws"; import { createDeflate } from "zlib"; -import { CLOSECODES, OPCODES } from "../util/Constants"; +import { CloseCodes, GatewayOPCodes } from "../util/Constants"; import { setHeartbeat } from "../util/Heartbeat"; import { Send } from "../util/Send"; import { Close } from "./Close"; @@ -35,7 +35,7 @@ export async function Connection(this: WS.Server, socket: WebSocket, request: In "pong", "unexpected-response" ].forEach((x) => { - socket.on(x, (y) => console.log(x, y)); + socket.on(x, (y) => console.log("[Gateway]", x, y)); }); console.log(`[Gateway] Connections: ${this.clients.size}`); @@ -47,17 +47,17 @@ export async function Connection(this: WS.Server, socket: WebSocket, request: In if (socket.encoding === "etf" && erlpack) { throw new Error("Erlpack is not installed: 'npm i @yukikaze-bot/erlpack'"); } - return socket.close(CLOSECODES.Decode_error); + 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); + if (socket.version != 8) return socket.close(CloseCodes.Invalid_API_version); // @ts-ignore socket.compress = searchParams.get("compress") || ""; if (socket.compress) { - if (socket.compress !== "zlib-stream") return socket.close(CLOSECODES.Decode_error); + if (socket.compress !== "zlib-stream") return socket.close(CloseCodes.Decode_error); socket.deflate = createDeflate({ chunkSize: 65535 }); socket.deflate.on("data", (chunk) => socket.send(chunk)); } @@ -69,18 +69,18 @@ export async function Connection(this: WS.Server, socket: WebSocket, request: In setHeartbeat(socket); + socket.readyTimeout = setTimeout(() => { + return socket.close(CloseCodes.Session_timed_out); + }, 1000 * 30); + await Send(socket, { - op: OPCODES.Hello, + op: GatewayOPCodes.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); + return socket.close(CloseCodes.Unknown_error); } } diff --git a/src/gateway/events/Message.ts b/src/gateway/events/Message.ts index 96950a42..e5ee5828 100644 --- a/src/gateway/events/Message.ts +++ b/src/gateway/events/Message.ts @@ -1,7 +1,7 @@ import { Payload, WebSocket } from "@fosscord/gateway"; import OPCodeHandlers from "../opcodes"; import { check } from "../opcodes/instanceOf"; -import { CLOSECODES } from "../util/Constants"; +import { CloseCodes } from "../util/Constants"; let erlpack: any; try { erlpack = require("@yukikaze-bot/erlpack"); @@ -29,13 +29,13 @@ export async function Message(this: WebSocket, buffer: Buffer) { return; } - if (process.env.WS_VERBOSE) console.log(`[Websocket] Incomming message: ${JSON.stringify(data)}`); + if (process.env.WS_VERBOSE) console.log(`[Gateway] Incomming message: ${JSON.stringify(data)}`); if (data.op !== 1) check.call(this, PayloadSchema, data); else { //custom validation for numbers, because heartbeat if (data.s || data.t || (typeof data.d !== "number" && data.d)) { console.log("Invalid heartbeat..."); - this.close(CLOSECODES.Decode_error); + this.close(CloseCodes.Decode_error); } } @@ -44,14 +44,14 @@ export async function Message(this: WebSocket, buffer: Buffer) { if (!OPCodeHandler) { console.error("[Gateway] Unkown opcode " + data.op); // TODO: if all opcodes are implemented comment this out: - // this.close(CLOSECODES.Unknown_opcode); + // this.close(CloseCodes.Unknown_opcode); return; } try { return await OPCodeHandler.call(this, data); } catch (error) { - console.error(error); - if (!this.CLOSED && this.CLOSING) return this.close(CLOSECODES.Unknown_error); + console.error("[Gateway]", error); + if (!this.CLOSED && this.CLOSING) return this.close(CloseCodes.Unknown_error); } } diff --git a/src/gateway/listener/listener.ts b/src/gateway/listener/listener.ts index 811318af..6e88c446 100644 --- a/src/gateway/listener/listener.ts +++ b/src/gateway/listener/listener.ts @@ -13,7 +13,7 @@ import { RelationshipType } from "@fosscord/util"; import { Channel as AMQChannel } from "amqplib"; -import { OPCODES } from "../util/Constants"; +import { GatewayOPCodes } from "../util/Constants"; import { Send } from "../util/Send"; // TODO: close connection on Invalidated Token @@ -27,7 +27,7 @@ export function handlePresenceUpdate(this: WebSocket, { event, acknowledge, data acknowledge?.(); if (event === EVENTEnum.PresenceUpdate) { return Send(this, { - op: OPCODES.Dispatch, + op: GatewayOPCodes.Dispatch, t: event, d: data, s: this.sequence++ @@ -212,7 +212,7 @@ async function consume(this: WebSocket, opts: EventOpts) { } Send(this, { - op: OPCODES.Dispatch, + op: GatewayOPCodes.Dispatch, t: event, d: data, s: this.sequence++ diff --git a/src/gateway/opcodes/Identify.ts b/src/gateway/opcodes/Identify.ts index ac6955fd..033f9247 100644 --- a/src/gateway/opcodes/Identify.ts +++ b/src/gateway/opcodes/Identify.ts @@ -24,7 +24,7 @@ import { UserSettings } from "@fosscord/util"; import { setupListener } from "../listener/listener"; -import { CLOSECODES, OPCODES } from "../util/Constants"; +import { CloseCodes, GatewayOPCodes } from "../util/Constants"; import { Send } from "../util/Send"; import { genSessionId } from "../util/SessionUtils"; import { check } from "./instanceOf"; @@ -46,7 +46,7 @@ export async function onIdentify(this: WebSocket, data: Payload) { var { decoded } = await checkToken(identify.token, jwtSecret); // will throw an error if invalid } catch (error) { console.error("invalid token", error); - return this.close(CLOSECODES.Authentication_failed); + return this.close(CloseCodes.Authentication_failed); } this.user_id = decoded.id; @@ -87,15 +87,15 @@ export async function onIdentify(this: WebSocket, data: Payload) { Application.findOne({ where: { id: this.user_id } }) ]); - if (!user) return this.close(CLOSECODES.Authentication_failed); + if (!user) return this.close(CloseCodes.Authentication_failed); if (!user.settings) { //settings may not exist after updating... user.settings = new UserSettings(); user.settings.id = user.id; - //await (user.settings as UserSettings).save(); + await user.settings.save(); } - if (!identify.intents) identify.intents = "30064771071"; + if (!identify.intents) identify.intents = "0x6ffffffff"; this.intents = new Intents(identify.intents); if (identify.shard) { this.shard_id = identify.shard[0]; @@ -108,7 +108,7 @@ export async function onIdentify(this: WebSocket, data: Payload) { this.shard_count <= 0 ) { console.log(identify.shard); - return this.close(CLOSECODES.Invalid_shard); + return this.close(CloseCodes.Invalid_shard); } } let users: PublicUser[] = []; @@ -130,7 +130,7 @@ export async function onIdentify(this: WebSocket, data: Payload) { if (user.bot) { setTimeout(() => { Send(this, { - op: OPCODES.Dispatch, + op: GatewayOPCodes.Dispatch, t: EVENTEnum.GuildCreate, s: this.sequence++, d: guild @@ -223,7 +223,7 @@ export async function onIdentify(this: WebSocket, data: Payload) { const d: ReadyEventData = { v: 8, - application: { id: application?.id ?? "", flags: application?.flags ?? 0 }, //TODO: check this code! + application: { id: application?.id ?? "", flags: application?.flags ?? "" }, //TODO: check this code! user: privateUser, user_settings: user.settings, // @ts-ignore @@ -268,7 +268,7 @@ export async function onIdentify(this: WebSocket, data: Payload) { // TODO: send real proper data structure await Send(this, { - op: OPCODES.Dispatch, + op: GatewayOPCodes.Dispatch, t: EVENTEnum.Ready, s: this.sequence++, d diff --git a/src/gateway/opcodes/LazyRequest.ts b/src/gateway/opcodes/LazyRequest.ts index ea69779e..c37eb058 100644 --- a/src/gateway/opcodes/LazyRequest.ts +++ b/src/gateway/opcodes/LazyRequest.ts @@ -1,6 +1,6 @@ import { handlePresenceUpdate, Payload, WebSocket } from "@fosscord/gateway"; import { getOrInitialiseDatabase, getPermission, LazyRequest, listenEvent, Member, Role } from "@fosscord/util"; -import { OPCODES } from "../util/Constants"; +import { GatewayOPCodes } from "../util/Constants"; import { Send } from "../util/Send"; import { check } from "./instanceOf"; @@ -129,7 +129,7 @@ export async function onLazyRequest(this: WebSocket, { d }: Payload) { }); return Send(this, { - op: OPCODES.Dispatch, + op: GatewayOPCodes.Dispatch, s: this.sequence++, t: "GUILD_MEMBER_LIST_UPDATE", d: { diff --git a/src/gateway/opcodes/RequestGuildMembers.ts b/src/gateway/opcodes/RequestGuildMembers.ts index b80721dc..d70bb1a8 100644 --- a/src/gateway/opcodes/RequestGuildMembers.ts +++ b/src/gateway/opcodes/RequestGuildMembers.ts @@ -1,5 +1,5 @@ import { Payload, WebSocket } from "@fosscord/gateway"; export function onRequestGuildMembers(this: WebSocket, data: Payload) { - // return this.close(CLOSECODES.Unknown_error); + // return this.close(CloseCodes.Unknown_error); } diff --git a/src/gateway/opcodes/Resume.ts b/src/gateway/opcodes/Resume.ts index f320864b..b30ea8f8 100644 --- a/src/gateway/opcodes/Resume.ts +++ b/src/gateway/opcodes/Resume.ts @@ -8,5 +8,5 @@ export async function onResume(this: WebSocket, data: Payload) { d: false }); - // return this.close(CLOSECODES.Invalid_session); + // return this.close(CloseCodes.Invalid_session); } diff --git a/src/gateway/opcodes/VoiceStateUpdate.ts b/src/gateway/opcodes/VoiceStateUpdate.ts index 20502584..be7bddd9 100644 --- a/src/gateway/opcodes/VoiceStateUpdate.ts +++ b/src/gateway/opcodes/VoiceStateUpdate.ts @@ -20,20 +20,16 @@ export async function onVoiceStateUpdate(this: WebSocket, data: Payload) { check.call(this, VoiceStateUpdateSchema, data.d); const body = data.d as VoiceStateUpdateSchema; - if (body.guild_id == null) { - console.log(`[Gateway] VoiceStateUpdate called with guild_id == null by user ${this.user_id}!`); - return; - } - + let onlySettingsChanged = false; let voiceState: VoiceState; try { voiceState = await VoiceState.findOneOrFail({ where: { user_id: this.user_id } }); - if (voiceState.session_id !== this.session_id && body.channel_id === null) { - //Should we also check guild_id === null? - //changing deaf or mute on a client that's not the one with the same session of the voicestate in the database should be ignored - return; + if (voiceState.session_id !== this.session_id) { + // new session + } else { + if (voiceState.channel_id === body.channel_id) onlySettingsChanged = true; } //If a user change voice channel between guild we should send a left event first @@ -70,7 +66,7 @@ export async function onVoiceStateUpdate(this: WebSocket, data: Payload) { if (voiceState.session_id !== this.session_id) voiceState.token = genVoiceToken(); voiceState.session_id = this.session_id; - const { id, ...newObj } = voiceState; + const { id, token, ...newObj } = voiceState; await Promise.all([ voiceState.save(), @@ -82,7 +78,7 @@ export async function onVoiceStateUpdate(this: WebSocket, data: Payload) { ]); //If it's null it means that we are leaving the channel and this event is not needed - if (voiceState.channel_id !== null) { + if (voiceState.channel_id !== null && !onlySettingsChanged) { const guild = await Guild.findOne({ where: { id: voiceState.guild_id } }); const regions = Config.get().regions; let guildRegion: Region; @@ -95,11 +91,11 @@ export async function onVoiceStateUpdate(this: WebSocket, data: Payload) { await emitEvent({ event: "VOICE_SERVER_UPDATE", data: { - token: voiceState.token, + token: token, guild_id: voiceState.guild_id, - endpoint: guildRegion.endpoint + endpoint: guildRegion.endpoint ? guildRegion.endpoint + "/voice" : `localhost:${process.env.PORT || 3001}/voice` }, - guild_id: voiceState.guild_id + user_id: this.user_id } as VoiceServerUpdateEvent); } } diff --git a/src/gateway/opcodes/instanceOf.ts b/src/gateway/opcodes/instanceOf.ts index 95d74963..530f639a 100644 --- a/src/gateway/opcodes/instanceOf.ts +++ b/src/gateway/opcodes/instanceOf.ts @@ -1,6 +1,6 @@ import { WebSocket } from "@fosscord/gateway"; import { instanceOf } from "@fosscord/util"; -import { CLOSECODES } from "../util/Constants"; +import { CloseCodes } from "../util/Constants"; export function check(this: WebSocket, schema: any, data: any) { try { @@ -12,7 +12,7 @@ export function check(this: WebSocket, schema: any, data: any) { } catch (error) { console.error(error); // invalid payload - this.close(CLOSECODES.Decode_error); + this.close(CloseCodes.Decode_error); throw error; } } diff --git a/src/gateway/util/Constants.ts b/src/gateway/util/Constants.ts index 78455ff8..b3e3c0d9 100644 --- a/src/gateway/util/Constants.ts +++ b/src/gateway/util/Constants.ts @@ -1,4 +1,6 @@ -export enum OPCODES { +import { VoiceOPCodes } from "@fosscord/webrtc"; + +export enum GatewayOPCodes { Dispatch = 0, Heartbeat = 1, Identify = 2, @@ -22,28 +24,59 @@ export enum OPCODES { Stream_Watch = 20, Stream_Ping = 21, Stream_Set_Paused = 22, - Request_Application_Commands = 24 + Request_Application_Commands = 24, + Embedded_Activity_Launch = 25, + Embedded_Activity_Close = 26, + Embedded_Activity_Update = 27, + Request_Forum_Unreads = 28, + Remote_Command = 29 +} + +export enum GatewayOPCodes { + DISPATCH = 0, + HEARTBEAT = 1, + IDENTIFY = 2, + PRESENCE_UPDATE = 3, + VOICE_STATE_UPDATE = 4, + VOICE_SERVER_PING = 5, + RESUME = 6, + RECONNECT = 7, + REQUEST_GUILD_MEMBERS = 8, + INVALID_SESSION = 9, + HELLO = 10, + HEARTBEAT_ACK = 11, + CALL_CONNECT = 13, + GUILD_SUBSCRIPTIONS = 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 } -export enum CLOSECODES { + +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 + Unknown_opcode = 4001, + Decode_error = 4002, + Not_authenticated = 4003, + Authentication_failed = 4004, + Already_authenticated = 4005, + Invalid_session = 4006, + Invalid_seq = 4007, + Rate_limited = 4008, + Session_timed_out = 4009, + Invalid_shard = 4010, + Sharding_required = 4011, + Invalid_API_version = 4012, + Invalid_intent = 4013, + Disallowed_intent = 4014 } export interface Payload { - op: OPCODES; + op: GatewayOPCodes | VoiceOPCodes; d?: any; s?: number; t?: string; diff --git a/src/gateway/util/Heartbeat.ts b/src/gateway/util/Heartbeat.ts index f6871cfe..cf2b1999 100644 --- a/src/gateway/util/Heartbeat.ts +++ b/src/gateway/util/Heartbeat.ts @@ -1,4 +1,4 @@ -import { CLOSECODES } from "./Constants"; +import { CloseCodes } from "./Constants"; import { WebSocket } from "./WebSocket"; // TODO: make heartbeat timeout configurable @@ -6,6 +6,6 @@ export function setHeartbeat(socket: WebSocket) { if (socket.heartbeatTimeout) clearTimeout(socket.heartbeatTimeout); socket.heartbeatTimeout = setTimeout(() => { - return socket.close(CLOSECODES.Session_timed_out); + return socket.close(CloseCodes.Session_timed_out); }, 1000 * 45); } diff --git a/src/gateway/util/Send.ts b/src/gateway/util/Send.ts index 7826dd40..3d10216d 100644 --- a/src/gateway/util/Send.ts +++ b/src/gateway/util/Send.ts @@ -7,7 +7,7 @@ try { import { Payload, WebSocket } from "@fosscord/gateway"; export async function Send(socket: WebSocket, data: Payload) { - if (process.env.WS_VERBOSE) console.log(`[Websocket] Outgoing message: ${JSON.stringify(data)}`); + if (process.env.WS_VERBOSE) console.log(`[Gateway] Outgoing message: ${JSON.stringify(data)}`); let buffer: Buffer | string; if (socket.encoding === "etf") buffer = erlpack.pack(data); // TODO: encode circular object diff --git a/src/gateway/util/WebSocket.ts b/src/gateway/util/WebSocket.ts index 9496da85..b0be11db 100644 --- a/src/gateway/util/WebSocket.ts +++ b/src/gateway/util/WebSocket.ts @@ -1,4 +1,5 @@ import { Intents, Permissions } from "@fosscord/util"; +import { Client } from "@fosscord/webrtc"; import WS from "ws"; import { Deflate } from "zlib"; @@ -19,4 +20,5 @@ export interface WebSocket extends WS { events: Record; member_events: Record; listen_options: any; + client: Client; } diff --git a/src/util/config/types/RegionConfiguration.ts b/src/util/config/types/RegionConfiguration.ts index b4b8c4a3..418f46f1 100644 --- a/src/util/config/types/RegionConfiguration.ts +++ b/src/util/config/types/RegionConfiguration.ts @@ -7,7 +7,7 @@ export class RegionConfiguration { { id: "fosscord", name: "Fosscord", - endpoint: "127.0.0.1:3004", + endpoint: undefined, vip: false, custom: false, deprecated: false diff --git a/src/util/entities/Attachment.ts b/src/util/entities/Attachment.ts index 8392f415..395e695a 100644 --- a/src/util/entities/Attachment.ts +++ b/src/util/entities/Attachment.ts @@ -1,7 +1,9 @@ -import { BeforeRemove, Column, Entity, JoinColumn, ManyToOne, RelationId } from "typeorm"; +import "reflect-metadata"; +import { BeforeRemove, Column, Entity, JoinColumn, ManyToOne, Relation, RelationId } from "typeorm"; import { URL } from "url"; import { deleteFile } from "../util/cdn"; import { BaseClass } from "./BaseClass"; +import { Message } from "./Message"; @Entity("attachments") export class Attachment extends BaseClass { @@ -34,7 +36,7 @@ export class Attachment extends BaseClass { @ManyToOne(() => require("./Message").Message, (message: import("./Message").Message) => message.attachments, { onDelete: "CASCADE" }) - message: import("./Message").Message; + message: Relation; @BeforeRemove() onDelete() { diff --git a/src/util/entities/AuditLog.ts b/src/util/entities/AuditLog.ts index 6f394f42..f8c65145 100644 --- a/src/util/entities/AuditLog.ts +++ b/src/util/entities/AuditLog.ts @@ -1,4 +1,5 @@ -import { Column, Entity, JoinColumn, ManyToOne, RelationId } from "typeorm"; +import "reflect-metadata"; +import { Column, Entity, JoinColumn, ManyToOne, Relation, RelationId } from "typeorm"; import { BaseClass } from "./BaseClass"; import { ChannelPermissionOverwrite } from "./Channel"; import { User } from "./User"; @@ -97,7 +98,7 @@ export enum AuditLogEvents { export class AuditLog extends BaseClass { @JoinColumn({ name: "target_id" }) @ManyToOne(() => User) - target?: User; + target?: Relation; @Column({ nullable: true }) @RelationId((auditlog: AuditLog) => auditlog.user) @@ -105,7 +106,7 @@ export class AuditLog extends BaseClass { @JoinColumn({ name: "user_id" }) @ManyToOne(() => User, (user: User) => user.id) - user: User; + user: Relation; @Column({ type: "int" }) action_type: AuditLogEvents; diff --git a/src/util/entities/BackupCodes.ts b/src/util/entities/BackupCodes.ts index 503b1dbd..79b60a5e 100644 --- a/src/util/entities/BackupCodes.ts +++ b/src/util/entities/BackupCodes.ts @@ -6,7 +6,7 @@ import { User } from "./User"; export class BackupCode extends BaseClass { @JoinColumn({ name: "user_id" }) @ManyToOne(() => User, { onDelete: "CASCADE" }) - user: User; + user: Relation; @Column() code: string; diff --git a/src/util/entities/Ban.ts b/src/util/entities/Ban.ts index 27c75278..e7daaf2a 100644 --- a/src/util/entities/Ban.ts +++ b/src/util/entities/Ban.ts @@ -1,4 +1,5 @@ -import { Column, Entity, JoinColumn, ManyToOne, RelationId } from "typeorm"; +import "reflect-metadata"; +import { Column, Entity, JoinColumn, ManyToOne, Relation, RelationId } from "typeorm"; import { BaseClass } from "./BaseClass"; import { Guild } from "./Guild"; import { User } from "./User"; @@ -13,7 +14,7 @@ export class Ban extends BaseClass { @ManyToOne(() => User, { onDelete: "CASCADE" }) - user: User; + user: Relation; @Column({ nullable: true }) @RelationId((ban: Ban) => ban.guild) @@ -23,7 +24,7 @@ export class Ban extends BaseClass { @ManyToOne(() => Guild, { onDelete: "CASCADE" }) - guild: Guild; + guild: Relation; @Column({ nullable: true }) @RelationId((ban: Ban) => ban.executor) @@ -31,7 +32,7 @@ export class Ban extends BaseClass { @JoinColumn({ name: "executor_id" }) @ManyToOne(() => User) - executor: User; + executor: Relation; @Column() ip: string; diff --git a/src/util/entities/Channel.ts b/src/util/entities/Channel.ts index b17fdba0..17a077ba 100644 --- a/src/util/entities/Channel.ts +++ b/src/util/entities/Channel.ts @@ -56,7 +56,7 @@ export class Channel extends BaseClass { cascade: true, orphanedRowAction: "delete" }) - recipients?: Recipient[]; + recipients?: Relation; @Column({ nullable: true }) last_message_id: string; @@ -69,7 +69,7 @@ export class Channel extends BaseClass { @ManyToOne(() => Guild, { onDelete: "CASCADE" }) - guild: Guild; + guild: Relation; @Column({ nullable: true }) @RelationId((channel: Channel) => channel.parent) @@ -77,7 +77,7 @@ export class Channel extends BaseClass { @JoinColumn({ name: "parent_id" }) @ManyToOne(() => Channel) - parent?: Channel; + parent?: Relation; // for group DMs and owned custom channel types @Column({ nullable: true }) @@ -86,7 +86,7 @@ export class Channel extends BaseClass { @JoinColumn({ name: "owner_id" }) @ManyToOne(() => User) - owner: User; + owner: Relation; @Column({ nullable: true }) last_pin_timestamp?: number; @@ -112,9 +112,6 @@ export class Channel extends BaseClass { @Column({ nullable: true }) nsfw?: boolean; - @Column({ nullable: true }) - rate_limit_per_user?: number; - @Column({ nullable: true }) topic?: string; @@ -122,7 +119,7 @@ export class Channel extends BaseClass { cascade: true, orphanedRowAction: "delete" }) - invites?: Invite[]; + invites?: Relation; @Column({ nullable: true }) retention_policy_id?: string; @@ -131,25 +128,25 @@ export class Channel extends BaseClass { cascade: true, orphanedRowAction: "delete" }) - messages?: Message[]; + messages?: Relation; @OneToMany(() => VoiceState, (voice_state: VoiceState) => voice_state.channel, { cascade: true, orphanedRowAction: "delete" }) - voice_states?: VoiceState[]; + voice_states?: Relation; @OneToMany(() => ReadState, (read_state: ReadState) => read_state.channel, { cascade: true, orphanedRowAction: "delete" }) - read_states?: ReadState[]; + read_states?: Relation; @OneToMany(() => Webhook, (webhook: Webhook) => webhook.channel, { cascade: true, orphanedRowAction: "delete" }) - webhooks?: Webhook[]; + webhooks?: Relation; @Column({ nullable: true }) flags?: number = 0; diff --git a/src/util/entities/ConnectedAccount.ts b/src/util/entities/ConnectedAccount.ts index 018b3995..a74b7a43 100644 --- a/src/util/entities/ConnectedAccount.ts +++ b/src/util/entities/ConnectedAccount.ts @@ -1,4 +1,5 @@ -import { Column, Entity, JoinColumn, ManyToOne, RelationId } from "typeorm"; +import "reflect-metadata"; +import { Column, Entity, JoinColumn, ManyToOne, Relation, RelationId } from "typeorm"; import { BaseClass } from "./BaseClass"; import { User } from "./User"; @@ -14,7 +15,7 @@ export class ConnectedAccount extends BaseClass { @ManyToOne(() => User, { onDelete: "CASCADE" }) - user: User; + user: Relation; @Column({ select: false }) access_token: string; diff --git a/src/util/entities/Emoji.ts b/src/util/entities/Emoji.ts index a2552995..4a453afe 100644 --- a/src/util/entities/Emoji.ts +++ b/src/util/entities/Emoji.ts @@ -1,4 +1,5 @@ -import { Column, Entity, JoinColumn, ManyToOne, RelationId } from "typeorm"; +import "reflect-metadata"; +import { Column, Entity, JoinColumn, ManyToOne, Relation, RelationId } from "typeorm"; import { User } from "."; import { BaseClass } from "./BaseClass"; import { Guild } from "./Guild"; @@ -18,7 +19,7 @@ export class Emoji extends BaseClass { @ManyToOne(() => Guild, { onDelete: "CASCADE" }) - guild: Guild; + guild: Relation; @Column({ nullable: true }) @RelationId((emoji: Emoji) => emoji.user) @@ -26,7 +27,7 @@ export class Emoji extends BaseClass { @JoinColumn({ name: "user_id" }) @ManyToOne(() => User) - user: User; + user: Relation; @Column() managed: boolean; diff --git a/src/util/entities/Guild.ts b/src/util/entities/Guild.ts index 015c6d04..9efb7e74 100644 --- a/src/util/entities/Guild.ts +++ b/src/util/entities/Guild.ts @@ -41,8 +41,8 @@ export class Guild extends BaseClass { afk_channel_id?: string; @JoinColumn({ name: "afk_channel_id" }) - @ManyToOne(() => Channel) - afk_channel?: Channel; + @ManyToOne(() => Channel, { nullable: true }) + afk_channel?: Relation; @Column({ nullable: true }) afk_timeout?: number = Config.get().defaults.guild.afkTimeout; @@ -57,7 +57,7 @@ export class Guild extends BaseClass { cascade: true, orphanedRowAction: "delete" }) - bans: Ban[]; + bans: Relation; @Column({ nullable: true }) banner?: string; @@ -107,7 +107,7 @@ export class Guild extends BaseClass { orphanedRowAction: "delete", onDelete: "CASCADE" }) - members: Member[]; + members: Relation; @JoinColumn({ name: "role_ids" }) @OneToMany(() => Role, (role: Role) => role.guild, { @@ -115,14 +115,14 @@ export class Guild extends BaseClass { orphanedRowAction: "delete", onDelete: "CASCADE" }) - roles: Role[]; + roles: Relation; @JoinColumn({ name: "channel_ids" }) @OneToMany(() => Channel, (channel: Channel) => channel.guild, { cascade: true, orphanedRowAction: "delete" }) - channels: Channel[]; + channels: Relation; @Column({ nullable: true }) @RelationId((guild: Guild) => guild.template) @@ -130,7 +130,7 @@ export class Guild extends BaseClass { @JoinColumn({ name: "template_id", referencedColumnName: "id" }) @ManyToOne(() => Template) - template: Template; + template: Relation