diff --git a/server/hybridServer.ts b/server/hybridServer.ts index 64467d1b..7339db1c 100644 --- a/server/hybridServer.ts +++ b/server/hybridServer.ts @@ -11,6 +11,13 @@ import { tokenManager } from "./lib/tokenManager"; import { APP_VERSION } from "./lib/consts"; export async function createHybridClientServer() { + logger.info("Starting hybrid client server..."); + + // Start the token manager + await tokenManager.start(); + + const token = await tokenManager.getToken(); + const monitor = new TraefikConfigManager(); await monitor.start(); @@ -23,11 +30,6 @@ export async function createHybridClientServer() { throw new Error("Hybrid configuration is not defined"); } - // Start the token manager - await tokenManager.start(); - - const token = await tokenManager.getToken(); - // Create client const client = createWebSocketClient( token, diff --git a/server/index.ts b/server/index.ts index 3e8c6769..73f3ac90 100644 --- a/server/index.ts +++ b/server/index.ts @@ -17,11 +17,13 @@ async function startServers() { // Start all servers const apiServer = createApiServer(); const internalServer = createInternalServer(); - const nextServer = await createNextServer(); let hybridClientServer; + let nextServer; if (config.isHybridMode()) { - hybridClientServer = createHybridClientServer(); + hybridClientServer = await createHybridClientServer(); + } else { + nextServer = await createNextServer(); } let integrationServer; diff --git a/server/lib/config.ts b/server/lib/config.ts index c8c7b7c4..6b41df79 100644 --- a/server/lib/config.ts +++ b/server/lib/config.ts @@ -148,7 +148,7 @@ export class Config { } public isHybridMode() { - return this.rawConfig?.hybrid; + return typeof this.rawConfig?.hybrid === "object"; } public async checkSupporterKey() { diff --git a/server/lib/tokenManager.ts b/server/lib/tokenManager.ts index 040dc609..8abfd969 100644 --- a/server/lib/tokenManager.ts +++ b/server/lib/tokenManager.ts @@ -67,6 +67,8 @@ export class TokenManager { /** * Get the current valid token */ + + // TODO: WE SHOULD NOT BE GETTING A TOKEN EVERY TIME WE REQUEST IT async getToken(): Promise { if (!this.token) { if (this.isRefreshing) { diff --git a/server/routers/external.ts b/server/routers/external.ts index 5bae553e..776db454 100644 --- a/server/routers/external.ts +++ b/server/routers/external.ts @@ -848,7 +848,7 @@ authRouter.post( rateLimit({ windowMs: 15 * 60 * 1000, max: 900, - keyGenerator: (req) => `newtGetToken:${req.body.newtId || req.ip}`, + keyGenerator: (req) => `olmGetToken:${req.body.newtId || req.ip}`, handler: (req, res, next) => { const message = `You can only request an Olm token ${900} times every ${15} minutes. Please try again later.`; return next(createHttpError(HttpCode.TOO_MANY_REQUESTS, message)); diff --git a/server/routers/ws/client.ts b/server/routers/ws/client.ts index 3f1fbf54..c40c976f 100644 --- a/server/routers/ws/client.ts +++ b/server/routers/ws/client.ts @@ -36,6 +36,7 @@ export class WebSocketClient extends EventEmitter { private pingTimer: NodeJS.Timeout | null = null; private pingTimeoutTimer: NodeJS.Timeout | null = null; private token: string; + private isConnecting: boolean = false; constructor( token: string, @@ -46,14 +47,16 @@ export class WebSocketClient extends EventEmitter { this.token = token; this.baseURL = options.baseURL || endpoint; - this.reconnectInterval = options.reconnectInterval || 3000; + this.reconnectInterval = options.reconnectInterval || 5000; this.pingInterval = options.pingInterval || 30000; this.pingTimeout = options.pingTimeout || 10000; } public async connect(): Promise { this.shouldReconnect = true; - await this.connectWithRetry(); + if (!this.isConnecting) { + await this.connectWithRetry(); + } } public async close(): Promise { @@ -141,20 +144,30 @@ export class WebSocketClient extends EventEmitter { } private async connectWithRetry(): Promise { - while (this.shouldReconnect) { + if (this.isConnecting) return; + + this.isConnecting = true; + + while (this.shouldReconnect && !this.isConnected) { try { await this.establishConnection(); + this.isConnecting = false; return; } catch (error) { console.error(`Failed to connect: ${error}. Retrying in ${this.reconnectInterval}ms...`); - if (!this.shouldReconnect) return; + if (!this.shouldReconnect) { + this.isConnecting = false; + return; + } await new Promise(resolve => { this.reconnectTimer = setTimeout(resolve, this.reconnectInterval); }); } } + + this.isConnecting = false; } private async establishConnection(): Promise { @@ -174,6 +187,7 @@ export class WebSocketClient extends EventEmitter { console.debug('WebSocket connection established'); this.conn = conn; this.setConnected(true); + this.isConnecting = false; this.startPingMonitor(); this.emit('connect'); resolve(); @@ -232,6 +246,7 @@ export class WebSocketClient extends EventEmitter { private handleDisconnect(): void { this.setConnected(false); + this.isConnecting = false; // Clear ping timers if (this.pingTimer) { @@ -252,7 +267,10 @@ export class WebSocketClient extends EventEmitter { // Reconnect if needed if (this.shouldReconnect) { - this.connectWithRetry(); + // Add a small delay before starting reconnection to prevent immediate retry + setTimeout(() => { + this.connectWithRetry(); + }, 1000); } }