91 lines
2.3 KiB
TypeScript
91 lines
2.3 KiB
TypeScript
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<IRCConnectorEvents>
|
|
implements IIRCConnector
|
|
{
|
|
connected = false;
|
|
private socket?: WebSocket;
|
|
private pingInterval?: any;
|
|
private lastPingName?: string;
|
|
|
|
constructor(
|
|
public secure: boolean,
|
|
public host: string,
|
|
public port?: number,
|
|
public connOpts?: Record<string, unknown>,
|
|
) {
|
|
super();
|
|
}
|
|
|
|
connect(): Promise<void> {
|
|
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;
|
|
this.pingInterval = setInterval(() => {
|
|
this.lastPingName = Date.now().toString();
|
|
this.write('PING :%s', this.lastPingName);
|
|
}, 60000);
|
|
resolve();
|
|
};
|
|
|
|
try {
|
|
this.socket = new WebSocket(url);
|
|
} catch (e: unknown) {
|
|
return reject(e);
|
|
}
|
|
|
|
this.socket?.addEventListener('open', onConnect);
|
|
this.handle();
|
|
});
|
|
}
|
|
|
|
async destroy(): Promise<void> {
|
|
this.connected = false;
|
|
this.socket?.close();
|
|
this.socket = undefined;
|
|
clearInterval(this.pingInterval);
|
|
}
|
|
|
|
write(format: string, ...args: any[]): void {
|
|
this.socket?.send(formatstr(format, ...args));
|
|
}
|
|
|
|
private handle() {
|
|
this.socket?.addEventListener('message', (event) => {
|
|
const line = event.data.toString();
|
|
|
|
if (line.indexOf('PING') === 0 && !this.connOpts?.skipPings) {
|
|
this.socket?.send('PONG' + line.substring(4));
|
|
return;
|
|
}
|
|
|
|
if (
|
|
line.indexOf('PONG') === 0 &&
|
|
line.includes(' :' + this.lastPingName)
|
|
) {
|
|
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;
|
|
clearInterval(this.pingInterval);
|
|
this.emit('close', err.reason);
|
|
});
|
|
}
|
|
}
|