@remix_labs/machine-starter 1.1865.0 → 1.1868.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.
@@ -1,2 +1,2 @@
1
- var GROOVEBOX_BUILD = "1865";
1
+ var GROOVEBOX_BUILD = "1868";
2
2
  export { GROOVEBOX_BUILD }
package/index.js CHANGED
@@ -1,14 +1,34 @@
1
1
  import { nanoid } from "nanoid";
2
2
  import { GROOVEBOX_BUILD } from "./groovebox_build.js";
3
3
 
4
- let terminate = function(f) {};
5
- if (globalThis.ThisIsNode) {
6
- terminate = function(f) {
7
- Process.on("exit", () => {
8
- console.log("terminating machine worker");
9
- f()
10
- })
4
+ let workers = {};
5
+ let parents = {};
6
+
7
+ function terminateAll() {
8
+ for (let [vmID, worker] of Object.entries(workers)) {
9
+ worker.terminate();
10
+ };
11
+ workers = {};
12
+ parents = {};
13
+ }
14
+
15
+ function terminateVM(vmID) {
16
+ let worker = workers[vmID];
17
+ if (worker) {
18
+ delete workers[vmID];
19
+ delete parents[vmID];
20
+ worker.terminate();
21
+ for (let [subID, parentID] of Object.entries(parents)) {
22
+ terminateVM(subID);
23
+ };
11
24
  }
25
+ }
26
+
27
+ if (globalThis.ThisIsNode) {
28
+ Process.on("exit", () => {
29
+ console.log("terminating machine workers");
30
+ terminateAll()
31
+ })
12
32
  };
13
33
 
14
34
  function CreateVMID() {
@@ -16,8 +36,14 @@ function CreateVMID() {
16
36
  }
17
37
 
18
38
  let initialMask = 64 + 1024; // default for web
39
+
19
40
  globalThis.MixSetMask = (m => {
20
41
  initialMask = m;
42
+ for (let [vmID, worker] of Object.entries(workers)) {
43
+ worker.postMessage({ "_rmx_type": "msg_vm_logMask",
44
+ "mask": m
45
+ })
46
+ }
21
47
  });
22
48
 
23
49
  function StartWASM(hub, baseURL, org, workspace, vmID, user, token, noOutputViaMQTT) {
@@ -51,20 +77,29 @@ function StartWASM2(hub, config) {
51
77
  fetch(code_url, {cache:"default"}).then(resp => { return resp.arrayBuffer() });
52
78
  bundle = new URL("/g/machine-wasm-core.js", window.location.href);
53
79
  }
54
- let localFFIs = {};
80
+ let localFFIkind = {};
81
+ let localFFIfuns = {};
55
82
  if (config.localFFIs) {
56
83
  for (const [k, v] of Object.entries(config.localFFIs)) {
84
+ localFFIfuns[k] = {...v};
57
85
  if (v.isRaw && (v.canFail || v.useJsonDecoder)) {
58
86
  console.error("A raw, local FFI must neither be failing nor use the JSON decoder: " + k);
59
87
  } else {
60
- localFFIs[k] = {...v};
61
- delete localFFIs[k].run;
88
+ localFFIkind[k] = {...v};
89
+ delete localFFIkind[k].run;
62
90
  }
63
- }
91
+ };
92
+ let vm_kind = { isRaw:false, canFail:false, useJsonDecoder:false};
93
+ localFFIkind["$vm_start"] = vm_kind;
94
+ localFFIfuns["$vm_start"] = ffi_vm_start;
95
+ localFFIkind["$vm_stop"] = vm_kind;
96
+ localFFIfuns["$vm_stop"] = ffi_vm_stop;
64
97
  }
65
98
  let worker = new Worker(bundle);
99
+ workers[config.vmID] = worker;
66
100
  let config_msg =
67
101
  { "_rmx_type": "msg_vm_configure",
102
+ "workerURL": bundle.toString(),
68
103
  "baseURL": config.baseURL,
69
104
  "org": config.org,
70
105
  "workspace": config.workspace,
@@ -75,25 +110,44 @@ function StartWASM2(hub, config) {
75
110
  "outputViaMQTT": !(config.noOutputViaMQTT),
76
111
  "machType": config.machType,
77
112
  "debugMask": initialMask,
78
- "localFFIs": localFFIs,
113
+ "localFFIs": localFFIkind,
79
114
  "grooveboxUrlPrefix": globalThis.GROOVEBOX_URL_PREFIX,
80
115
  "allowInsecureHttp": globalThis.GROOVEBOX_ALLOW_INSECURE_HTTP,
81
116
  "interceptFFI": config.interceptFFI,
82
117
  "interceptDynloadFFI": config.interceptDynloadFFI,
83
118
  };
84
119
  worker.postMessage(config_msg, [ channel.port ]);
85
- terminate(() => worker.terminate());
86
- globalThis.MixSetMask = (m => {
87
- worker.postMessage({ "_rmx_type": "msg_vm_logMask",
88
- "mask": m
89
- })
90
- });
91
120
  if (config.localFFIs)
92
- setupLocalFFIs(hub, config); // don't await!
121
+ setupLocalFFIs(hub, config, localFFIfuns); // don't await!
93
122
  return worker;
94
123
  })
95
124
  }
96
125
 
126
+ async function ffi_vm_start(conn, args) {
127
+ let vm_id = "embedded." + nanoid();
128
+ let config = {};
129
+ for (const [k, v] of Object.entries(conn.config)) {
130
+ config[k] = v;
131
+ }
132
+ config["vmID"] = vm_id;
133
+ parents[vm_id] = conn.config.vmID;
134
+ let arg_config = args[0];
135
+ if (arg_config.interceptFFI !== undefined)
136
+ config["interceptFFI"] = arg_config.interceptFFI;
137
+ if (arg_config.interceptDynloadFFI !== undefined)
138
+ config["interceptDynloadFFI"] = arg_config.interceptDynloadFFI;
139
+ let worker = await StartWASM2(conn.hub, config);
140
+ return vm_id;
141
+ }
142
+
143
+ async function ffi_vm_stop(conn, args) {
144
+ let vm_id = args[0];
145
+ let worker = workers[vm_id];
146
+ if (!worker) throw new Error("no such VM: " + vm_id);
147
+ terminateVM(vm_id);
148
+ return null;
149
+ }
150
+
97
151
  class Token {
98
152
  constructor(data, enabled, extras) {
99
153
  // data: must be an Uint8Array
@@ -209,13 +263,13 @@ function decode(val) {
209
263
  }
210
264
  }
211
265
 
212
- async function setupLocalFFIs(hub, config) {
266
+ async function setupLocalFFIs(hub, config, localFFIs) {
267
+ let vmID = config.vmID;
213
268
  let channel = await hub.newChannel();
214
- let comm = new FFIComm(hub, channel);
215
- let localFFIs = config.localFFIs;
216
- await channel.setLocalSubTopic("/local/ffi/call");
217
- await channel.setLocalPubTopic("/local/ffi/return");
218
- let sub = await channel.subscribe("/local/ffi/call");
269
+ let comm = new FFIComm(vmID, hub, channel);
270
+ await channel.setLocalSubTopic("/local/" + vmID);
271
+ await channel.setLocalPubTopic("/local/" + vmID);
272
+ let sub = await channel.subscribe("/local/" + vmID + "/ffi/call");
219
273
  while (true) {
220
274
  let msg = await sub.next();
221
275
  let name = msg.payload.name;
@@ -229,14 +283,15 @@ async function setupLocalFFIs(hub, config) {
229
283
  { call_id: call_id,
230
284
  hub: hub,
231
285
  channel: channel,
286
+ config: config,
232
287
  state: config.state,
233
288
  };
234
289
  let r = fun instanceof Function ? fun(connector, args) : fun.run(connector, args);
235
290
  if (r instanceof Promise) {
291
+ r.catch(_ => null); // prevent "unhandled rejection"
236
292
  await comm.later(call_id);
237
- r.then(
238
- (value) => comm.returnOrFail(fun, call_id, value),
239
- (reason) => comm.error(call_id, reason.message, reason.stack));
293
+ let value = await r;
294
+ await comm.returnOrFail(fun, call_id, value);
240
295
  } else {
241
296
  await comm.returnOrFail(fun, call_id, r);
242
297
  }
@@ -247,7 +302,8 @@ async function setupLocalFFIs(hub, config) {
247
302
  }
248
303
 
249
304
  class FFIComm {
250
- constructor(hub, channel) {
305
+ constructor(vmID, hub, channel) {
306
+ this.vmID = vmID;
251
307
  this.hub = hub;
252
308
  this.channel = channel;
253
309
  }
@@ -256,7 +312,7 @@ class FFIComm {
256
312
  { call_id: call_id,
257
313
  };
258
314
  let response = this.hub.newLocalMessage("msg_ffi_later", "starter", r_payload);
259
- return this.channel.publish("/local/ffi/return", response, false);
315
+ return this.channel.publish("/local/" + this.vmID + "/ffi/return", response, false);
260
316
  }
261
317
  return_(fun, call_id, result) {
262
318
  let r_payload =
@@ -264,7 +320,7 @@ class FFIComm {
264
320
  value: fun.useJsonDecoder ? result : encode(result)
265
321
  };
266
322
  let response = this.hub.newLocalMessage("msg_ffi_return", "starter", r_payload);
267
- return this.channel.publish("/local/ffi/return", response, false);
323
+ return this.channel.publish("/local/" + this.vmID + "/ffi/return", response, false);
268
324
  }
269
325
  error(call_id, message, stack) {
270
326
  let r_payload =
@@ -273,7 +329,7 @@ class FFIComm {
273
329
  stack: stack === undefined ? [] : stack,
274
330
  };
275
331
  let response = this.hub.newLocalMessage("msg_ffi_error", "starter", r_payload);
276
- this.channel.publish("/local/ffi/return", response, false);
332
+ this.channel.publish("/local/" + this.vmID + "/ffi/return", response, false);
277
333
  }
278
334
  returnOrFail(fun, call_id, result) {
279
335
  if (fun.canFail) {
@@ -304,5 +360,6 @@ class FFIComm {
304
360
  // use worker.terminate() to shut a worker down!
305
361
 
306
362
  export { CreateVMID, StartWASM, StartWASM2,
363
+ terminateAll, terminateVM,
307
364
  Token, Case, Opaque
308
365
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@remix_labs/machine-starter",
3
- "version": "1.1865.0",
3
+ "version": "1.1868.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": "1.1865.0",
14
+ "@remix_labs/hub-client": "1.1868.0-dev",
15
15
  "nanoid": "^3.1.12",
16
16
  "web-worker": "^1.2.0"
17
17
  },
package/start.js CHANGED
@@ -45,7 +45,8 @@ w.configure({wsURL: mqttURL, user:mqttUser, token:mqttToken}).then(resp => {
45
45
  user: mqttUser,
46
46
  token: mqttToken,
47
47
  noOutputViaMQTT: noOutputViaMQTT,
48
- machType: variant
48
+ machType: variant,
49
+ localFFIs: {},
49
50
  });
50
51
  break
51
52
  default: