mirror of
https://codeberg.org/vlw/monkeydo.git
synced 2025-09-13 23:53:41 +02:00
dev21w45a
This commit is contained in:
parent
ff0ed25a3b
commit
86ea8cd031
3 changed files with 129 additions and 26 deletions
26
Monkeydo.mjs
26
Monkeydo.mjs
|
@ -10,16 +10,32 @@ export default class Monkeydo extends MonkeyMaster {
|
||||||
Object.assign(this.methods,methods);
|
Object.assign(this.methods,methods);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Execute a task
|
||||||
do(task) {
|
do(task) {
|
||||||
console.log("TASK",task);
|
if(!task[1] in this.methods) return;
|
||||||
|
const args = task.splice(0,2);
|
||||||
|
this.methods[task[1]](...args);
|
||||||
}
|
}
|
||||||
|
|
||||||
async loop(times = null) {
|
async debug(state = true) {
|
||||||
times = times < 0 ? null : times;
|
return await this.setFlag("debug",state);
|
||||||
return await this.setFlag("loop",times);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Loop playback X times or negative number for infinite
|
||||||
|
async loop(times = 255) {
|
||||||
|
if(typeof times !== "number") {
|
||||||
|
times = parseInt(times);
|
||||||
|
}
|
||||||
|
// Clamp number to 8 bit max
|
||||||
|
times = Math.min(Math.max(times,0),255);
|
||||||
|
return await this.setFlag("playing",times);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Load Monkeydo manifest
|
||||||
async load(manifest) {
|
async load(manifest) {
|
||||||
|
if(typeof manifest === "object") {
|
||||||
|
manifest = JSON.stringify(manifest);
|
||||||
|
}
|
||||||
|
return await this.loadManifest(manifest);
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -4,10 +4,44 @@ importScripts("https://unpkg.com/comlink/dist/umd/comlink.js");
|
||||||
|
|
||||||
class Monkey {
|
class Monkey {
|
||||||
constructor() {
|
constructor() {
|
||||||
this.manifest = {};
|
|
||||||
|
|
||||||
// Runtime flags
|
|
||||||
this.flags = new Uint8ClampedArray(2);
|
this.flags = new Uint8ClampedArray(2);
|
||||||
|
this.tasks = [];
|
||||||
|
// Runtime task queue
|
||||||
|
this.queue = {
|
||||||
|
thisTask: null,
|
||||||
|
nextTask: null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Task scheduler
|
||||||
|
next() {
|
||||||
|
if(this.flags[0] === 0) return;
|
||||||
|
const task = this.tasks[this.i];
|
||||||
|
|
||||||
|
// Run task after delay
|
||||||
|
this.queue.thisTask = setTimeout(() => {
|
||||||
|
// Dispatch task to main thread
|
||||||
|
this.postMessage(["TASK",task]);
|
||||||
|
this.i++;
|
||||||
|
},task[0]);
|
||||||
|
|
||||||
|
// Loop until flag is 0 or infinite if 255
|
||||||
|
if(this.i === this.tasks.length) {
|
||||||
|
this.i = 0;
|
||||||
|
if(flags[1] === 255) return;
|
||||||
|
flags[1]--;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Queue the next task
|
||||||
|
this.queue.nextTask = setTimeout(() => this.next(),task[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
abort() {
|
||||||
|
clearTimeout(this.queue.thisTask);
|
||||||
|
clearTimeout(this.queue.nextTask);
|
||||||
|
this.queue.thisTask = null;
|
||||||
|
this.queue.nextTask = null;
|
||||||
|
this.flags[1] = 0; // Playing: false
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set or get a runtime flag
|
// Set or get a runtime flag
|
||||||
|
@ -15,15 +49,28 @@ class Monkey {
|
||||||
return value ? this.flags[index] = value : this.flags[index];
|
return value ? this.flags[index] = value : this.flags[index];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Fetch and install manifest from URL
|
||||||
|
async fetchManifest(url) {
|
||||||
|
const manifest = await fetch(url);
|
||||||
|
const json = await manifest.json();
|
||||||
|
return await this.loadManifest(json);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Install a Monkeydo manifest
|
||||||
async loadManifest(manifest) {
|
async loadManifest(manifest) {
|
||||||
try {
|
return await new Promise((resolve,reject) => {
|
||||||
const data = JSON.parse(manifest);
|
if(typeof manifest !== "object") {
|
||||||
this.manifest = data;
|
try {
|
||||||
this.flags[0] = 1;
|
manifest = JSON.parse(manifest);
|
||||||
}
|
}
|
||||||
catch {
|
catch {
|
||||||
const url = new URL(manifest);
|
reject("Failed to load manifest");
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
this.tasks = manifest.tasks;
|
||||||
|
this.flags[0] = 1; // Manifest loaded: true
|
||||||
|
resolve();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -7,8 +7,21 @@ export default class MonkeyMaster {
|
||||||
this.comlink = null;
|
this.comlink = null;
|
||||||
|
|
||||||
this.ready = false;
|
this.ready = false;
|
||||||
this.flagQueue = [];
|
// Tasks will be queued here on runtime if the worker isn't ready
|
||||||
this.init();
|
this.queue = {
|
||||||
|
_flags: [],
|
||||||
|
set flag(flag) {
|
||||||
|
this._flags.push(flag);
|
||||||
|
},
|
||||||
|
// Attempt to send all queued flags
|
||||||
|
sendAllFlags: () => {
|
||||||
|
// Copy flags and clear queue
|
||||||
|
const flags = [...this.queue._flags];
|
||||||
|
this.queue._flags = [];
|
||||||
|
|
||||||
|
flags.forEach(flag => this.setFlag(flag));
|
||||||
|
}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
// Import worker relative to this module
|
// Import worker relative to this module
|
||||||
|
@ -16,6 +29,7 @@ export default class MonkeyMaster {
|
||||||
const name = "Monkey.js";
|
const name = "Monkey.js";
|
||||||
const url = new URL(import.meta.url);
|
const url = new URL(import.meta.url);
|
||||||
|
|
||||||
|
// Replace pathname of this file with worker
|
||||||
const path = url.pathname.split("/");
|
const path = url.pathname.split("/");
|
||||||
path[path.length - 1] = name;
|
path[path.length - 1] = name;
|
||||||
|
|
||||||
|
@ -27,24 +41,31 @@ export default class MonkeyMaster {
|
||||||
// Spawn and wrap dedicated worker with Comlink
|
// Spawn and wrap dedicated worker with Comlink
|
||||||
const worker = new Worker(this.getWorkerPath());
|
const worker = new Worker(this.getWorkerPath());
|
||||||
const Monkey = Comlink.wrap(worker);
|
const Monkey = Comlink.wrap(worker);
|
||||||
|
|
||||||
this.comlink = await new Monkey();
|
this.comlink = await new Monkey();
|
||||||
|
|
||||||
|
// Wait for comlink to initialize proxy and send queued flags
|
||||||
|
return await new Promise((resolve,reject) => {
|
||||||
|
if(!this.comlink) reject("Failed to open proxy to worker");
|
||||||
|
|
||||||
|
this.ready = true;
|
||||||
|
this.queue.sendAllFlags();
|
||||||
|
resolve();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return a flag array index by name
|
// Return a flag array index by name
|
||||||
flagStringToIndex(flag) {
|
flagStringToIndex(flag) {
|
||||||
const flags = [
|
const flags = [
|
||||||
"MANIFEST_LOADED",
|
"MANIFEST_LOADED",
|
||||||
"PLAYING",
|
"PLAYING"
|
||||||
"LOOP"
|
|
||||||
];
|
];
|
||||||
|
|
||||||
// Translate string to index
|
// Translate string to index
|
||||||
if(typeof flag === "string" || flag < 0) {
|
if(typeof flag === "string" || flag < 0) {
|
||||||
const key = flags.indexOf(flag.toUpperCase());
|
const key = flags.indexOf(flag.toUpperCase());
|
||||||
if(key < 0) {
|
if(key < 0) return;
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check key is in bounds
|
// Check key is in bounds
|
||||||
if(flag < 0 || flags > flags.length - 1) {
|
if(flag < 0 || flags > flags.length - 1) {
|
||||||
throw new Error(`Array key '${flag}' out of range`);
|
throw new Error(`Array key '${flag}' out of range`);
|
||||||
|
@ -57,11 +78,30 @@ export default class MonkeyMaster {
|
||||||
return await this.comlink.flag(key);
|
return await this.comlink.flag(key);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Set or queue worker runtime flag
|
||||||
async setFlag(flag,value) {
|
async setFlag(flag,value) {
|
||||||
const key = this.flagStringToIndex(flag);
|
const key = this.flagStringToIndex(flag);
|
||||||
const update = await this.comlink.flag(0,12);
|
if(!this.ready) {
|
||||||
|
this.queue.flag = [key,value];
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Tell worker to update flag by key
|
||||||
|
const update = await this.comlink.flag(key,value);
|
||||||
if(!update) {
|
if(!update) {
|
||||||
this.flagQueue.push([key,value]);
|
this.queue.flag = [key,value];
|
||||||
|
}
|
||||||
|
return update;
|
||||||
|
}
|
||||||
|
|
||||||
|
async loadManifest(manifest) {
|
||||||
|
if(!this.ready) await this.init();
|
||||||
|
try {
|
||||||
|
const url = new URL(manifest);
|
||||||
|
this.comlink.fetchManifest(url.toString());
|
||||||
|
}
|
||||||
|
catch {
|
||||||
|
this.comlink.loadManifest(manifest);
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue