171 lines
4.0 KiB
TypeScript
171 lines
4.0 KiB
TypeScript
/* eslint-disable @typescript-eslint/no-empty-function */
|
|
import { EMessageType, IMessage } from './message';
|
|
import { Protocol } from './protocol';
|
|
|
|
/**
|
|
* Service is used to run, keep track of and kill Protocols.
|
|
*/
|
|
export class Service {
|
|
private protocols: Map<string, Protocol> = new Map();
|
|
private stopped = false;
|
|
|
|
constructor(private protoType: any) {}
|
|
|
|
public setExternalEvents(pto: Protocol): void {
|
|
const eventMessage: IMessage = {
|
|
type: EMessageType.protocolStart,
|
|
resolve: () => {},
|
|
reject: () => {},
|
|
mention: () => '',
|
|
data: pto,
|
|
source: pto,
|
|
text: `Protocol ${pto.fullName} running`,
|
|
time: new Date(),
|
|
resolved: true,
|
|
};
|
|
|
|
pto.on('running', () => {
|
|
pto.plugin.stream.emitTo('channel', 'event', eventMessage);
|
|
});
|
|
|
|
pto.on('stopped', () => {
|
|
pto.plugin.stream.emitTo('channel', 'event', {
|
|
...eventMessage,
|
|
type: EMessageType.protocolExit,
|
|
text: `Protocol ${pto.fullName} stopped`,
|
|
});
|
|
|
|
// TODO: restart handling
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Add a new protocol to this service.
|
|
* @param pto Protocol instance
|
|
* @param autostart Automatically start the protocol
|
|
* @returns Protocol instance
|
|
*/
|
|
public use(pto: Protocol, autostart = true): Protocol {
|
|
// This service is no longer accepting new protocols
|
|
if (this.stopped) {
|
|
return pto;
|
|
}
|
|
|
|
const n = pto.name;
|
|
if (n == null || n === '') {
|
|
throw new Error('Invalid Protocol configuration: Needs an unique name!');
|
|
}
|
|
|
|
if (this.protocols.has(n)) {
|
|
return this.protocols.get(n) as Protocol;
|
|
}
|
|
|
|
this.protocols.set(n, pto);
|
|
this.setExternalEvents(pto);
|
|
|
|
if (autostart) {
|
|
pto.start();
|
|
}
|
|
|
|
return pto;
|
|
}
|
|
|
|
/**
|
|
* Stop a protocol running in this service
|
|
* @param pto Protocol instance or name
|
|
* @param force Force stop
|
|
*/
|
|
public stop(pto: string | Protocol, force = false): void {
|
|
let proto: Protocol;
|
|
if (typeof pto === 'string') {
|
|
if (!this.protocols.get(pto)) {
|
|
return;
|
|
}
|
|
proto = this.protocols.get(pto) as Protocol;
|
|
} else {
|
|
proto = pto;
|
|
if (!this.protocols.get(pto.name)) {
|
|
// Not part of this service!
|
|
return;
|
|
}
|
|
}
|
|
proto.stop(force);
|
|
this.protocols.delete(proto.name);
|
|
}
|
|
|
|
/**
|
|
* Find a protocol by name.
|
|
* @param name Protocol name
|
|
* @returns Protocol instance or undefined
|
|
*/
|
|
public getProtocolByName(name: string): Protocol | undefined {
|
|
return this.protocols.get(name);
|
|
}
|
|
|
|
/**
|
|
* Get all protocol instances running in this service.
|
|
* @returns List of all protocol instances running in this service
|
|
*/
|
|
public getAll(): Protocol[] {
|
|
return Array.from(this.protocols.values());
|
|
}
|
|
|
|
/**
|
|
* Gracefully stops everything running in this service
|
|
*/
|
|
public stopAll(): Promise<void> {
|
|
return new Promise((resolve, reject) => {
|
|
if (this.stopped) {
|
|
return resolve();
|
|
}
|
|
|
|
let toStop = +this.protocols.size;
|
|
let killed = false;
|
|
|
|
// Nothing to stop
|
|
if (toStop === 0) {
|
|
return resolve();
|
|
}
|
|
|
|
// If the protocols fail to stop within a time frame, we have to kill
|
|
// them in order to prevent lingering connections.
|
|
const killTimeout = setTimeout(() => {
|
|
killed = true;
|
|
this.die();
|
|
resolve();
|
|
}, 10000);
|
|
|
|
// Stop everything and wait for them to announce the fact
|
|
// that they've stopped.
|
|
this.stopped = true;
|
|
for (const [name, proto] of this.protocols) {
|
|
proto.once('stopped', () => {
|
|
if (killed) {
|
|
return;
|
|
}
|
|
|
|
toStop--;
|
|
|
|
if (toStop <= 0) {
|
|
this.protocols.clear();
|
|
clearTimeout(killTimeout);
|
|
resolve();
|
|
}
|
|
});
|
|
proto.stop();
|
|
}
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Forcefully kills everything running in this service,
|
|
*/
|
|
public die(): void {
|
|
this.stopped = true;
|
|
for (const [name, proto] of this.protocols) {
|
|
proto.stop(true);
|
|
}
|
|
this.protocols.clear();
|
|
}
|
|
}
|