mirror of
https://github.com/umami-software/umami.git
synced 2026-02-07 06:07:17 +01:00
Add authentication, Redis pub/sub, and error handling to SSE
Improvements: - Add Redis pub/sub support for multi-server deployments - Add authentication check to SSE stream endpoint - Add 30s heartbeat keepalive for long-lived connections - Implement exponential backoff reconnection logic in client - Fix TypeScript types (websiteId optional, timer types) - Use specific query key invalidation instead of broad match - Fix undefined access in session-events listener map
This commit is contained in:
parent
ef9a382cdd
commit
5874cf80f5
4 changed files with 114 additions and 11 deletions
|
|
@ -152,7 +152,7 @@ export async function POST(request: Request) {
|
|||
distinctId: id,
|
||||
createdAt,
|
||||
});
|
||||
emitSessionCreated(sourceId, sessionId);
|
||||
await emitSessionCreated(sourceId, sessionId);
|
||||
}
|
||||
|
||||
// Visit info
|
||||
|
|
|
|||
|
|
@ -1,20 +1,45 @@
|
|||
import { subscribeToSessions } from '@/lib/session-events';
|
||||
import { initializeRedisSubscriber, subscribeToSessions } from '@/lib/session-events';
|
||||
import { parseRequest } from '@/lib/request';
|
||||
import { unauthorized } from '@/lib/response';
|
||||
import { canViewWebsite } from '@/permissions';
|
||||
|
||||
const HEARTBEAT_INTERVAL = 30000;
|
||||
|
||||
export async function GET(
|
||||
request: Request,
|
||||
{ params }: { params: Promise<{ websiteId: string }> },
|
||||
) {
|
||||
const { auth, error } = await parseRequest(request);
|
||||
|
||||
if (error) {
|
||||
return error();
|
||||
}
|
||||
|
||||
const { websiteId } = await params;
|
||||
|
||||
if (!(await canViewWebsite(auth, websiteId))) {
|
||||
return unauthorized();
|
||||
}
|
||||
|
||||
await initializeRedisSubscriber();
|
||||
|
||||
const stream = new ReadableStream({
|
||||
start(controller) {
|
||||
const encoder = new TextEncoder();
|
||||
let heartbeatTimer: ReturnType<typeof setInterval> | null = null;
|
||||
|
||||
const unsubscribe = subscribeToSessions(websiteId, (_, sessionId) => {
|
||||
controller.enqueue(encoder.encode(`data: ${JSON.stringify({ sessionId })}\n\n`));
|
||||
});
|
||||
|
||||
heartbeatTimer = setInterval(() => {
|
||||
controller.enqueue(encoder.encode(': heartbeat\n\n'));
|
||||
}, HEARTBEAT_INTERVAL);
|
||||
|
||||
request.signal.addEventListener('abort', () => {
|
||||
if (heartbeatTimer) {
|
||||
clearInterval(heartbeatTimer);
|
||||
}
|
||||
unsubscribe();
|
||||
controller.close();
|
||||
});
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue