infoalloggi-monorepo/apps/infoalloggi/src/server/sse.ts

151 lines
4 KiB
TypeScript
Raw Normal View History

2025-08-04 17:45:44 +02:00
import EventEmitter, { on } from "node:events";
import type { ChatsChatid } from "~/schemas/public/Chats";
import type { MessagesMessageid } from "~/schemas/public/Messages";
import type { UsersId } from "~/schemas/public/Users";
import type { ChatMessage } from "~/server/services/messages.service";
export type WhoIsTyping = {
userId: UsersId;
username: string;
};
export type OnlineStatus = {
userId: UsersId;
nome: string;
isAdmin: boolean;
};
type ChatUpdate =
| {
eventType: "online";
data: OnlineStatus[];
}
| {
eventType: "typing";
data: WhoIsTyping[];
};
// export type AddEvent = {
// eventType: "add";
// data: ChatMessage;
// };
type EditEvent = {
eventType: "edit";
data: { messageId: MessagesMessageid; message: string };
};
type DeleteEvent = {
eventType: "delete";
data: MessagesMessageid;
};
export type MessageUpdate = EditEvent | DeleteEvent;
interface Events {
add: [chatId: ChatsChatid, data: ChatMessage];
test: [ch: string, data: string];
notificaUpdate: [userId: UsersId];
messageUpdates: [chatId: ChatsChatid, data: MessageUpdate];
chatUpdates: [chatId: ChatsChatid, data: ChatUpdate];
}
enum LogLevel {
NONE = 0, // No logs
ERROR = 1, // Only errors
WARN = 2, // Warnings and errors
INFO = 3, // Info, warnings, and errors
DEBUG = 4, // Dbg, info, warnings, and errors
}
class IterableEventEmitter extends EventEmitter<Events> {
private logLevel: LogLevel = LogLevel.INFO; // Default log level
// Method to set the log level
setLogLevel(level: LogLevel): void {
this.logLevel = level;
}
// Method to log messages based on the current log level
private log(level: LogLevel, message: string, ...args: unknown[]): void {
if (this.logLevel >= level) {
console.log(message, ...args);
}
}
// Method to log emitted events
private logEvent(eventName: string | symbol, args: unknown[]): void {
this.log(
LogLevel.DEBUG,
`[EventEmitter] Event emitted: ${String(eventName)}`,
args,
);
}
// Method to log added listeners
private logListener(eventName: string | symbol): void {
this.log(
LogLevel.INFO,
`[EventEmitter] Listener added for event: ${String(eventName)}`,
);
}
// Method to log removed listeners
private logRemoveListener(eventName: string | symbol): void {
this.log(
LogLevel.INFO,
`[EventEmitter] Listener removed for event: ${String(eventName)}`,
);
}
// Override the `emit` method to include logging
emit<TEventName extends keyof Events>(
eventName: TEventName,
...args: Events[TEventName]
): boolean {
this.logEvent(eventName, args); // Log the event
//@ts-expect-error
return super.emit(eventName, ...args); // Call the original `emit` method
}
// Override the `on` method to include logging
on<TEventName extends keyof Events>(
eventName: TEventName,
listener: (...args: Events[TEventName]) => void,
): this {
this.logListener(eventName); // Log the listener addition
//@ts-expect-error
return super.on(eventName, listener); // Call the original `on` method
}
// Override the `off` method to include logging
off<TEventName extends keyof Events>(
eventName: TEventName,
listener: (...args: Events[TEventName]) => void,
): this {
this.logRemoveListener(eventName); // Log the listener removal
//@ts-expect-error
return super.off(eventName, listener); // Call the original `off` method
}
toIterable<TEventName extends keyof Events>(
eventName: TEventName,
opts?: NonNullable<Parameters<typeof on>[2]>,
): AsyncIterable<Events[TEventName]> {
this.log(
LogLevel.DEBUG,
`[EventEmitter] Creating async iterable for event: ${String(eventName)}`,
);
return on(this, eventName, opts) as AsyncIterable<Events[TEventName]>;
}
}
// In a real app, you'd probably use Redis or something
export const ee = new IterableEventEmitter();
// Example: Set log level to DEBUG
ee.setLogLevel(LogLevel.ERROR);
ee.setMaxListeners(200);