diff --git a/Monkeydo.mjs b/Monkeydo.mjs index c0f5002..977d9a6 100644 --- a/Monkeydo.mjs +++ b/Monkeydo.mjs @@ -4,13 +4,13 @@ export default class Monkeydo extends MonkeyWorker { constructor(manifest = false) { super(); this.monkeydo = { - version: "0.1", + version: "0.2.0", debugLevel: 0, // Flag if debugging is enabled, regardless of level get debug() { return this.debugLevel > 0 ? true : false; }, - // Set debug level. Non-verbose debugging by default + // Set debug level. Non-verbose debugging if called without an argument set debug(level = 1) { this.debugLevel = level; } @@ -32,13 +32,29 @@ export default class Monkeydo extends MonkeyWorker { } } - debug(attachment = "DEBUG_EMPTY") { + debug(...attachment) { if(this.monkeydo.debug) { console.warn("-- Monkeydo debug -->",attachment); 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; + } + this.setFlag("loop",times); + } + // Load a Monkeydo manifest from JSON via string or URL async load(manifest) { const errorPrefix = "MANIFEST_IMPORT_FAILED: "; diff --git a/worker/Monkey.js b/worker/Monkey.js index eb0a2ff..3fa9d52 100644 --- a/worker/Monkey.js +++ b/worker/Monkey.js @@ -5,6 +5,12 @@ class Monkey { this.data = manifest.body; this.dataLength = this.data.length - 1; + this.flags = { + playing: 0, + stacking: 0, // Subsequent calls to play() will build a queue (jQuery-style) + loop: 0, // Loop n times; <0 = infinite + } + this.i = 0; this.queue = { task: null, @@ -13,38 +19,66 @@ class Monkey { Object.seal(this.queue); } + // Parse task components and send them to main thread run(data) { - this.i++; + this.i++; // Advance index postMessage(data); + console.log(this.i); } - queueNext() { - const data = this.data[this.i]; - this.queue.task = setTimeout(() => this.run(data.do),data.wait); - - // Schedule next task if it's not the last - if(this.i >= this.dataLength) { - this.i = 0; - return false; - } - - this.queue.next = setTimeout(() => this.queueNext(),data.wait); - } - + // Interrupt timeout and put monkey to sleep interrupt() { clearTimeout(this.queue.task); clearTimeout(this.queue.next); this.queue.task = null; this.queue.next = null; + this.flags.playing = 0; + } + + play() { + if(this.flags.playing) { + if(this.flags.stacking) { + this.flags.loop++; + } + return; + } + this.queueNext(); + } + + // Schedule task for execution by index + queueNext() { + this.flags.playing = 1; + const data = this.data[this.i]; + + // Schedule the current task to run after the specified wait time + this.queue.task = setTimeout(() => this.run(data.do),data.wait); + + // We're out of tasks to schedule.. + if(this.i >= this.dataLength) { + this.i = -1; + // Exit if we're out of loops + if(this.flags.loop === 0) { + this.flags.playing = 0; + return false; + } + + if(this.flags.loop <= -1) { + 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); } } -// Global event handler for this worker +// Global message event handler for this worker onmessage = (message) => { - const type = message.data[0] ? message.data[0] : null; + const type = message.data[0] ? message.data[0] : message.data; const data = message.data[1]; switch(type) { + // Attempt to load manfiest provided by initiator thread case "GIVE_MANIFEST": try { this.monkey = new Monkey(data); @@ -55,8 +89,24 @@ onmessage = (message) => { } break; - case "PLAYING": - this.monkey.queueNext(); + // 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; + + case "GET_FLAG": + const flag = this.monkey.flags[data]; + postMessage(parseInt(flag)); + break; + + case "SET_FLAG": + console.log(data); + this.monkey.flags[data[0]] = data[1]; break; default: return; // No op diff --git a/worker/TaskManager.mjs b/worker/TaskManager.mjs index c126685..5593323 100644 --- a/worker/TaskManager.mjs +++ b/worker/TaskManager.mjs @@ -11,13 +11,23 @@ export default class TaskManager { this.worker = new Worker(location + "Monkey.js"); } - play() { - this.worker.postMessage(["PLAYING",true]); - this.worker.addEventListener("message",message => eval(message.data)); + // 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; } - pause() { - this.worker.postMessage(["PLAYING",false]); + // 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