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 { 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( 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( 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( 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( eventName: TEventName, opts?: NonNullable[2]>, ): AsyncIterable { this.log( LogLevel.DEBUG, `[EventEmitter] Creating async iterable for event: ${String(eventName)}`, ); return on(this, eventName, opts) as AsyncIterable; } } // 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);