@dashevo/wallet-lib
Version:
Light wallet library for Dash
147 lines (123 loc) • 4.13 kB
JavaScript
const _ = require('lodash');
const StandardPlugin = require('./StandardPlugin');
// eslint-disable-next-line no-underscore-dangle
const _defaultOpts = {
workerIntervalTime: 10 * 1000,
executeOnStart: false,
firstExecutionRequired: false,
workerMaxPass: null,
executeAfterStart: false,
};
class Worker extends StandardPlugin {
constructor(opts = JSON.parse(JSON.stringify(_defaultOpts))) {
const defaultOpts = JSON.parse(JSON.stringify(_defaultOpts));
super({ type: 'Worker', ...opts });
this.worker = null;
this.workerPass = 0;
this.isWorkerRunning = false;
this.awaitOnInjection = _.has(opts, 'awaitOnInjection')
? opts.awaitOnInjection
: false;
this.firstExecutionRequired = _.has(opts, 'firstExecutionRequired')
? opts.firstExecutionRequired
: defaultOpts.firstExecutionRequired;
this.executeOnStart = _.has(opts, 'executeOnStart')
? opts.executeOnStart
: defaultOpts.executeOnStart;
this.workerIntervalTime = _.has(opts, 'workerIntervalTime')
? opts.workerIntervalTime
: defaultOpts.workerIntervalTime;
this.workerMaxPass = (opts.workerMaxPass)
? opts.workerMaxPass
: defaultOpts.workerMaxPass;
this.state = {
started: false,
ready: false,
};
}
async startWorker() {
let payloadResult = null;
const self = this;
const eventTypeStarting = `WORKER/${this.name.toUpperCase()}/STARTING`;
this.parentEvents.emit(eventTypeStarting, { type: eventTypeStarting, payload: payloadResult });
try {
if (this.worker) await this.stopWorker();
if (this.workerIntervalTime > 0) {
this.worker = setInterval(this.execWorker.bind(self), this.workerIntervalTime);
}
if (this.executeOnStart === true) {
if (this.onStart) {
payloadResult = await this.onStart();
}
}
const eventTypeStarted = `WORKER/${this.name.toUpperCase()}/STARTED`;
this.parentEvents.emit(eventTypeStarted, { type: eventTypeStarted, payload: payloadResult });
this.state.started = true;
// TODO: refactor this to be more elegant
// This change is needed to refine plugin execution sequence
// with the least amount of refactoring
if (this.executeOnStart && this.executeAfterStart) {
await this.execWorker();
}
} catch (e) {
this.emit('error', e, {
type: 'plugin',
pluginType: 'worker',
pluginName: this.name,
});
}
}
/**
* @param {Object} [options]
* @param {Boolean} [options.force=false]
* @param {Boolean} [options.reason]
* @returns {Promise<void>}
*/
async stopWorker(options = {}) {
let payloadResult = options.reason;
clearInterval(this.worker);
this.worker = null;
this.workerPass = 0;
this.isWorkerRunning = false;
const eventType = `WORKER/${this.name.toUpperCase()}/STOPPED`;
if (this.onStop) {
payloadResult = await this.onStop(options);
}
this.state.started = false;
this.parentEvents.emit(eventType, { type: eventType, payload: payloadResult });
}
async execWorker() {
let payloadResult = null;
if (this.isWorkerRunning) {
return false;
}
if (this.workerMaxPass !== null && this.workerPass >= this.workerMaxPass) {
await this.stopWorker();
return false;
}
this.isWorkerRunning = true;
if (this.execute) {
try {
payloadResult = await this.execute();
} catch (e) {
await this.stopWorker({
reason: e.message,
});
this.emit('error', e, {
type: 'plugin',
pluginType: 'worker',
pluginName: this.name,
});
}
} else {
throw new Error(`Worker ${this.name}: Missing execute function`);
}
this.isWorkerRunning = false;
this.workerPass += 1;
if (!this.state.ready) this.state.ready = true;
const eventType = `WORKER/${this.name.toUpperCase()}/EXECUTED`;
this.parentEvents.emit(eventType, { type: eventType, payload: payloadResult });
return true;
}
}
module.exports = Worker;