implement new sendTo method
This commit is contained in:
parent
bac88841b0
commit
2483a67088
9
cron/plugin.json
Normal file
9
cron/plugin.json
Normal file
@ -0,0 +1,9 @@
|
||||
{
|
||||
"main": "plugin.js",
|
||||
"name": "cron",
|
||||
"description": "API for plugin-scoped cron tasks",
|
||||
"tags": ["timers", "cron", "scheduler", "api"],
|
||||
"version": "1.0.0",
|
||||
"dependencies": ["control?"],
|
||||
"npmDependencies": ["node-cron@3.0.0"]
|
||||
}
|
166
cron/plugin.ts
Normal file
166
cron/plugin.ts
Normal file
@ -0,0 +1,166 @@
|
||||
import { logger } from '@squeebot/core/lib/core';
|
||||
import {
|
||||
Plugin,
|
||||
Configurable,
|
||||
EventListener,
|
||||
IPlugin,
|
||||
} from '@squeebot/core/lib/plugin';
|
||||
|
||||
import nodeCron, { ScheduledTask } from 'node-cron';
|
||||
|
||||
type ExecutorFn = (...args: any[]) => void;
|
||||
|
||||
class CronWrapper {
|
||||
private cronTask: ScheduledTask | null = null;
|
||||
public id = Math.random().toString(36).slice(2);
|
||||
public stopped = true;
|
||||
public destroyed = false;
|
||||
|
||||
constructor(
|
||||
public expression: string,
|
||||
public taskFn: ExecutorFn,
|
||||
public origin: IPlugin,
|
||||
) {}
|
||||
|
||||
assert(): void {
|
||||
if (!nodeCron.validate(this.expression)) {
|
||||
throw new Error('Invalid cron pattern!');
|
||||
}
|
||||
}
|
||||
|
||||
start(): void {
|
||||
if (this.destroyed) {
|
||||
logger.warn('[cron] Someone tried to start a destroyed task! This could indicate a memory leak!');
|
||||
return;
|
||||
}
|
||||
|
||||
if (!this.cronTask) {
|
||||
this.assert();
|
||||
this.cronTask = nodeCron.schedule(this.expression, this.execute, {
|
||||
scheduled: false,
|
||||
});
|
||||
}
|
||||
|
||||
this.cronTask.start();
|
||||
this.stopped = false;
|
||||
}
|
||||
|
||||
stop(): void {
|
||||
if (!this.cronTask) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.cronTask.stop();
|
||||
this.stopped = true;
|
||||
}
|
||||
|
||||
destroy(): void {
|
||||
this.destroyed = true;
|
||||
|
||||
if (!this.cronTask) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.cronTask.destroy();
|
||||
this.cronTask = null;
|
||||
}
|
||||
|
||||
execute(): void {
|
||||
this.taskFn.call(this.origin);
|
||||
}
|
||||
|
||||
belongsTo(plugin: IPlugin | string): boolean {
|
||||
if (typeof plugin === 'string') {
|
||||
return this.origin.manifest.name === plugin;
|
||||
}
|
||||
return plugin === this.origin ||
|
||||
plugin.manifest.name === this.origin.manifest.name;
|
||||
}
|
||||
}
|
||||
|
||||
// @Configurable({})
|
||||
class CronPlugin extends Plugin {
|
||||
private timers: CronWrapper[] = [];
|
||||
|
||||
@EventListener('pluginUnload')
|
||||
public unloadEventHandler(plugin: string | Plugin): void {
|
||||
if (plugin === this.name || plugin === this) {
|
||||
this.timers.forEach((timer) => timer.destroy());
|
||||
this.timers = [];
|
||||
this.emit('pluginUnloaded', this);
|
||||
}
|
||||
}
|
||||
|
||||
@EventListener('pluginUnloaded')
|
||||
public unloadedEventHandler(plugin: string | Plugin): void {
|
||||
this.timers.forEach((timer) => {
|
||||
if (timer.belongsTo(plugin)) {
|
||||
timer.destroy();
|
||||
}
|
||||
});
|
||||
this.cleanUp();
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns A list of tasks including id, cron expression and origin plugin.
|
||||
*/
|
||||
public getList(): string[][] {
|
||||
return this.timers.map((timer) => ([
|
||||
timer.id,
|
||||
timer.expression,
|
||||
timer.origin.manifest.name,
|
||||
timer.destroyed || timer.stopped ? 'stopped' : 'running',
|
||||
]));
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a new cron task
|
||||
* @param plugin Plugin registering this task
|
||||
* @param expression Cron expression
|
||||
* @param taskFn Function to execute
|
||||
* @param autostart Start the scheduler on add
|
||||
* @returns The task
|
||||
*/
|
||||
public registerTimer(
|
||||
plugin: IPlugin,
|
||||
expression: string,
|
||||
taskFn: ExecutorFn,
|
||||
autostart = true,
|
||||
): CronWrapper {
|
||||
const newTimer = new CronWrapper(expression, taskFn, plugin);
|
||||
|
||||
newTimer.assert();
|
||||
if (autostart) {
|
||||
newTimer.start();
|
||||
}
|
||||
|
||||
return newTimer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a scheduled timer by ID or by the object itself.
|
||||
* Always use this to ensure that memory is properly cleared.
|
||||
* @param timer Timer or timer ID
|
||||
*/
|
||||
public removeTimer(timer: string | CronWrapper): void {
|
||||
if (typeof timer === 'string') {
|
||||
const find = this.timers.find((item) => item.id === timer);
|
||||
if (find) {
|
||||
find.destroy();
|
||||
}
|
||||
} else {
|
||||
timer.destroy();
|
||||
}
|
||||
|
||||
this.cleanUp();
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove destroyed timers from the cache
|
||||
*/
|
||||
private cleanUp(): void {
|
||||
this.timers = this.timers.filter((timer) => !timer.destroyed);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = CronPlugin;
|
85
package-lock.json
generated
85
package-lock.json
generated
@ -10,10 +10,12 @@
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"@squeebot/core": "^3.3.1",
|
||||
"node-cron": "^3.0.0",
|
||||
"typescript": "^4.4.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^16.7.10"
|
||||
"@types/node": "^16.7.10",
|
||||
"@types/node-cron": "^2.0.4"
|
||||
}
|
||||
},
|
||||
"../core": {
|
||||
@ -54,6 +56,21 @@
|
||||
"integrity": "sha512-S63Dlv4zIPb8x6MMTgDq5WWRJQe56iBEY0O3SOFA9JrRienkOVDXSXBjjJw6HTNQYSE2JI6GMCR6LVbIMHJVvA==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@types/node-cron": {
|
||||
"version": "2.0.4",
|
||||
"resolved": "https://registry.npmjs.org/@types/node-cron/-/node-cron-2.0.4.tgz",
|
||||
"integrity": "sha512-vXzgDRWCZpuut5wJVZtluEnkNhzGojYlyMch2c4kMj7H74L8xTLytVlgQzj+/17wfcjs49aJDFBDglFSGt7GeA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@types/tz-offset": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/tz-offset": {
|
||||
"version": "0.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@types/tz-offset/-/tz-offset-0.0.0.tgz",
|
||||
"integrity": "sha512-XLD/llTSB6EBe3thkN+/I0L+yCTB6sjrcVovQdx2Cnl6N6bTzHmwe/J8mWnsXFgxLrj/emzdv8IR4evKYG2qxQ==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/at-least-node": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz",
|
||||
@ -164,6 +181,36 @@
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/moment": {
|
||||
"version": "2.29.1",
|
||||
"resolved": "https://registry.npmjs.org/moment/-/moment-2.29.1.tgz",
|
||||
"integrity": "sha512-kHmoybcPV8Sqy59DwNDY3Jefr64lK/by/da0ViFcuA4DH0vQg5Q6Ze5VimxkfQNSC+Mls/Kx53s7TjP1RhFEDQ==",
|
||||
"engines": {
|
||||
"node": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/moment-timezone": {
|
||||
"version": "0.5.33",
|
||||
"resolved": "https://registry.npmjs.org/moment-timezone/-/moment-timezone-0.5.33.tgz",
|
||||
"integrity": "sha512-PTc2vcT8K9J5/9rDEPe5czSIKgLoGsH8UNpA4qZTVw0Vd/Uz19geE9abbIOQKaAQFcnQ3v5YEXrbSc5BpshH+w==",
|
||||
"dependencies": {
|
||||
"moment": ">= 2.9.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/node-cron": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/node-cron/-/node-cron-3.0.0.tgz",
|
||||
"integrity": "sha512-DDwIvvuCwrNiaU7HEivFDULcaQualDv7KoNlB/UU1wPW0n1tDEmBJKhEIE6DlF2FuoOHcNbLJ8ITL2Iv/3AWmA==",
|
||||
"dependencies": {
|
||||
"moment-timezone": "^0.5.31"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/semver": {
|
||||
"version": "7.3.5",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz",
|
||||
@ -238,6 +285,21 @@
|
||||
"integrity": "sha512-S63Dlv4zIPb8x6MMTgDq5WWRJQe56iBEY0O3SOFA9JrRienkOVDXSXBjjJw6HTNQYSE2JI6GMCR6LVbIMHJVvA==",
|
||||
"dev": true
|
||||
},
|
||||
"@types/node-cron": {
|
||||
"version": "2.0.4",
|
||||
"resolved": "https://registry.npmjs.org/@types/node-cron/-/node-cron-2.0.4.tgz",
|
||||
"integrity": "sha512-vXzgDRWCZpuut5wJVZtluEnkNhzGojYlyMch2c4kMj7H74L8xTLytVlgQzj+/17wfcjs49aJDFBDglFSGt7GeA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@types/tz-offset": "*"
|
||||
}
|
||||
},
|
||||
"@types/tz-offset": {
|
||||
"version": "0.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@types/tz-offset/-/tz-offset-0.0.0.tgz",
|
||||
"integrity": "sha512-XLD/llTSB6EBe3thkN+/I0L+yCTB6sjrcVovQdx2Cnl6N6bTzHmwe/J8mWnsXFgxLrj/emzdv8IR4evKYG2qxQ==",
|
||||
"dev": true
|
||||
},
|
||||
"at-least-node": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz",
|
||||
@ -316,6 +378,27 @@
|
||||
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz",
|
||||
"integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw=="
|
||||
},
|
||||
"moment": {
|
||||
"version": "2.29.1",
|
||||
"resolved": "https://registry.npmjs.org/moment/-/moment-2.29.1.tgz",
|
||||
"integrity": "sha512-kHmoybcPV8Sqy59DwNDY3Jefr64lK/by/da0ViFcuA4DH0vQg5Q6Ze5VimxkfQNSC+Mls/Kx53s7TjP1RhFEDQ=="
|
||||
},
|
||||
"moment-timezone": {
|
||||
"version": "0.5.33",
|
||||
"resolved": "https://registry.npmjs.org/moment-timezone/-/moment-timezone-0.5.33.tgz",
|
||||
"integrity": "sha512-PTc2vcT8K9J5/9rDEPe5czSIKgLoGsH8UNpA4qZTVw0Vd/Uz19geE9abbIOQKaAQFcnQ3v5YEXrbSc5BpshH+w==",
|
||||
"requires": {
|
||||
"moment": ">= 2.9.0"
|
||||
}
|
||||
},
|
||||
"node-cron": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/node-cron/-/node-cron-3.0.0.tgz",
|
||||
"integrity": "sha512-DDwIvvuCwrNiaU7HEivFDULcaQualDv7KoNlB/UU1wPW0n1tDEmBJKhEIE6DlF2FuoOHcNbLJ8ITL2Iv/3AWmA==",
|
||||
"requires": {
|
||||
"moment-timezone": "^0.5.31"
|
||||
}
|
||||
},
|
||||
"semver": {
|
||||
"version": "7.3.5",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz",
|
||||
|
@ -12,9 +12,11 @@
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"@squeebot/core": "^3.3.1",
|
||||
"node-cron": "^3.0.0",
|
||||
"typescript": "^4.4.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^16.7.10"
|
||||
"@types/node": "^16.7.10",
|
||||
"@types/node-cron": "^2.0.4"
|
||||
}
|
||||
}
|
||||
|
@ -5,6 +5,10 @@
|
||||
"name": "control",
|
||||
"version": "0.1.1"
|
||||
},
|
||||
{
|
||||
"name": "cron",
|
||||
"version": "1.0.0"
|
||||
},
|
||||
{
|
||||
"name": "permissions",
|
||||
"version": "0.1.0"
|
||||
@ -12,6 +16,10 @@
|
||||
{
|
||||
"name": "simplecommands",
|
||||
"version": "1.1.1"
|
||||
},
|
||||
{
|
||||
"name": "xprotocol",
|
||||
"version": "1.0.0"
|
||||
}
|
||||
],
|
||||
"typescript": true
|
||||
|
9
xprotocol/plugin.json
Normal file
9
xprotocol/plugin.json
Normal file
@ -0,0 +1,9 @@
|
||||
{
|
||||
"main": "plugin.js",
|
||||
"name": "xprotocol",
|
||||
"description": "API for sending messages to other protocols",
|
||||
"tags": ["messages", "relaying", "api"],
|
||||
"version": "1.0.0",
|
||||
"dependencies": ["control?"],
|
||||
"npmDependencies": []
|
||||
}
|
55
xprotocol/plugin.ts
Normal file
55
xprotocol/plugin.ts
Normal file
@ -0,0 +1,55 @@
|
||||
import { ISqueebotCore, logger } from '@squeebot/core/lib/core';
|
||||
import {
|
||||
Plugin,
|
||||
EventListener,
|
||||
} from '@squeebot/core/lib/plugin';
|
||||
|
||||
class XProtocolPlugin extends Plugin {
|
||||
private core: ISqueebotCore | null = null;
|
||||
|
||||
@EventListener('pluginUnload')
|
||||
public unloadEventHandler(plugin: string | Plugin): void {
|
||||
if (plugin === this.name || plugin === this) {
|
||||
this.core = null;
|
||||
this.emit('pluginUnloaded', this);
|
||||
}
|
||||
}
|
||||
|
||||
public async sendTo(target: string, ...data: any[]): Promise<boolean> {
|
||||
if (!this.core) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Find target plugin
|
||||
const rxSplit = target.split('/');
|
||||
const plugin = this.core.pluginManager.getLoadedByName(rxSplit[0]);
|
||||
if (!plugin || !plugin.service) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Find target protocol
|
||||
const protocol = plugin.service.getProtocolByName(rxSplit[1]);
|
||||
if (!protocol || !protocol.running) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return protocol.sendTo(target, ...data);
|
||||
}
|
||||
|
||||
initialize(): void {
|
||||
this.on('core', (core: ISqueebotCore) => {
|
||||
this.core = core;
|
||||
});
|
||||
|
||||
this.emitTo('core', 'request-core', this.name);
|
||||
|
||||
this.on('send', (data: any[]) => {
|
||||
const target = data[0];
|
||||
this.sendTo(target, ...data.slice(1)).catch((error: Error) => {
|
||||
logger.error(`[sendto] Sending to protocol from event failed:`, error.message ?? error);
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = XProtocolPlugin;
|
Loading…
Reference in New Issue
Block a user