/** Copyright Stewart Allen -- All Rights Reserved */ "use strict"; (function() { let moto = self.moto = self.moto || {}, ccvalue = self.navigator ? navigator.hardwareConcurrency || 1 : 1, ccmax = ccvalue > 3 ? ccvalue - 1 : 0, workcc = false, // concurrent or not workurl = null, // url to load worker worknum = 1, // number of workers to start workers = [], // array of all workers queue = []; // array of work requests if (moto.client) return; gapp.register('moto.client'); // code is running in the browser / client context let client = moto.client = { live: () => { return workers.length; }, free: () => { return workers.filter(w => w.run === null).length; }, max: () => { return ccmax; }, fn: {}, bind: (task) => { if (!client.fn[task]) { client.fn[task] = (data, options) => { return client.call(task, data, options); }; } }, call: (task, data, options = {}) => { let { direct, stream } = options; return new Promise((resolve, reject) => { let ondata, ondone, onerror = reject; if (!stream) { let accum = []; ondata = (data) => { accum.push(data); }; ondone = () => { resolve(accum); }; } else { ondata = stream; ondone = resolve; } client.queue(task, data, { direct, ondata, ondone, onerror }); }); }, queue: (task, data, options = {}) => { queue.push({task, data, options}); client.kick(); }, kick: () => { if (queue.length === 0) { return; } let rec, worker; outer: for (let qrec of queue) { let { options } = qrec; let { index } = options; if (index >= 0) { // worker designated by index let mod = index % workers.length; if (workers[mod].run === null) { worker = workers[mod]; rec = qrec; break; } } else { // first available worker for (let i=0; i w.run).length; }, stop: function() { for (let w of workers) { w.terminate(); } workers = []; }, // same as restart start: function(url = workurl, cc = workcc || 1) { workcc = cc; worknum = Math.min(ccmax, workcc); workurl = url; client.restart(url, cc); }, restart: function() { client.stop(); // send cancel/error notification to requestors for (let w of workers.filter(w => w.run)) { if (w.run.ondone) { w.run.ondone({error: "cancelled operation"}); } } for (let i=0; i