import {
|
|
logger
|
|
} from './logger.js'
|
|
|
|
const NAME = 'Events';
|
|
|
|
let watches = {};
|
|
let triggers = {};
|
|
let id = 0;
|
|
|
|
Array.prototype.removeIf = function (callback) {
|
|
let i = this.length;
|
|
while (i--) {
|
|
if (callback(this[i], i)) {
|
|
this.splice(i, 1);
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
};
|
|
|
|
export class Events {
|
|
|
|
/**
|
|
* Similar in operation to `Hooks.on`, with two exceptions. First, the provided function
|
|
* can be asynchronous and will be awaited. Second, an optional `conditionFn` parameter
|
|
* is added to help compartmentalize logic between detecting the desired event and responding to said event.
|
|
*
|
|
* @param {String} name Event name to watch for; It is recommended to use the enums found in {@link warpgate.EVENT}
|
|
* @param {function(object):Promise|void} fn Function to execute when this event has passed the condition function. Will be awaited
|
|
* @param {function(object):boolean} [condition = ()=>true] Optional. Function to determine if the event function should
|
|
* be executed. While not strictly required, as the `fn` function could simply return as a NOOP, providing this
|
|
* parameter may help compartmentalize "detection" vs "action" processing.
|
|
*
|
|
* @returns {number} Function id assigned to this event, for use with {@link warpgate.event.remove}
|
|
*/
|
|
static watch(name, fn, condition = () => {
|
|
return true;
|
|
}) {
|
|
if (!watches[name]) watches[name] = [];
|
|
id++;
|
|
watches[name].push({
|
|
fn,
|
|
condition,
|
|
id
|
|
});
|
|
return id;
|
|
}
|
|
|
|
/**
|
|
* Identical to {@link warpgate.event.watch}, except that this function will only be called once, after the condition is met.
|
|
*
|
|
* @see {@link warpgate.event.watch}
|
|
*/
|
|
static trigger(name, fn, condition = () => {
|
|
return true;
|
|
}) {
|
|
if (!triggers[name]) triggers[name] = [];
|
|
id++;
|
|
triggers[name].push({
|
|
fn,
|
|
condition,
|
|
id
|
|
});
|
|
return id;
|
|
}
|
|
|
|
|
|
static async run(name, data) {
|
|
for (const {
|
|
fn,
|
|
condition,
|
|
id
|
|
} of watches[name] ?? []) {
|
|
try {
|
|
if (condition(data)) {
|
|
logger.debug(`${name} | ${id} passes watch condition`);
|
|
await fn(data);
|
|
} else {
|
|
logger.debug(`${name} | ${id} fails watch condition`);
|
|
}
|
|
} catch (e) {
|
|
logger.error(`${NAME} | error`, e, `\n \nIn watch function (${name})\n`, fn);
|
|
}
|
|
}
|
|
|
|
let {
|
|
run,
|
|
keep
|
|
} = (triggers[name] ?? []).reduce((acum, elem) => {
|
|
try {
|
|
const passed = elem.condition(data);
|
|
if (passed) {
|
|
logger.debug(`${name} | ${elem.id} passes trigger condition`);
|
|
acum.run.push(elem);
|
|
} else {
|
|
logger.debug(`${name} | ${elem.id} fails trigger condition`);
|
|
acum.keep.push(elem);
|
|
}
|
|
} catch (e) {
|
|
logger.error(`${NAME} | error`, e, `\n \nIn trigger condition function (${name})\n`, elem.condition);
|
|
return acum;
|
|
} finally {
|
|
return acum;
|
|
}
|
|
}, {
|
|
run: [],
|
|
keep: []
|
|
});
|
|
|
|
for (const {
|
|
fn,
|
|
id
|
|
} of run) {
|
|
logger.debug(`${name} | calling trigger ${id}`);
|
|
try {
|
|
await fn(data);
|
|
} catch (e) {
|
|
logger.error(`${NAME} | error`, e, `\n \nIn trigger function (${name})\n`, fn);
|
|
}
|
|
}
|
|
|
|
triggers[name] = keep;
|
|
}
|
|
|
|
/**
|
|
* Removes a `watch` or `trigger` by its provided id -- obtained by the return value of `watch` and `trigger`.
|
|
*
|
|
* @param {number} id Numerical ID of the event function to remove.
|
|
*
|
|
* @see warpgate.event.watch
|
|
* @see warpgate.event.trigger
|
|
*/
|
|
static remove(id) {
|
|
const searchFn = (elem) => {
|
|
return elem.id === id
|
|
};
|
|
|
|
const tryRemove = (page) => page.removeIf(searchFn);
|
|
|
|
const hookRemove = Object.values(watches).map(tryRemove).reduce((sum, current) => {
|
|
return sum || current
|
|
}, false);
|
|
|
|
const triggerRemove = Object.values(triggers).map(tryRemove).reduce((sum, current) => {
|
|
return sum || current
|
|
}, false);
|
|
|
|
return hookRemove || triggerRemove;
|
|
}
|
|
}
|