core/src/types/protocol.ts

148 lines
3.2 KiB
TypeScript

import { randomBytes } from 'crypto';
import { EventEmitter } from 'events';
import { IPlugin } from '../plugin';
import { IMessage, IMessageTarget } from './message';
import { Formatter } from './message-format';
import { ProtocolFeatureFlag } from './protocol-flags';
/**
* The base class for a protocol handler.
*/
export class Protocol extends EventEmitter {
/**
* Protocol message formatter.
*/
public format: Formatter = new Formatter(false, false, this.flags);
/**
* Connection ID
*/
public id = randomBytes(4).toString('hex');
/**
* Protocol type name.
*/
public type = 'GenericProtocol';
/**
* Indicates that the protocol is currently running.
*/
public running = false;
/**
* This should be set to true when the protocol was stopped for any reason
* at any time.
*/
public stopped = false;
/**
* This will be set to true when the protocol fails for any reason
*/
public failed = false;
/**
* This identifies the bot itself.
*/
public me: IMessageTarget = {
id: '',
name: '',
};
/**
* @param plugin Reference to the plugin which provides this protocol.
* @param config Protocol connection instance configuration.
* @param flags Feature flags which describe this protocol.
*/
constructor(
public plugin: IPlugin,
public config: any,
public flags: ProtocolFeatureFlag[] = [
ProtocolFeatureFlag.EVENT_MESSAGE,
ProtocolFeatureFlag.PLAIN,
]
) {
super();
this.passEvents();
}
/**
* Protocol connection's configured name.
*/
public get name(): string {
return this.config.name;
}
/**
* Protocol's running status.
*/
public get status(): boolean {
return this.running;
}
/**
* Start the protocol. Create connections here.
* @param args Start arguments
*/
public start(...args: any[]): void {
this.running = true;
this.emit('running');
}
/**
* Stop the protocol. This should stop any connections.
* @param force Force stop
*/
public stop(force = false): void {
if (!this.running) {
return;
}
this.running = false;
this.stopped = true;
if (force) {
this.failed = true;
}
this.emit('stopped');
}
public resolve(message: IMessage, ...data: any[]): void {
throw new Error('Method not implemented.');
}
public async sendTo(target: string, ...data: any[]): Promise<boolean> {
throw new Error('Method not implemented.');
}
/**
* Full name of this protocol (`<plugin name>/<protocol connection name>`)
*/
public get fullName(): string {
return this.plugin.manifest.name + '/' + this.name;
}
/**
* Check if this protocol supports a feature flag
* @param flag Feature flag to check for
* @returns Boolean
*/
public supports(flag: ProtocolFeatureFlag | ProtocolFeatureFlag[]) {
return Array.isArray(flag)
? flag.every((entry) => this.flags.includes(entry))
: this.flags.includes(flag);
}
protected passEvents(): void {
this.on('stop', (force) => this.stop(force));
this.on('start', (...args: any[]) => {
// Prevent restarting from here, it's unsafe
if (this.status || (!this.status && this.stopped)) {
return;
}
this.start(...args);
});
}
}