import { IRCConnectorEvents } from '../types/events'; import { IIRCConnector } from '../types/impl.interface'; import { formatstr } from '../utility/formatstr'; import { TypedEventEmitter } from '../utility/typed-event-emitter'; export class IRCWebSocketConnector extends TypedEventEmitter implements IIRCConnector { connected = false; private socket?: WebSocket; constructor( public secure: boolean, public host: string, public port?: number, public connOpts?: Record, ) { super(); } connect(): Promise { let url = `ws${this.secure ? 's' : ''}://${this.host}:${this.port || 6667}`; if (this.connOpts?.path) { url += ('/' + this.connOpts.path) as string; } return new Promise((resolve, reject) => { const onConnect = () => { this.connected = true; resolve(); }; try { this.socket = new WebSocket(url); } catch (e: unknown) { return reject(e); } this.socket?.addEventListener('open', onConnect); this.handle(); }); } async destroy(): Promise { this.connected = false; this.socket?.close(); this.socket = undefined; } write(format: string, ...args: any[]): void { this.socket?.send(formatstr(format, ...args) + '\r\n'); } private handle() { let buffer: string = ''; this.socket?.addEventListener('message', (event) => { const chunk = event.data.toString(); buffer += chunk; const data = buffer.split('\r\n'); buffer = data.pop() || ''; data.forEach((line: string) => { if (line.indexOf('PING') === 0 && !this.connOpts?.skipPings) { this.socket?.send('PONG' + line.substring(4) + '\r\n'); return; } this.emit('data', line); }); }); this.socket?.addEventListener('error', (err) => this.emit('error', err)); this.socket?.addEventListener('close', (err) => { this.connected = false; this.socket = undefined; this.emit('close', err.reason); }); } }