@remix_labs/machine-starter 2.12820.0-dev → 2.12824.0-dev
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/common.js +9 -151
- package/groovebox_build.js +1 -1
- package/package.json +2 -2
package/common.js
CHANGED
|
@@ -8,32 +8,10 @@ let last_hub = null;
|
|
|
8
8
|
|
|
9
9
|
let workers = {};
|
|
10
10
|
let worker_topics = {};
|
|
11
|
-
// hub channel handed to each VM worker; the hub's end must be released when the worker dies
|
|
12
|
-
let worker_chans = {};
|
|
13
11
|
let children = {};
|
|
14
12
|
let ffiLoops = {};
|
|
15
13
|
let blobs = {};
|
|
16
14
|
let blobsLoops = {};
|
|
17
|
-
// vmID -> { cancelled } for a StartWASM2 that has not finished setting itself
|
|
18
|
-
// up. terminateVM marks it cancelled so the start can unwind instead of
|
|
19
|
-
// registering loops for a VM that was already stopped.
|
|
20
|
-
let starting = {};
|
|
21
|
-
|
|
22
|
-
// Diagnostics for slowdowns and "the ID is used" errors. Call
|
|
23
|
-
// globalThis.__rmxMachineDiag() in the console: every map below should be empty
|
|
24
|
-
// when no VM is running. A non-empty ffiLoops/blobsLoops/worker_topics entry
|
|
25
|
-
// without a worker is a leak.
|
|
26
|
-
const diag = { started: 0, terminated: 0, cancelledStarts: 0, terminateWhileStarting: 0, loopsClosed: 0, killPublishFailed: 0 };
|
|
27
|
-
globalThis.__rmxMachineDiag = () => ({
|
|
28
|
-
...diag,
|
|
29
|
-
workers: Object.keys(workers),
|
|
30
|
-
worker_topics: Object.keys(worker_topics),
|
|
31
|
-
ffiLoops: Object.keys(ffiLoops),
|
|
32
|
-
blobsLoops: Object.keys(blobsLoops),
|
|
33
|
-
children: Object.keys(children),
|
|
34
|
-
blobs: Object.keys(blobs),
|
|
35
|
-
starting: Object.keys(starting),
|
|
36
|
-
});
|
|
37
15
|
|
|
38
16
|
function terminateAll() {
|
|
39
17
|
console.log("[machine-starter] terminate all VMs");
|
|
@@ -62,19 +40,6 @@ function terminateAll() {
|
|
|
62
40
|
function terminateVM(vmID) {
|
|
63
41
|
console.log("[machine-starter] terminate VM", vmID);
|
|
64
42
|
let worker = workers[vmID];
|
|
65
|
-
if (starting[vmID]) {
|
|
66
|
-
// Stopped while StartWASM2 was still awaiting (fetching/compiling mixrt,
|
|
67
|
-
// creating the starter mixcore). Tell it to unwind; it removes what it
|
|
68
|
-
// registered. Without this it registered ffiLoops[vmID] after this
|
|
69
|
-
// call and every later start of the same vmID failed with
|
|
70
|
-
// "Cannot start VM, the ID is used".
|
|
71
|
-
starting[vmID].cancelled = true;
|
|
72
|
-
// free the id now: a start that follows this stop must not see the cancelled one
|
|
73
|
-
// (the cancelled start still holds its token and unwinds itself)
|
|
74
|
-
delete starting[vmID];
|
|
75
|
-
diag.terminateWhileStarting++;
|
|
76
|
-
console.warn("[machine-starter] terminate VM while it is still starting", vmID);
|
|
77
|
-
}
|
|
78
43
|
if (worker) {
|
|
79
44
|
let vmChildren = children[vmID];
|
|
80
45
|
let blobList = blobs[vmID] || [];
|
|
@@ -83,12 +48,8 @@ function terminateVM(vmID) {
|
|
|
83
48
|
delete children[vmID];
|
|
84
49
|
delete ffiLoops[vmID];
|
|
85
50
|
delete blobsLoops[vmID];
|
|
86
|
-
delete blobs[vmID];
|
|
87
51
|
killVM(vmID);
|
|
88
|
-
|
|
89
|
-
if (ffiLoop) {
|
|
90
|
-
ffiLoop.terminate();
|
|
91
|
-
}
|
|
52
|
+
ffiLoop.terminate();
|
|
92
53
|
if (blobsLoop) {
|
|
93
54
|
blobsLoop.terminate();
|
|
94
55
|
}
|
|
@@ -111,39 +72,15 @@ function killVM(vmID) {
|
|
|
111
72
|
delete worker_topics[vmID];
|
|
112
73
|
if (topic && last_hub) {
|
|
113
74
|
let payload = { _rmx_type:"msg_vm_register", id: vmID, alive: false };
|
|
114
|
-
// The worker must be terminated even when the unannounce cannot be published:
|
|
115
|
-
// a chain of .then() skipped worker.terminate() on any failure, leaking a Web Worker
|
|
116
|
-
// (with its wasm instance) for every VM stopped that way.
|
|
117
75
|
last_hub.newChannel().then(channel => {
|
|
118
76
|
let msg = channel.newJSONMessage("msg_vm_register", "vm", payload);
|
|
119
|
-
|
|
120
|
-
}).
|
|
121
|
-
diag.killPublishFailed++;
|
|
122
|
-
console.warn("[machine-starter] could not announce VM stop", vmID, e);
|
|
123
|
-
}).finally(() => { worker.terminate(); releaseWorkerChannel(last_hub, vmID); });
|
|
77
|
+
channel.publish(topic + "/announce", msg, true)
|
|
78
|
+
}).then(_ => worker.terminate())
|
|
124
79
|
} else {
|
|
125
|
-
worker.terminate()
|
|
126
|
-
releaseWorkerChannel(last_hub, vmID);
|
|
80
|
+
worker.terminate()
|
|
127
81
|
}
|
|
128
82
|
}
|
|
129
83
|
|
|
130
|
-
// A hub channel has no explicit close: drop its MessagePort so the hub worker can release it.
|
|
131
|
-
function closeChannel(channel) {
|
|
132
|
-
try {
|
|
133
|
-
if (typeof channel.close === "function") channel.close();
|
|
134
|
-
else channel.port && channel.port.close && channel.port.close();
|
|
135
|
-
// a message sent just before close() may not arrive: ask via the hub itself as well
|
|
136
|
-
if (last_hub && last_hub.closeChannelById) last_hub.closeChannelById(channel.chanId);
|
|
137
|
-
} catch (_) {}
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
// The channel given to a VM worker was transferred, so only the hub can release its end.
|
|
141
|
-
function releaseWorkerChannel(hub, vmID) {
|
|
142
|
-
let chanId = worker_chans[vmID];
|
|
143
|
-
delete worker_chans[vmID];
|
|
144
|
-
try { if (hub && hub.closeChannelById) hub.closeChannelById(chanId); } catch (_) {}
|
|
145
|
-
}
|
|
146
|
-
|
|
147
84
|
if (globalThis.Process) {
|
|
148
85
|
Process.on("exit", () => {
|
|
149
86
|
terminateAll()
|
|
@@ -196,60 +133,12 @@ async function StartWASM2(hub, config, getWorker) {
|
|
|
196
133
|
console.log("[machine-starter] Call MixExplain() for explaining debug levels, and MixSetMask(m) for changing these")
|
|
197
134
|
};
|
|
198
135
|
last_hub = hub;
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
// Registered before the first await: a terminateVM that arrives while the channel and worker
|
|
204
|
-
// are still being created finds the token and cancels this start. Without it that stop was a
|
|
205
|
-
// no-op, the VM registered and ran with no owner, and every later start failed with
|
|
206
|
-
// "Cannot start VM, the ID is used".
|
|
207
|
-
const startToken = { cancelled: false };
|
|
208
|
-
starting[config.vmID] = startToken;
|
|
209
|
-
let channel;
|
|
210
|
-
let worker;
|
|
211
|
-
try {
|
|
212
|
-
channel = await hub.newChannel();
|
|
213
|
-
// injected by either index.js or node.js
|
|
214
|
-
worker = await getWorker();
|
|
215
|
-
} catch (e) {
|
|
216
|
-
if (starting[config.vmID] === startToken) delete starting[config.vmID];
|
|
217
|
-
if (channel) closeChannel(channel);
|
|
218
|
-
throw e;
|
|
219
|
-
}
|
|
220
|
-
if (startToken.cancelled) {
|
|
221
|
-
diag.cancelledStarts++;
|
|
222
|
-
console.warn("[machine-starter] start cancelled before the VM was registered", config.vmID);
|
|
223
|
-
if (starting[config.vmID] === startToken) delete starting[config.vmID];
|
|
224
|
-
closeChannel(channel);
|
|
225
|
-
try { worker.terminate(); } catch (_) {}
|
|
226
|
-
return worker;
|
|
227
|
-
}
|
|
228
|
-
if (workers[config.vmID] || ffiLoops[config.vmID]) {
|
|
229
|
-
if (starting[config.vmID] === startToken) delete starting[config.vmID];
|
|
230
|
-
closeChannel(channel);
|
|
136
|
+
let channel = await hub.newChannel();
|
|
137
|
+
// injected by either index.js or node.js
|
|
138
|
+
let worker = await getWorker();
|
|
139
|
+
if (workers[config.vmID] || ffiLoops[config.vmID])
|
|
231
140
|
throw new Error("Cannot start VM, the ID is used: " + config.vmID);
|
|
232
|
-
}
|
|
233
141
|
workers[config.vmID] = worker;
|
|
234
|
-
worker_chans[config.vmID] = channel.chanId;
|
|
235
|
-
diag.started++;
|
|
236
|
-
// Called after every await below: if terminateVM ran meanwhile, undo and stop.
|
|
237
|
-
const abortIfCancelled = () => {
|
|
238
|
-
if (!startToken.cancelled) return false;
|
|
239
|
-
diag.cancelledStarts++;
|
|
240
|
-
console.warn("[machine-starter] start cancelled, VM was terminated while starting", config.vmID);
|
|
241
|
-
if (starting[config.vmID] === startToken) delete starting[config.vmID];
|
|
242
|
-
// only undo what this start registered: a newer start of the same id may own the maps now
|
|
243
|
-
if (workers[config.vmID] === worker) {
|
|
244
|
-
delete ffiLoops[config.vmID];
|
|
245
|
-
delete blobsLoops[config.vmID];
|
|
246
|
-
delete worker_topics[config.vmID];
|
|
247
|
-
delete workers[config.vmID];
|
|
248
|
-
releaseWorkerChannel(hub, config.vmID);
|
|
249
|
-
}
|
|
250
|
-
try { worker.terminate(); } catch (_) {}
|
|
251
|
-
return true;
|
|
252
|
-
};
|
|
253
142
|
if (config.topicPrefix != undefined && config.topicPrefix != "") {
|
|
254
143
|
worker_topics[config.vmID] = config.topicPrefix + "/vm/" + config.vmID;
|
|
255
144
|
} else {
|
|
@@ -259,11 +148,9 @@ async function StartWASM2(hub, config, getWorker) {
|
|
|
259
148
|
// from now on, the "local" FFIs are called "starter" FFIs, because this
|
|
260
149
|
// distinguishes these from other locally defined FFIs
|
|
261
150
|
let mixcore = await createStarterMixcore(config.mixcore);
|
|
262
|
-
if (abortIfCancelled()) return worker;
|
|
263
151
|
if (mixcore) {
|
|
264
152
|
// merge the ffis and store them back into the config so sub vms also get them
|
|
265
153
|
config.localFFIs = Object.assign(starterFFIs, await mixcoreStarterFFIs(mixcore));
|
|
266
|
-
if (abortIfCancelled()) return worker;
|
|
267
154
|
// delete the mixcore config to avoid being handled further by the worker
|
|
268
155
|
delete config.mixcore;
|
|
269
156
|
}
|
|
@@ -297,9 +184,7 @@ async function StartWASM2(hub, config, getWorker) {
|
|
|
297
184
|
globalThis.mixrtCodeURL = url;
|
|
298
185
|
globalThis.mixrtCodeModule = mixrtCode;
|
|
299
186
|
}
|
|
300
|
-
if (abortIfCancelled()) return worker;
|
|
301
187
|
};
|
|
302
|
-
if (abortIfCancelled()) return worker;
|
|
303
188
|
ffiLoops[config.vmID] = setupStarterFFIs(hub, config, starterFFIfuns);
|
|
304
189
|
blobsLoops[config.vmID] = setupBlobs(hub, config);
|
|
305
190
|
let config_msg =
|
|
@@ -325,7 +210,6 @@ async function StartWASM2(hub, config, getWorker) {
|
|
|
325
210
|
// (http, https, data)
|
|
326
211
|
};
|
|
327
212
|
worker.postMessage(config_msg, [ channel.port ]);
|
|
328
|
-
if (starting[config.vmID] === startToken) delete starting[config.vmID];
|
|
329
213
|
return worker;
|
|
330
214
|
}
|
|
331
215
|
|
|
@@ -350,7 +234,6 @@ async function ffi_vm_start(conn, args, getWorker) {
|
|
|
350
234
|
let vmChildren = children[conn.config.vmID];
|
|
351
235
|
if (!vmChildren) vmChildren = [];
|
|
352
236
|
vmChildren.push(vm_id);
|
|
353
|
-
children[conn.config.vmID] = vmChildren; // was never stored: embedded VMs were not stopped with their parent
|
|
354
237
|
let arg_config = args[0];
|
|
355
238
|
if (arg_config.interceptFFI !== undefined)
|
|
356
239
|
config["interceptFFI"] = arg_config.interceptFFI;
|
|
@@ -364,10 +247,6 @@ async function ffi_vm_stop(conn, args) {
|
|
|
364
247
|
let vm_id = args[0];
|
|
365
248
|
let worker = workers[vm_id];
|
|
366
249
|
if (!worker) throw new Error("no such VM: " + vm_id);
|
|
367
|
-
for (let parent of Object.keys(children)) {
|
|
368
|
-
let i = children[parent].indexOf(vm_id);
|
|
369
|
-
if (i >= 0) children[parent].splice(i, 1);
|
|
370
|
-
}
|
|
371
250
|
terminateVM(vm_id);
|
|
372
251
|
return null;
|
|
373
252
|
}
|
|
@@ -510,11 +389,6 @@ async function starterFFIsMessageLoop(hub, config, starterFFIs, terminate) {
|
|
|
510
389
|
]);
|
|
511
390
|
if (terminated) {
|
|
512
391
|
// console.log("[machine-starter] terminate FFI loop", vmID);
|
|
513
|
-
// Release the hub subscription and channel; without this each VM (one per build in the
|
|
514
|
-
// builder) left both behind for the lifetime of the page.
|
|
515
|
-
await sub.unsubscribe().catch(() => {});
|
|
516
|
-
closeChannel(channel);
|
|
517
|
-
diag.loopsClosed++;
|
|
518
392
|
return;
|
|
519
393
|
}
|
|
520
394
|
let name = msg.payload.name;
|
|
@@ -575,9 +449,6 @@ async function blobsMessageLoop(hub, config, terminate) {
|
|
|
575
449
|
]);
|
|
576
450
|
if (terminated) {
|
|
577
451
|
// console.log("[machine-starter] terminate blobs loop", vmID);
|
|
578
|
-
await sub.unsubscribe().catch(() => {});
|
|
579
|
-
closeChannel(channel);
|
|
580
|
-
diag.loopsClosed++;
|
|
581
452
|
return;
|
|
582
453
|
}
|
|
583
454
|
let name = msg.payload.name;
|
|
@@ -645,20 +516,7 @@ class FFIComm {
|
|
|
645
516
|
}
|
|
646
517
|
}
|
|
647
518
|
|
|
648
|
-
// Stops every VM that `parentVmID` started (through $vm_start) and has not stopped itself, including
|
|
649
|
-
// ones that are still starting. Returns how many were stopped. A parent that outlives its children
|
|
650
|
-
// (the L2 session agent starts one embedded VM per session) can leave one running when its owner
|
|
651
|
-
// goes away before the session finished starting; the caller decides when that has happened.
|
|
652
|
-
function terminateChildren(parentVmID) {
|
|
653
|
-
let list = children[parentVmID];
|
|
654
|
-
if (!list || list.length === 0) return 0;
|
|
655
|
-
let ids = list.slice();
|
|
656
|
-
children[parentVmID] = [];
|
|
657
|
-
for (let id of ids) terminateVM(id);
|
|
658
|
-
return ids.length;
|
|
659
|
-
}
|
|
660
|
-
|
|
661
519
|
// use terminateVM to shut a worker down!
|
|
662
|
-
export { StartWASM, StartWASM2, terminateAll, terminateVM,
|
|
520
|
+
export { StartWASM, StartWASM2, terminateAll, terminateVM,
|
|
663
521
|
Token, Case, Opaque
|
|
664
522
|
}
|
package/groovebox_build.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
var GROOVEBOX_BUILD = "
|
|
1
|
+
var GROOVEBOX_BUILD = "12824";
|
|
2
2
|
export { GROOVEBOX_BUILD }
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@remix_labs/machine-starter",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.12824.0-dev",
|
|
4
4
|
"description": "start the groove",
|
|
5
5
|
"main": "node.js",
|
|
6
6
|
"browser": "index.js",
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
"author": "Remixlabs staff",
|
|
12
12
|
"license": "ISC",
|
|
13
13
|
"dependencies": {
|
|
14
|
-
"@remix_labs/hub-client": "2.
|
|
14
|
+
"@remix_labs/hub-client": "2.12824.0-dev",
|
|
15
15
|
"nanoid": "^5.0.2",
|
|
16
16
|
"web-worker": "^1.2.0"
|
|
17
17
|
},
|