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 = {
|
2025-08-28 18:27:07 +02:00
|
|
|
userId: UsersId;
|
|
|
|
|
username: string;
|
2025-08-04 17:45:44 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
export type OnlineStatus = {
|
2025-08-28 18:27:07 +02:00
|
|
|
userId: UsersId;
|
|
|
|
|
nome: string;
|
|
|
|
|
isAdmin: boolean;
|
2025-08-04 17:45:44 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
type ChatUpdate =
|
2025-08-28 18:27:07 +02:00
|
|
|
| {
|
|
|
|
|
eventType: "online";
|
|
|
|
|
data: OnlineStatus[];
|
|
|
|
|
}
|
|
|
|
|
| {
|
|
|
|
|
eventType: "typing";
|
|
|
|
|
data: WhoIsTyping[];
|
|
|
|
|
};
|
2025-08-04 17:45:44 +02:00
|
|
|
|
|
|
|
|
// export type AddEvent = {
|
|
|
|
|
// eventType: "add";
|
|
|
|
|
// data: ChatMessage;
|
|
|
|
|
// };
|
|
|
|
|
|
|
|
|
|
type EditEvent = {
|
2025-08-28 18:27:07 +02:00
|
|
|
eventType: "edit";
|
|
|
|
|
data: { messageId: MessagesMessageid; message: string };
|
2025-08-04 17:45:44 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
type DeleteEvent = {
|
2025-08-28 18:27:07 +02:00
|
|
|
eventType: "delete";
|
|
|
|
|
data: MessagesMessageid;
|
2025-08-04 17:45:44 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
export type MessageUpdate = EditEvent | DeleteEvent;
|
|
|
|
|
|
|
|
|
|
interface Events {
|
2025-08-28 18:27:07 +02:00
|
|
|
add: [chatId: ChatsChatid, data: ChatMessage];
|
2025-08-04 17:45:44 +02:00
|
|
|
|
2025-08-28 18:27:07 +02:00
|
|
|
test: [ch: string, data: string];
|
|
|
|
|
notificaUpdate: [userId: UsersId];
|
|
|
|
|
messageUpdates: [chatId: ChatsChatid, data: MessageUpdate];
|
|
|
|
|
chatUpdates: [chatId: ChatsChatid, data: ChatUpdate];
|
2025-08-04 17:45:44 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
enum LogLevel {
|
2025-08-28 18:27:07 +02:00
|
|
|
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
|
2025-08-04 17:45:44 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
class IterableEventEmitter extends EventEmitter<Events> {
|
2025-08-28 18:27:07 +02:00
|
|
|
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]>;
|
|
|
|
|
}
|
2025-08-04 17:45:44 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 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);
|