61 lines
2.0 KiB
TypeScript
61 lines
2.0 KiB
TypeScript
export type Message<T> = {
|
|
type: string,
|
|
data?: T,
|
|
};
|
|
|
|
export type MessageHandler<T> = (message: Message<T>) => void;
|
|
|
|
export class MessagingSystem {
|
|
private handlers: Record<string, MessageHandler<any>[]> = {};
|
|
|
|
public registerHandler<T>(type: string, handler: MessageHandler<T>): void {
|
|
if (!this.handlers[type]) {
|
|
this.handlers[type] = [];
|
|
}
|
|
if (!this.handlers[type].includes(handler)) {
|
|
this.handlers[type].push(handler);
|
|
}
|
|
}
|
|
|
|
public unregisterHandler<T>(type: string, handler: MessageHandler<T>): void {
|
|
if (this.handlers[type]) {
|
|
this.handlers[type] = this.handlers[type].filter(h => h !== handler);
|
|
}
|
|
}
|
|
|
|
public registerHandlerOnce<T>(type: string, handler: MessageHandler<T>): void {
|
|
const wrappedHandler = (message: Message<T>) => {
|
|
handler(message);
|
|
this.unregisterHandler(type, wrappedHandler);
|
|
};
|
|
this.registerHandler(type, wrappedHandler);
|
|
}
|
|
|
|
public waitForMessage<T>(type: string, timeout?: number): Promise<T> {
|
|
return new Promise((resolve, reject) => {
|
|
const handler = (message: Message<T>) => {
|
|
if (timer) clearTimeout(timer);
|
|
resolve(message.data!);
|
|
this.unregisterHandler(type, handler);
|
|
};
|
|
|
|
this.registerHandler(type, handler);
|
|
|
|
let timer: ReturnType<typeof setTimeout> | undefined;
|
|
if (timeout) {
|
|
timer = setTimeout(() => {
|
|
this.unregisterHandler(type, handler);
|
|
reject(new Error(`Timeout waiting for message of type '${type}'`));
|
|
}, timeout);
|
|
}
|
|
});
|
|
}
|
|
|
|
public sendMessage<T>(message: Message<T>): void {
|
|
const handlers = this.handlers[message.type];
|
|
if (handlers) {
|
|
handlers.forEach(handler => handler(message));
|
|
}
|
|
}
|
|
}
|