64 lines
1.6 KiB
TypeScript
64 lines
1.6 KiB
TypeScript
export interface SSEEventClient {
|
|
send: (data: string) => void;
|
|
events?: Set<string>;
|
|
userId?: number;
|
|
presenceChannel?: string;
|
|
}
|
|
|
|
const clients = new Set<SSEEventClient>();
|
|
|
|
export function subscribe(client: SSEEventClient): () => void {
|
|
clients.add(client);
|
|
return () => clients.delete(client);
|
|
}
|
|
|
|
export function unsubscribe(client: SSEEventClient): void {
|
|
clients.delete(client);
|
|
}
|
|
|
|
export function clientCount(): number {
|
|
return clients.size;
|
|
}
|
|
|
|
export function broadcast(event: string, data: unknown): number {
|
|
const payload = `event: ${event}\ndata: ${JSON.stringify(data)}\n\n`;
|
|
const presenceChannel =
|
|
event === "presence" &&
|
|
typeof data === "object" &&
|
|
data !== null &&
|
|
"channel" in data &&
|
|
typeof data.channel === "string"
|
|
? data.channel
|
|
: undefined;
|
|
for (const client of clients) {
|
|
if (client.events && !client.events.has(event)) continue;
|
|
if (
|
|
event === "presence" &&
|
|
client.presenceChannel !== undefined &&
|
|
client.presenceChannel !== presenceChannel
|
|
) {
|
|
continue;
|
|
}
|
|
try {
|
|
client.send(payload);
|
|
} catch {
|
|
clients.delete(client);
|
|
}
|
|
}
|
|
return clients.size;
|
|
}
|
|
|
|
export function broadcastToUser(event: string, userId: number, data: unknown): number {
|
|
const payload = `event: ${event}\ndata: ${JSON.stringify(data)}\n\n`;
|
|
const targetUserId = Number(userId);
|
|
for (const client of clients) {
|
|
if (client.userId !== targetUserId) continue;
|
|
if (client.events && !client.events.has(event)) continue;
|
|
try {
|
|
client.send(payload);
|
|
} catch {
|
|
clients.delete(client);
|
|
}
|
|
}
|
|
return clients.size;
|
|
}
|