From 4765f9dc175faf152966647f65096c4747a79ef9 Mon Sep 17 00:00:00 2001 From: Victor Westerlund Date: Thu, 7 Oct 2021 12:47:20 +0200 Subject: [PATCH] 0.2.1 - Replaced `eval()` with namespaced method calls. - Created a class-scoped listener for incoming messages from worker - Renamed TaskManager to MonkeyManager --- Monkeydo.mjs | 36 +++++++----------- worker/Monkey.js | 27 ++++++++------ worker/MonkeyManager.mjs | 79 ++++++++++++++++++++++++++++++++++++++++ worker/TaskManager.mjs | 48 ------------------------ 4 files changed, 107 insertions(+), 83 deletions(-) create mode 100644 worker/MonkeyManager.mjs delete mode 100644 worker/TaskManager.mjs diff --git a/Monkeydo.mjs b/Monkeydo.mjs index 977d9a6..e67236b 100644 --- a/Monkeydo.mjs +++ b/Monkeydo.mjs @@ -1,10 +1,10 @@ -import { default as MonkeyWorker } from "./worker/TaskManager.mjs"; +import { default as MonkeyWorker } from "./worker/MonkeyManager.mjs"; export default class Monkeydo extends MonkeyWorker { - constructor(manifest = false) { - super(); + constructor(methods = {},manifest = false) { + super(methods); this.monkeydo = { - version: "0.2.0", + version: "0.2.1", debugLevel: 0, // Flag if debugging is enabled, regardless of level get debug() { @@ -32,26 +32,20 @@ export default class Monkeydo extends MonkeyWorker { } } - debug(...attachment) { + debug(...attachments) { if(this.monkeydo.debug) { - console.warn("-- Monkeydo debug -->",attachment); + console.warn("-- Monkeydo debug -->",attachments); return; } } - play() { - this.worker.postMessage(["SET_PLAYING",true]); - this.worker.addEventListener("message",message => eval(message.data)); - } - - pause() { - this.worker.postMessage(["SET_PLAYING",false]); - } - - loop(times) { - if(!times || times === "infinite") { - times = -1; + // Loop playback; -1 or false = infinite + loop(times = -1) { + // Typecast boolean to left shifted integer; + if(typeof times === "boolean") { + times = times ? -1 : 0; } + times = times < 0 ? -1 : times; this.setFlag("loop",times); } @@ -111,10 +105,6 @@ export default class Monkeydo extends MonkeyWorker { // Hand over the loaded manifest to the MonkeyWorker task manager const monkey = this.giveManifest(); - monkey.then(() => this.play()) - .catch(error => { - this.debug(error); - throw new Error(errorPrefix + "Failed to post manifest to worker thread"); - }); + this.play(); } } \ No newline at end of file diff --git a/worker/Monkey.js b/worker/Monkey.js index 3fa9d52..9bb7d66 100644 --- a/worker/Monkey.js +++ b/worker/Monkey.js @@ -11,7 +11,7 @@ class Monkey { loop: 0, // Loop n times; <0 = infinite } - this.i = 0; + this.i = 0; // Manifest iterator index this.queue = { task: null, next: null @@ -20,10 +20,9 @@ class Monkey { } // Parse task components and send them to main thread - run(data) { + run(task) { this.i++; // Advance index - postMessage(data); - console.log(this.i); + postMessage(["TASK",task]); } // Interrupt timeout and put monkey to sleep @@ -36,6 +35,7 @@ class Monkey { } play() { + // Stack playback as loops if flag is set if(this.flags.playing) { if(this.flags.stacking) { this.flags.loop++; @@ -49,9 +49,14 @@ class Monkey { queueNext() { this.flags.playing = 1; const data = this.data[this.i]; + const task = { + wait: data[0], + func: data[1], + args: data.slice(2) + }; // Schedule the current task to run after the specified wait time - this.queue.task = setTimeout(() => this.run(data.do),data.wait); + this.queue.task = setTimeout(() => this.run(task),task.wait); // We're out of tasks to schedule.. if(this.i >= this.dataLength) { @@ -62,13 +67,14 @@ class Monkey { return false; } - if(this.flags.loop <= -1) { + // Decrement loop iterations if not infinite (negative int) + if(this.flags.loop > 0) { this.flags.loop = this.flags.loop - 1; } } // Run this function again when the scheduled task will fire - this.queue.next = setTimeout(() => this.queueNext(),data.wait); + this.queue.next = setTimeout(() => this.queueNext(),task.wait); } } @@ -82,20 +88,18 @@ onmessage = (message) => { case "GIVE_MANIFEST": try { this.monkey = new Monkey(data); - postMessage("OK"); + postMessage(["RECEIVED_MANIFEST","OK"]); } catch(error) { - postMessage(["MANIFEST_ERROR",error]); + postMessage(["RECEIVED_MANIFEST",error]); } break; - // Set playstate case "SET_PLAYING": if(data === true) { this.monkey.play(); return; } - // Treat data that isn't a TRUE boolean as an interrupt this.monkey.interrupt(); break; @@ -105,7 +109,6 @@ onmessage = (message) => { break; case "SET_FLAG": - console.log(data); this.monkey.flags[data[0]] = data[1]; break; diff --git a/worker/MonkeyManager.mjs b/worker/MonkeyManager.mjs new file mode 100644 index 0000000..66d2dd7 --- /dev/null +++ b/worker/MonkeyManager.mjs @@ -0,0 +1,79 @@ +// Task manager for Monkeydo dedicated workers + +export default class MonkeyManager { + constructor(methods) { + // Object of scoped methods for this manifest + this.methods = {}; + Object.assign(this.methods,methods); + + // Get path of this file + let location = new URL(import.meta.url); + location = location.pathname.replace("MonkeyManager.mjs",""); // Get parent directory + + // Spawn a dedicated worker for scheduling events from manifest + this.worker = new Worker(location + "Monkey.js"); + this.worker.addEventListener("message",message => this.message(message)); + } + + // Get a status flag from the worker + async getFlag(flag) { + this.worker.postMessage(["GET_FLAG",flag]); + const response = await new Promise((resolve) => { + this.worker.addEventListener("message",message => resolve(message.data)); + }); + this.debug("GET_FLAG",flag,response); + return response; + } + + // Set a status flag for the worker + async setFlag(flag,value = 0) { + const flagExists = await this.getFlag(flag); + if(flagExists === null) { + this.debug(flagExists); + throw new Error("Flag does not not exist"); + } + this.worker.postMessage(["SET_FLAG",[flag,value]]); + } + + // Call method from object and pass arguments + runTask(task) { + this.methods[task.func](...task.args); + } + + play() { + this.worker.postMessage(["SET_PLAYING",true]); + } + + pause() { + this.worker.postMessage(["SET_PLAYING",false]); + } + + // Pass manifest to worker and await response + async giveManifest() { + this.worker.postMessage(["GIVE_MANIFEST",this.manifest]); + + const status = await new Promise((resolve,reject) => { + const ack = this.worker.addEventListener("message",message => { + if(message.data[0] !== "RECEIVED_MANIFEST") { + return false; + } + + if(message.data[1] !== "OK") { + reject(message.data); + } + resolve(); + }); + this.worker.removeEventListener("message",ack); + }); + return status; + } + + message(message) { + const type = message.data[0] ? message.data[0] : message.data; + const data = message.data[1]; + if(type !== "TASK") { + return false; + } + this.runTask(data); + } +} \ No newline at end of file diff --git a/worker/TaskManager.mjs b/worker/TaskManager.mjs deleted file mode 100644 index 5593323..0000000 --- a/worker/TaskManager.mjs +++ /dev/null @@ -1,48 +0,0 @@ -// Task manager for Monkeydo dedicated workers - -export default class TaskManager { - constructor() { - // Get path of this file - this.ready = false; - let location = new URL(import.meta.url); - location = location.pathname.replace("TaskManager.mjs",""); // Get parent directory - - // Spawn a dedicated worker for scheduling events from manifest - this.worker = new Worker(location + "Monkey.js"); - } - - // Get a status flag from the worker - async getFlag(flag) { - this.worker.postMessage(["GET_FLAG",flag]); - const response = await new Promise((resolve) => { - this.worker.addEventListener("message",message => resolve(message.data)); - }); - return response; - } - - // Set a status flag for the worker - async setFlag(flag,value = 0) { - const flagExists = await this.getFlag(flag); - if(!flagExists) { - this.debug(flagExists); - throw new Error("Flag does not not exist"); - } - this.worker.postMessage(["SET_FLAG",[flag,value]]); - } - - // Pass manifest to worker and await response - async giveManifest() { - this.worker.postMessage(["GIVE_MANIFEST",this.manifest]); - - // Wait for the worker to install the manifest - const ack = await new Promise((resolve,reject) => { - this.worker.addEventListener("message",message => { - if(message.data !== "OK") { - reject(message.data); - } - resolve(); - }); - }); - return ack; - } -} \ No newline at end of file