remove timer based kvstore status stragedy, only sse based now
This commit is contained in:
parent
e64910d895
commit
f1539bdffa
2 changed files with 40 additions and 60 deletions
|
|
@ -1,7 +1,7 @@
|
||||||
import type { Handle } from '@sveltejs/kit';
|
import type { Handle } from '@sveltejs/kit';
|
||||||
import * as auth from '$lib/server/auth';
|
import * as auth from '$lib/server/auth';
|
||||||
import { kvStore } from '$lib/server/db';
|
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';
|
import { Status } from '$lib';
|
||||||
|
|
||||||
const handleAuth: Handle = async ({ event, resolve }) => {
|
const handleAuth: Handle = async ({ event, resolve }) => {
|
||||||
|
|
@ -24,57 +24,6 @@ const handleAuth: Handle = async ({ event, resolve }) => {
|
||||||
event.locals.user = user;
|
event.locals.user = user;
|
||||||
event.locals.session = session;
|
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<number>(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<NodeJS.Timeout>(timerKey);
|
|
||||||
if (existingTimer) {
|
|
||||||
clearTimeout(existingTimer);
|
|
||||||
}
|
|
||||||
|
|
||||||
const offlineTimer = setTimeout(() => {
|
|
||||||
const last = kvStore.get<number>(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);
|
return resolve(event);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,6 @@
|
||||||
|
import { Status } from '$lib';
|
||||||
|
import { kvStore } from '$lib/server/db/index.js';
|
||||||
|
|
||||||
interface SubscribedTo {
|
interface SubscribedTo {
|
||||||
subscribed: string[];
|
subscribed: string[];
|
||||||
userId: string;
|
userId: string;
|
||||||
|
|
@ -5,35 +8,63 @@ interface SubscribedTo {
|
||||||
}
|
}
|
||||||
|
|
||||||
export const _clients = new Map<string, SubscribedTo>();
|
export const _clients = new Map<string, SubscribedTo>();
|
||||||
|
|
||||||
export function _sendToSubscribers(userId: string, payload: unknown) {
|
export function _sendToSubscribers(userId: string, payload: unknown) {
|
||||||
for (const client of _clients) {
|
for (const [key, client] of _clients) {
|
||||||
if (client[1].subscribed.includes(userId)) {
|
if (client.subscribed.includes(userId)) {
|
||||||
try {
|
try {
|
||||||
client[1].controller.enqueue(`data: ${JSON.stringify(payload)}\n\n`);
|
client.controller.enqueue(`data: ${JSON.stringify(payload)}\n\n`);
|
||||||
} catch {
|
} 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 }) {
|
export async function GET({ locals, request }) {
|
||||||
if (!locals.user) {
|
if (!locals.user) {
|
||||||
return new Response('No authentication', { status: 401 });
|
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 reqId = crypto.randomUUID();
|
||||||
|
|
||||||
const stream = new ReadableStream({
|
const stream = new ReadableStream({
|
||||||
start(controller) {
|
start(controller) {
|
||||||
_clients.set(reqId, { subscribed, userId: locals.user!.id, controller });
|
_clients.set(reqId, { subscribed, userId, controller });
|
||||||
console.log(`SSE Client opened. ${_clients.size}`);
|
console.log(`SSE Client opened. total: ${_clients.size}`);
|
||||||
|
|
||||||
controller.enqueue(`data: ${JSON.stringify({ type: 'connected' })}\n\n`);
|
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', () => {
|
request.signal.addEventListener('abort', () => {
|
||||||
_clients.delete(reqId);
|
_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 });
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue