UNPKG

@akala/core

Version:
148 lines 5.74 kB
import { EventEmitter } from "../index.browser.js"; /** * Adapts a socket connection to handle protocol-level message transformations. * Provides an event-based interface for managing socket communication with custom * serialization/deserialization logic. * @template T The type of messages after transformation */ export class SocketProtocolAdapter extends EventEmitter { transform; socket; /** * Creates a new socket protocol adapter. * @param transform Configuration object containing receive, send, and optional close handlers * @param transform.receive Function to deserialize incoming data into application messages * @param transform.send Function to serialize application messages for transmission * @param transform.close Optional function to perform protocol-specific cleanup * @param socket The underlying socket adapter to wrap */ constructor(transform, socket) { super(); this.transform = transform; this.socket = socket; this.on(Symbol.dispose, () => socket.close()); } /** * Pipes incoming messages to another socket adapter. * @param socket The destination socket to send messages to */ pipe(socket) { this.on('message', (message) => socket.send(message)); this.on('close', () => socket.close()); } /** * Gets the open status of the underlying socket. */ get open() { return this.socket.open; } /** * Closes the socket and performs any necessary protocol cleanup. */ async close() { await this.transform.close?.(this.socket); await this.socket.close(); } /** * Sends a message through the socket after applying the send transformation. * @param data The message to send */ send(data) { return this.socket.send(this.transform.send(data, this)); } messageListeners = []; messageSubscription; /** * Removes an event listener from the adapter. * @param event The event type to remove the listener from * @param handler The event handler to remove, or undefined to remove all handlers * @returns true if the listener was successfully removed */ off(event, handler) { switch (event) { case 'message': { let listeners = this.messageListeners; if (handler) this.messageListeners.splice(listeners.findIndex(f => f[0] == handler), 1); else this.messageListeners.length = 0; if (this.messageListeners.length == 0) this.messageSubscription?.(); } break; case 'close': case 'error': case 'open': //eslint-disable-next-line @typescript-eslint/no-explicit-any this.socket.off(event, handler); break; default: throw new Error(`Unsupported event ${String(event)}`); } return true; } /** * Registers an event listener on the adapter. * @param event The event type to listen for * @param handler The callback to invoke when the event occurs * @param options Optional event listener configuration * @returns A subscription function to unsubscribe from the event */ on(event, handler, options) { switch (event) { case 'message': { if (this.messageListeners.length === 0) this.messageSubscription = this.socket.on('message', message => { const m = this.transform.receive(message, this); for (const message of m) for (const listener of this.messageListeners) listener(message); }, options); this.messageListeners.push(handler); return () => { this.messageListeners.splice(this.messageListeners.findIndex(x => x === handler), 1); if (this.messageListeners.length === 0 && this.messageSubscription) return this.messageSubscription(); }; } case 'close': case 'error': case 'open': case Symbol.dispose: //eslint-disable-next-line @typescript-eslint/no-explicit-any return this.socket.on(event, handler); default: throw new Error(`Unsupported event ${String(event)}`); } } /** * Registers an event listener that fires only once. * @param event The event type to listen for * @param handler The callback to invoke when the event occurs * @returns A subscription function to unsubscribe from the event */ once(event, handler) { switch (event) { case 'message': return this.on(event, handler, { once: true }); case 'close': case 'error': case 'open': return this.on(event, handler, { once: true }); default: throw new Error(`Unsupported event ${event?.toString()}`); } } /** * Emits an event to all registered listeners. * @param event The event type to emit * @param args Arguments to pass to event listeners * @returns The result of the emit operation */ emit(event, ...args) { return super.emit(event, ...args); } } //# sourceMappingURL=shared.socket-protocol-adapter.js.map