import net, { Socket } from 'net'; import tls, { TLSSocket } from 'tls'; 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 IRCSocketConnector extends TypedEventEmitter implements IIRCConnector { connected = false; private socket?: Socket | TLSSocket; constructor( public secure: boolean, public host: string, public port?: number, public connOpts?: Record, ) { super(); } connect(): Promise { const opts = { host: this.host, port: this.port || 6667, ...this.connOpts }; return new Promise((resolve, reject) => { const onConnect = () => { this.connected = true; resolve(); }; try { if (this.secure) { this.socket = tls.connect(opts, onConnect); } else { this.socket = net.connect(opts, onConnect); } } catch (e: unknown) { return reject(e); } this.handle(); }); } async destroy(): Promise { this.connected = false; this.socket?.destroy(); this.socket = undefined; } write(format: string, ...args: any[]): void { this.socket?.write(formatstr(format, ...args) + '\r\n'); } private handle() { this.socket?.setDefaultEncoding('utf-8'); let buffer: string = ''; this.socket?.on('data', (chunk: string) => { 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?.write('PONG' + line.substring(4) + '\r\n'); return; } this.emit('data', line); }); }); this.socket?.on('error', (err) => this.emit('error', err)); this.socket?.on('close', (err) => { this.connected = false; this.socket = undefined; this.emit('close', err); }); } }