@remix_labs/machine-starter 1.1767.0-dev → 1.1772.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 = "1767";
1
+ var GROOVEBOX_BUILD = "1772";
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,23 +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,
116
+ "interceptFFI": config.interceptFFI,
117
+ "interceptDynloadFFI": config.interceptDynloadFFI,
81
118
  };
82
119
  worker.postMessage(config_msg, [ channel.port ]);
83
- terminate(() => worker.terminate());
84
- globalThis.MixSetMask = (m => {
85
- worker.postMessage({ "_rmx_type": "msg_vm_logMask",
86
- "mask": m
87
- })
88
- });
89
120
  if (config.localFFIs)
90
- setupLocalFFIs(hub, config); // don't await!
121
+ setupLocalFFIs(hub, config, localFFIfuns); // don't await!
91
122
  return worker;
92
123
  })
93
124
  }
94
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
+
95
151
  class Token {
96
152
  constructor(data, enabled, extras) {
97
153
  // data: must be an Uint8Array
@@ -207,13 +263,13 @@ function decode(val) {
207
263
  }
208
264
  }
209
265
 
210
- async function setupLocalFFIs(hub, config) {
266
+ async function setupLocalFFIs(hub, config, localFFIs) {
267
+ let vmID = config.vmID;
211
268
  let channel = await hub.newChannel();
212
- let comm = new FFIComm(hub, channel);
213
- let localFFIs = config.localFFIs;
214
- await channel.setLocalSubTopic("/local/ffi/call");
215
- await channel.setLocalPubTopic("/local/ffi/return");
216
- 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");
217
273
  while (true) {
218
274
  let msg = await sub.next();
219
275
  let name = msg.payload.name;
@@ -227,14 +283,15 @@ async function setupLocalFFIs(hub, config) {
227
283
  { call_id: call_id,
228
284
  hub: hub,
229
285
  channel: channel,
286
+ config: config,
230
287
  state: config.state,
231
288
  };
232
289
  let r = fun instanceof Function ? fun(connector, args) : fun.run(connector, args);
233
290
  if (r instanceof Promise) {
291
+ r.catch(_ => null); // prevent "unhandled rejection"
234
292
  await comm.later(call_id);
235
- r.then(
236
- (value) => comm.returnOrFail(fun, call_id, value),
237
- (reason) => comm.error(call_id, reason.message, reason.stack));
293
+ let value = await r;
294
+ await comm.returnOrFail(fun, call_id, value);
238
295
  } else {
239
296
  await comm.returnOrFail(fun, call_id, r);
240
297
  }
@@ -245,7 +302,8 @@ async function setupLocalFFIs(hub, config) {
245
302
  }
246
303
 
247
304
  class FFIComm {
248
- constructor(hub, channel) {
305
+ constructor(vmID, hub, channel) {
306
+ this.vmID = vmID;
249
307
  this.hub = hub;
250
308
  this.channel = channel;
251
309
  }
@@ -254,7 +312,7 @@ class FFIComm {
254
312
  { call_id: call_id,
255
313
  };
256
314
  let response = this.hub.newLocalMessage("msg_ffi_later", "starter", r_payload);
257
- return this.channel.publish("/local/ffi/return", response, false);
315
+ return this.channel.publish("/local/" + this.vmID + "/ffi/return", response, false);
258
316
  }
259
317
  return_(fun, call_id, result) {
260
318
  let r_payload =
@@ -262,7 +320,7 @@ class FFIComm {
262
320
  value: fun.useJsonDecoder ? result : encode(result)
263
321
  };
264
322
  let response = this.hub.newLocalMessage("msg_ffi_return", "starter", r_payload);
265
- return this.channel.publish("/local/ffi/return", response, false);
323
+ return this.channel.publish("/local/" + this.vmID + "/ffi/return", response, false);
266
324
  }
267
325
  error(call_id, message, stack) {
268
326
  let r_payload =
@@ -271,7 +329,7 @@ class FFIComm {
271
329
  stack: stack === undefined ? [] : stack,
272
330
  };
273
331
  let response = this.hub.newLocalMessage("msg_ffi_error", "starter", r_payload);
274
- this.channel.publish("/local/ffi/return", response, false);
332
+ this.channel.publish("/local/" + this.vmID + "/ffi/return", response, false);
275
333
  }
276
334
  returnOrFail(fun, call_id, result) {
277
335
  if (fun.canFail) {
@@ -302,5 +360,6 @@ class FFIComm {
302
360
  // use worker.terminate() to shut a worker down!
303
361
 
304
362
  export { CreateVMID, StartWASM, StartWASM2,
363
+ terminateAll, terminateVM,
305
364
  Token, Case, Opaque
306
365
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@remix_labs/machine-starter",
3
- "version": "1.1767.0-dev",
3
+ "version": "1.1772.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.1767.0-dev",
14
+ "@remix_labs/hub-client": "1.1772.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: