import type { Channel } from "phoenix"; import type { AnyMessage } from "./messages"; export type Handlers = { [event: string]: EventHandler; }; type EventHandler = { tokenHandler: TokenHandler; directHandlers: Handler[]; }; export type TokenHandler = { [token: string]: Handler; }; export type Handler = ( message?: Message, unregister?: UnregisterHandler ) => void; export type UnregisterHandler = () => void; export function registerTokenHandler( handlers: Handlers, channel: Channel, event: string, token: string | null, handler: Handler ): UnregisterHandler { let eventHandler = handlers[event]; // If this event did not yet have any handlers registered we have to register it if (eventHandler === undefined) { eventHandler = { tokenHandler: {}, directHandlers: [], }; handlers[event] = eventHandler; registerNewEvent(channel, eventHandler, event); } let unregister: UnregisterHandler; if (token === null) { const directHandlers = eventHandler.directHandlers; directHandlers.push(handler); unregister = makeDirectUnregister(directHandlers, handler); } else { const tokenHandler = eventHandler.tokenHandler; tokenHandler[token] = handler; unregister = makeTokenUnregister(tokenHandler, token); } return unregister; } function registerNewEvent( channel: Channel, eventHandler: EventHandler, event: string ) { const callback = (data: Message) => { handleEvent(eventHandler, data); }; channel.on(event, callback); } function handleEvent( eventHandler: EventHandler, message: Message ) { if (message["token"] !== undefined) { const token = message["token"]; const tokenHandler = eventHandler.tokenHandler; const handler: Handler = tokenHandler[token]; if (handler !== undefined) { handler(message, makeTokenUnregister(tokenHandler, token)); } } const directHandlers = eventHandler.directHandlers; for (const handler of directHandlers) { handler(message, makeDirectUnregister(directHandlers, handler)); } } function makeDirectUnregister( directHandlers: Handler[], handler: Handler ): UnregisterHandler { return () => { const index = directHandlers.findIndex(h => h === handler); directHandlers.splice(index, 1); }; } function makeTokenUnregister( tokenHandler: TokenHandler, token: string ): UnregisterHandler { return () => { delete tokenHandler[token]; }; }