You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
session-desktop/js/modules/util_worker_interface.js

119 lines
2.7 KiB
JavaScript

/* global Worker, window, setTimeout */
const WORKER_TIMEOUT = 60 * 1000; // one minute
class TimedOutError extends Error {
constructor(message) {
super(message);
this.name = this.constructor.name;
if (typeof Error.captureStackTrace === 'function') {
Error.captureStackTrace(this, this.constructor);
} else {
this.stack = new Error(message).stack;
}
}
}
class WorkerInterface {
constructor(path, timeout = WORKER_TIMEOUT) {
this._utilWorker = new Worker(path);
this.timeout = timeout;
this._jobs = Object.create(null);
this._DEBUG = false;
this._jobCounter = 0;
this._utilWorker.onmessage = e => {
const [jobId, errorForDisplay, result] = e.data;
const job = this._getJob(jobId);
if (!job) {
throw new Error(
`Received worker reply to job ${jobId}, but did not have it in our registry!`
);
}
const { resolve, reject, fnName } = job;
if (errorForDisplay) {
return reject(
new Error(`Error received from worker job ${jobId} (${fnName}): ${errorForDisplay}`)
);
}
return resolve(result);
};
}
_makeJob(fnName) {
this._jobCounter += 1;
const id = this._jobCounter;
if (this._DEBUG) {
window.log.info(`Worker job ${id} (${fnName}) started`);
}
this._jobs[id] = {
fnName,
start: Date.now(),
};
return id;
}
_updateJob(id, data) {
const { resolve, reject } = data;
const { fnName, start } = this._jobs[id];
this._jobs[id] = {
...this._jobs[id],
...data,
resolve: value => {
this._removeJob(id);
const end = Date.now();
if (this._DEBUG) {
window.log.info(`Worker job ${id} (${fnName}) succeeded in ${end - start}ms`);
}
return resolve(value);
},
reject: error => {
this._removeJob(id);
const end = Date.now();
window.log.info(`Worker job ${id} (${fnName}) failed in ${end - start}ms`);
return reject(error);
},
};
}
_removeJob(id) {
if (this._DEBUG) {
this._jobs[id].complete = true;
} else {
delete this._jobs[id];
}
}
_getJob(id) {
return this._jobs[id];
}
callWorker(fnName, ...args) {
const jobId = this._makeJob(fnName);
return new Promise((resolve, reject) => {
this._utilWorker.postMessage([jobId, fnName, ...args]);
this._updateJob(jobId, {
resolve,
reject,
args: this._DEBUG ? args : null,
});
setTimeout(
() => reject(new TimedOutError(`Worker job ${jobId} (${fnName}) timed out`)),
this.timeout
);
});
}
}
module.exports = WorkerInterface;