From f1539bdffa403dd6f2368540e1182a9ffc84e935 Mon Sep 17 00:00:00 2001 From: fucksophie Date: Sun, 4 Jan 2026 20:41:49 +0200 Subject: [PATCH] remove timer based kvstore status stragedy, only sse based now --- src/hooks.server.ts | 53 +------------------------------ src/routes/api/updates/+server.ts | 47 ++++++++++++++++++++++----- 2 files changed, 40 insertions(+), 60 deletions(-) diff --git a/src/hooks.server.ts b/src/hooks.server.ts index f861857..3aff2d3 100644 --- a/src/hooks.server.ts +++ b/src/hooks.server.ts @@ -1,7 +1,7 @@ import type { Handle } from '@sveltejs/kit'; import * as auth from '$lib/server/auth'; import { kvStore } from '$lib/server/db'; -import { _sendToSubscribers } from './routes/api/updates/+server'; +import { _isUserConnected, _sendToSubscribers } from './routes/api/updates/+server'; import { Status } from '$lib'; const handleAuth: Handle = async ({ event, resolve }) => { @@ -24,57 +24,6 @@ const handleAuth: Handle = async ({ event, resolve }) => { event.locals.user = user; event.locals.session = session; - if (event.locals.user) { - const id = event.locals.user.id; - const overwrite = event.locals.user.statusOverwrite as 1 | 2 | 3 | undefined; - const now = Date.now(); - - const lastActiveKey = `user-${id}-last-active`; - const stateKey = `user-${id}-state`; - const timerKey = `user-${id}-offline-timer`; - - const lastActive = kvStore.get(lastActiveKey) ?? 0; - const state = kvStore.get<1 | 2 | 3>(stateKey) ?? Status.OFFLINE; - - // always update activity - kvStore.set(lastActiveKey, now); - if (overwrite !== Status.OFFLINE) { - const shouldSend = state === Status.OFFLINE && now - lastActive > 5000; - - if (shouldSend) { - const outgoingStatus = overwrite === Status.DND ? Status.DND : Status.ONLINE; - - _sendToSubscribers(id, { - type: 'status', - id, - status: outgoingStatus - }); - - kvStore.set(stateKey, outgoingStatus); - } - } - const existingTimer = kvStore.get(timerKey); - if (existingTimer) { - clearTimeout(existingTimer); - } - - const offlineTimer = setTimeout(() => { - const last = kvStore.get(lastActiveKey) ?? 0; - - if (Date.now() - last >= 10_000) { - _sendToSubscribers(id, { - type: 'status', - id, - status: Status.OFFLINE - }); - - kvStore.set(stateKey, Status.OFFLINE); - kvStore.delete(timerKey); - } - }, 10_000); - - kvStore.set(timerKey, offlineTimer + ''); - } return resolve(event); }; diff --git a/src/routes/api/updates/+server.ts b/src/routes/api/updates/+server.ts index a5c3a8e..c8ac92c 100644 --- a/src/routes/api/updates/+server.ts +++ b/src/routes/api/updates/+server.ts @@ -1,3 +1,6 @@ +import { Status } from '$lib'; +import { kvStore } from '$lib/server/db/index.js'; + interface SubscribedTo { subscribed: string[]; userId: string; @@ -5,35 +8,63 @@ interface SubscribedTo { } export const _clients = new Map(); + export function _sendToSubscribers(userId: string, payload: unknown) { - for (const client of _clients) { - if (client[1].subscribed.includes(userId)) { + for (const [key, client] of _clients) { + if (client.subscribed.includes(userId)) { try { - client[1].controller.enqueue(`data: ${JSON.stringify(payload)}\n\n`); + client.controller.enqueue(`data: ${JSON.stringify(payload)}\n\n`); } catch { - _clients.delete(client[0]); + _clients.delete(key); } } } } + +export function _isUserConnected(userId: string): boolean { + for (const client of _clients.values()) { + if (client.userId === userId) return true; + } + return false; +} + export async function GET({ locals, request }) { if (!locals.user) { return new Response('No authentication', { status: 401 }); } - const subscribed = locals.user.friends.map((z) => z.id); + const userId = locals.user.id; + //@TODO add more to subscribed eventually, server members, et cetera + const subscribed = locals.user.friends.map((f) => f.id); + const overwrite = locals.user.statusOverwrite; + const reqId = crypto.randomUUID(); const stream = new ReadableStream({ start(controller) { - _clients.set(reqId, { subscribed, userId: locals.user!.id, controller }); - console.log(`SSE Client opened. ${_clients.size}`); + _clients.set(reqId, { subscribed, userId, controller }); + console.log(`SSE Client opened. total: ${_clients.size}`); controller.enqueue(`data: ${JSON.stringify({ type: 'connected' })}\n\n`); + if (overwrite === Status.DND) { + kvStore.set(`user-${userId}-state`, Status.DND); + _sendToSubscribers(userId, { type: 'status', id: userId, status: Status.DND }); + } else { + kvStore.set(`user-${userId}-state`, Status.ONLINE); + _sendToSubscribers(userId, { type: 'status', id: userId, status: Status.ONLINE }); + } + request.signal.addEventListener('abort', () => { _clients.delete(reqId); - console.log(`SSE Client aborted. ${_clients.size}`); + console.log(`SSE Client aborted. total: ${_clients.size}`); + + if (_isUserConnected(userId)) return; + + if (overwrite === Status.OFFLINE) return; + + kvStore.set(`user-${userId}-state`, Status.OFFLINE); + _sendToSubscribers(userId, { type: 'status', id: userId, status: Status.OFFLINE }); }); } });