@naanlang/naan 1.6.0 → 1.7.1

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.
Files changed (54) hide show
  1. package/LICENSE.md +1 -1
  2. package/README.md +1 -1
  3. package/bin/index.js +2 -2
  4. package/dist/env_web.js +3 -32
  5. package/dist/naan.min.js +10 -10
  6. package/frameworks/browser/sworker.js +23 -23
  7. package/frameworks/browser/terminals.nlg +161 -212
  8. package/frameworks/browser/worker.nlg +78 -30
  9. package/frameworks/browser/workers.nlg +1 -1
  10. package/frameworks/browser/ws_client.nlg +23 -87
  11. package/frameworks/client/apiclient.nlg +91 -58
  12. package/frameworks/client/client.nlg +22 -2
  13. package/frameworks/client/psm_client.nlg +10 -14
  14. package/frameworks/client/relaycon.nlg +1 -1
  15. package/frameworks/common/common.nlg +13 -9
  16. package/frameworks/node/apiserver.nlg +1 -2
  17. package/frameworks/node/node.nlg +1 -0
  18. package/frameworks/node/pty.nlg +21 -21
  19. package/frameworks/node/shell.nlg +26 -3
  20. package/frameworks/node/worker.nlg +166 -84
  21. package/frameworks/node/ws_client.nlg +25 -84
  22. package/frameworks/project/build.nlg +83 -32
  23. package/frameworks/project/projects.nlg +2 -2
  24. package/frameworks/running/debugcom.nlg +20 -3
  25. package/frameworks/running/debugnub.nlg +16 -7
  26. package/frameworks/running/executors.nlg +36 -26
  27. package/frameworks/running/instances.nlg +34 -22
  28. package/frameworks/running/remote_req.nlg +6 -9
  29. package/frameworks/running/remote_res.nlg +2 -2
  30. package/frameworks/running/sourcecode.nlg +3 -2
  31. package/frameworks/running/taskexec.nlg +14 -57
  32. package/frameworks/service/imp.nlg +37 -5
  33. package/frameworks/service/nubnode.nlg +39 -8
  34. package/frameworks/service/nubweb.nlg +28 -10
  35. package/frameworks/storage/file_manager.nlg +3 -2
  36. package/lib/browser/env_web.js +10 -39
  37. package/lib/browser/env_webworker.js +1 -30
  38. package/lib/core/naanlib.js +10 -10
  39. package/lib/env_node.js +5 -22
  40. package/lib/env_nodeworker.js +8 -43
  41. package/lib/node_server_init.nlg +149 -0
  42. package/lib/node_worker.js +36 -0
  43. package/lib/node_worker_init.nlg +43 -0
  44. package/package.json +1 -1
  45. package/plugins/openSearch/openSearch.nlg +3 -2
  46. package/plugins/openSearch/os_dynamo.nlg +3 -2
  47. package/plugins/serviceAws/aws_cloudwatchlogs.nlg +44 -2
  48. package/plugins/serviceAws/aws_dynamo.nlg +144 -63
  49. package/plugins/serviceAws/aws_utils.nlg +6 -11
  50. package/plugins/serviceAws/serviceAws.nlg +3 -2
  51. package/test/test_01_core.nlg +2 -2
  52. package/test/test_02_context.nlg +8 -8
  53. package/test/test_03_jsinterop.nlg +3 -3
  54. package/test/test_07_lingo.nlg +1 -1
@@ -10,93 +10,24 @@
10
10
  *
11
11
  */
12
12
 
13
- /*
14
- * globals
15
- *
16
- */
17
-
18
- gWorkers;
19
-
20
-
21
- /*
22
- * ioctl terminal control and events
23
- *
24
- * Example "raw" mode:
25
- *
26
- // rawTest
27
- // echo typed keystrokes in BOLD until Control-C stops it.
28
- //
29
- closure rawTest(local dokey) {
30
- dokey = xnew(function(msg, arg) {
31
- if arg.key == "\x03" {
32
- js.t.ioctl("raw", false)
33
- js.t.ioctl_remove_listener("raw-key", dokey)
34
- }
35
- else
36
- print("\x1b[1m${arg.key}\x1b[22m")
37
- })
38
- js.t.ioctl_add_listener("raw-key", dokey)
39
- js.t.ioctl("raw", true)
40
- };
41
-
42
- rawTest();
43
- *
44
- *
45
- * Example echo control:
46
- *
47
- js.t.ioctl("echo", 0) // no echo at all
48
- js.t.ioctl("echo", 1) // echo newlines (best for hiding REPL commands)
49
- js.t.ioctl("echo", 2) // normal echo
50
-
51
- js.t.ioctl("sane") // restore echo and raw
52
- *
53
- *
54
- * Example simulated keystrokes:
55
- *
56
- future(function(){ js.t.ioctl("keystroke", "joe") }, 10); // "joe" in keyboard buffer
57
- *
58
- *
59
- * Example terminal resize notification:
60
- *
61
- doresize = xnew(function(msg, dim) { printline("(${dim.cols}, ${dim.rows})")})
62
- js.t.ioctl_add_listener("term-resize", doresize);
63
- *
64
- *
65
- * Example terminal connection notification:
66
- *
67
- // add removable listener:
68
- listener = xnew(function(msg,arg) { debuglog("listener:", msg, arg) });
69
- js.t.ioctl_add_listener("term-attach", listener);
70
- js.t.ioctl_add_listener("term-detach", listener);
71
-
72
- // remove the listeners:
73
- js.t.ioctl_remove_listener("term-attach", listener);
74
- js.t.ioctl_remove_listener("term-detach", listener);
75
- *
76
- * Note that js.t.ioctl(...) controls the *terminal* even if attached to a different instance. But
77
- * ioctl event listeners are attached to an *instance* regardless of what terminal is connected.
78
- * But in general it does the "right thing" for multiple terminals on a single instance, and when
79
- * switching among instances.
80
- *
81
- */
82
-
83
13
 
84
14
  /*
85
15
  * TermHost
86
16
  *
87
- * Make an Nide API Server debugger target.
17
+ * Make a debugger target on our Host NaanIDE Server or a remote one.
88
18
  *
89
19
  * Options:
90
20
  * {
91
- * type: <string> // target category, e.g. "Host", "api.yyy.com"
92
- * workerID: <string> // kind of worker in server subsystem
93
- * startup: <dictionary> // startup options
21
+ * serverID: <string> // target server if not our Host
22
+ * type: <string> // target category, e.g. "Remote", "api.yyy.com"
23
+ * workerID: <string> // kind of worker in server subsystem
24
+ * startup: <dictionary> // startup options
94
25
  * }
95
26
  *
96
27
  */
97
28
 
98
29
  closure TermHost(track, name, options,
99
- local relay, error, destID, target, xc)
30
+ local relay, error, serverID, targetID, target, xc)
100
31
  {
101
32
  global(App)
102
33
 
@@ -105,15 +36,20 @@ closure TermHost(track, name, options,
105
36
  // Find the host instance name/type, or create new remote worker. The default for no name/type is
106
37
  // the server itself.
107
38
  //
108
- function findHostInstance(relay, name, type, local error, found, dest, worker) {
109
- `(error, found) = relay.clients()
110
- if !error {
111
- dest = found.find(function(item) { item.name == "NaanIDE Server" && item.type == "Server IMP" })
112
- if !dest
113
- error = Error("cannot locate host")
39
+ function findHostInstance(relay, name, type,
40
+ local error, found, dest, worker) {
41
+ if !serverID {
42
+ `(error, found) = relay.clients()
43
+ if !error {
44
+ dest = found.find(function(item) { item.name == "NaanIDE Server" && item.type == "Server IMP" })
45
+ if dest
46
+ serverID = dest.destID
47
+ else
48
+ error = Error("cannot locate host")
49
+ }
114
50
  }
115
51
  if !error
116
- `(error, found) = relay.clients(dest.destID)
52
+ `(error, found) = relay.clients(serverID)
117
53
  if !error {
118
54
  if name && type {
119
55
  dest = found.find(function(item) { item.name == name && item.type == type })
@@ -143,6 +79,7 @@ closure TermHost(track, name, options,
143
79
  name: name
144
80
  type: options.type
145
81
  startup: options.startup
82
+ rootPath: options.rootPath || undefined
146
83
  topOriginID: App.imp.us.instanceID
147
84
  })
148
85
  if error
@@ -162,10 +99,11 @@ closure TermHost(track, name, options,
162
99
  return (list(false, target)) // already exists
163
100
 
164
101
  relay = require("naanlib:frameworks/client/relaycon.nlg").RelayCon(App.imp)
102
+ serverID = options.serverID
165
103
  if options.workerID == "NideServer" // server main thread
166
- `(error, destID) = findHostInstance(relay)
104
+ `(error, targetID) = findHostInstance(relay)
167
105
  else
168
- `(error, destID) = findHostInstance(relay, name, options.type)
106
+ `(error, targetID) = findHostInstance(relay, name, options.type)
169
107
  relay.close()
170
108
  if error
171
109
  return (list(error))
@@ -174,9 +112,10 @@ closure TermHost(track, name, options,
174
112
  name: name
175
113
  type: options.type
176
114
  })
177
- target.workerID = options.workerID
115
+ target.serverID = serverID // server instanceID
116
+ target.workerID = options.workerID // worker on server instanceID
178
117
 
179
- `(error) = target.open(destID)
118
+ `(error) = target.open(targetID)
180
119
  if error
181
120
  return (list(Error("cannot create InTop", error)))
182
121
 
@@ -193,19 +132,19 @@ closure TermHost(track, name, options,
193
132
  *
194
133
  * Options:
195
134
  * {
196
- * workerID: <string> // kind of worker in server subsystem
135
+ * workerID: <string> // kind of worker in server subsystem
197
136
  * // "NaanIDE" for local IDE
198
- * startup: <dictionary> // startup options
199
- * type: <string> // (rare) target category, e.g. "Local"
137
+ * startup: <dictionary> // startup options
138
+ * type: <string> // (rare) target category, e.g. "Local"
139
+ * worker: <xobject> // existing worker or window
140
+ * naancont: <xobject> // NaaN controller if vsite
200
141
  * }
201
142
  *
202
143
  */
203
144
 
204
- closure TermLocal(track, name, options, local target, worker, inbot, error)
145
+ closure TermLocal(track, name, options, local target, worker, wowbot, error)
205
146
  {
206
- global(js, window, gWorkers)
207
- if !dictionary(gWorkers)
208
- gWorkers = {}
147
+ global(js, window)
209
148
  options = merge({
210
149
  type: "Local"
211
150
  }, options)
@@ -216,12 +155,18 @@ closure TermLocal(track, name, options, local target, worker, inbot, error)
216
155
  return (termIDE(track, name, options.workerID, js.t)) // connect to IDE execution instance itself
217
156
  }
218
157
 
219
- target = findIDEtarget(track, name, options.workerID)
220
- if target
221
- return (list(false, target)) // already exists
158
+ target = findIDEtarget(track, name, options.workerID, options.title, options.naancont)
159
+ if target { // new naancont on existing target
160
+ target.updateController(options)
161
+ track.update(target)
162
+ return (list(false, target))
163
+ }
222
164
 
223
- worker = xnew(window.Worker, "env_webworker.js")
224
- inbot = NubBot(worker, {
165
+ if options.worker
166
+ worker = options.worker
167
+ else
168
+ worker = xnew(window.Worker, "env_webworker.js")
169
+ wowbot = WowBot(worker, {
225
170
  name: name
226
171
  type: options.workerID
227
172
  startup: options.startup
@@ -231,10 +176,95 @@ closure TermLocal(track, name, options, local target, worker, inbot, error)
231
176
  type: options.type
232
177
  workerID: options.workerID
233
178
  })
234
- `(error) = target.open(inbot.instanceID)
179
+ `(error) = target.open(wowbot.instanceID)
235
180
  if error
236
181
  return (list(Error("cannot create InTop", error)))
237
182
 
183
+ target.title = options.title
184
+ target.naancont = options.naancont
185
+
186
+ // updateController
187
+ //
188
+ // Our controller was replaced, meaning the window changed.
189
+ //
190
+ target.updateController = function updateController(newops) {
191
+ target.execReset()
192
+ target.statusPoll = false
193
+ wowbot.close()
194
+ if defined(newops, `worker) {
195
+ if worker
196
+ target.impReceive({
197
+ id: "textout"
198
+ text: "\x1b[90m\x1b[3m".concat("\ntarget replaced", "\x1b[0m\n")
199
+ })
200
+ worker = newops.worker
201
+ }
202
+ if defined(newops, `title)
203
+ target.title = newops.title
204
+ if defined(newops, `naancont)
205
+ target.naancont = newops.naancont
206
+ wowbot = WowBot(worker, {
207
+ name: name
208
+ type: options.workerID
209
+ startup: options.startup
210
+ })
211
+ target.open(wowbot.instanceID)
212
+ }
213
+
214
+ // targetClose
215
+ //
216
+ // Mark the target window as closed.
217
+ //
218
+ target.targetClose = function targetClose() {
219
+ worker = false
220
+ target.execReset()
221
+ target.cleanup()
222
+ target.impReceive({
223
+ id: "textout"
224
+ text: "\x1b[90m\x1b[3m".concat("\nwindow closed", "\x1b[0m\n")
225
+ })
226
+ target.close()
227
+ }
228
+
229
+ // cleanup
230
+ //
231
+ // InTop is destroying our worker.
232
+ //
233
+ target.cleanup = function cleanup() {
234
+ target.statusPoll = false
235
+ target.naancont = false
236
+ }
237
+
238
+ // setCheckStatus
239
+ //
240
+ // Begin or end checking status on the worker to see if stopped responding. The challenge
241
+ // here is that we open vsite windows in the main thread, but there is no reliable event to learn
242
+ // when they are closed. The solution is to poll the window.closed variable, which is reliable.
243
+ // to learn more quickly if the window as closed, the child may also inform us, but this is not
244
+ // entirely reliable--just quick if accurate.
245
+ //
246
+ target.setCheckStatus = closure setCheckStatus(hidden, window) {
247
+ if !target.statusPoll
248
+ target.statusPoll = future(function childWindowClosePoll() {
249
+ while target.statusPoll {
250
+ if window.closed {
251
+ targetClose()
252
+ target.statusPoll = false
253
+ break
254
+ } else
255
+ sleep(1000) // check 1x/second
256
+ }
257
+ }, 10) // start after 10 msec
258
+ }
259
+
260
+ // vsiteRefresh
261
+ //
262
+ // The vsite upon which we are based has changed.
263
+ //
264
+ target.vsiteRefresh = function vsiteRefresh(url_origin) {
265
+ target.naancont.VsiteRefresh(url_origin)
266
+ }
267
+
238
268
  // finis
239
269
 
240
270
  list(false, target)
@@ -266,39 +296,33 @@ closure findIDEtarget(track, name, workerID, title, naancont, local target) {
266
296
  *
267
297
  * Make an IDE debugger target. The Naan controller in this case, env_web.js, iterates through
268
298
  * all connected terminals so we just have to provide unique connection object for it to talk with.
269
- * This is used for both the IDE itself as well as any additional virtual website windows.
299
+ * This is used for just the IDE itself.
270
300
  *
271
301
  */
272
302
 
273
- closure termIDE(track, name, workerID, naancont, title, local target, connected) {
274
- global(js, gWorkers)
275
- target = findIDEtarget(track, name, workerID, title, naancont)
276
- if target { // new naancont on existing target
277
- if target.naancont && naancont !== target.naancont
278
- target.targetClose()
279
- target.updateController(naancont)
280
- target.title = title
281
- track.update(target)
282
- return (target)
283
- }
303
+ closure termIDE(track, name, workerID, naancont, local target, connected) {
304
+ global(js)
305
+ target = findIDEtarget(track, name, workerID)
306
+ if target
307
+ return (list(false, target))
284
308
  target = require("../running/executors.nlg").ExecutorBase(track, "Local", name)
309
+ target.dispatcher = require("../running/taskexec.nlg").TaskDispatcher(false, false, "termIDE")
285
310
  target.name = name
286
- target.title = title
287
311
  target.workerID = workerID
288
312
  target.naancont = naancont
313
+ target.jsterms = new(weakmap)
289
314
  naancont.ioctl_open(ioctl_callback.proc)
290
315
  connected = []
291
-
292
- // replyHook
316
+
317
+ // PostMessage
293
318
  //
294
- // Intercept the ReplyMessage function to see if we should handle it.
319
+ // Process a message through the dispatcher.
295
320
  //
296
- function replyHook(data) {
297
- if data._guid
298
- gWorkers[data._guid].worker.postMessage({
299
- id: "targetreceive"
300
- data: data
301
- })
321
+ target.PostMessage = function PostMessage(data) {
322
+ target.dispatcher(data, function(reply) {
323
+ target.execReceived(reply)
324
+ })
325
+ list(false, { posted: true })
302
326
  }
303
327
 
304
328
  // ioctl_callback
@@ -323,22 +347,16 @@ closure termIDE(track, name, workerID, naancont, title, local target, connected)
323
347
  naancont.DispatchDebugger(data)
324
348
  }
325
349
 
326
- // target.PostMessage
327
- //
328
- // Post a message to the target, ourselves.
329
- //
330
- target.PostMessage = function PostMessage(data) {
331
- naancont.DispatchMessage(data)
332
- list(false, { posted: true })
333
- }
334
-
335
350
  // termAttach
336
351
  //
337
352
  // Create a closure for an attaching terminal.
338
353
  //
339
354
  target.termAttach = closure termAttach(term, db, notify, local connection, jsterm, inbound) {
340
- connection = new(object, this)
341
355
  jsterm = term.jsAcquire() // termIDE must be direct
356
+ if target.jsterms[jsterm]
357
+ return // return existing connection
358
+ connection = new(object, this)
359
+ target.jsterms[jsterm] = connection
342
360
 
343
361
  function oninterrupt() {
344
362
  naancont.Interrupt(inbound)
@@ -350,11 +368,7 @@ closure termIDE(track, name, workerID, naancont, title, local target, connected)
350
368
 
351
369
  function onstatus(status) {
352
370
  target.execSetStatus(status)
353
- statusCB(target, status)
354
- }
355
-
356
- function onmessageout(data) {
357
- target.execReceived(data)
371
+ notify.execStatus(target, status)
358
372
  }
359
373
 
360
374
  function ondebugout(data) {
@@ -377,10 +391,13 @@ closure termIDE(track, name, workerID, naancont, title, local target, connected)
377
391
  }
378
392
 
379
393
  connection.termDetach = function termDetach() { // disconnect the terminal
394
+ if !target.jsterms[jsterm]
395
+ return // already released
380
396
  db.detach(target)
381
397
  if inbound
382
398
  naancont.Detach(inbound)
383
399
  connected = connected.filter(function(conn) { conn !== connection })
400
+ target.jsterms[jsterm] = undefined
384
401
  term.jsRelease()
385
402
  }
386
403
 
@@ -399,7 +416,6 @@ closure termIDE(track, name, workerID, naancont, title, local target, connected)
399
416
  OnMessage: jsterm.OnMessage
400
417
  StateSave: jsterm.StateSave
401
418
  OnStatus: onstatus.proc
402
- OnMessageOut: onmessageout.proc
403
419
  OnDebugOut: ondebugout.proc
404
420
  })
405
421
  naancont.Attach(inbound)
@@ -439,74 +455,6 @@ closure termIDE(track, name, workerID, naancont, title, local target, connected)
439
455
  connection
440
456
  }
441
457
 
442
- // updateController
443
- //
444
- // Update the naan controller on this target, which means updating for all the terminals.
445
- //
446
- target.updateController = function updateController(newnc, local conn) {
447
- naancont.ioctl_close()
448
- naancont = newnc
449
- naancont.ioctl_open(ioctl_callback.proc)
450
- target.naancont = newnc
451
- for conn in connected {
452
- if naancont {
453
- naancont.Attach(conn.inbound) // tell the controller about terminals
454
- conn.db.attach(target) // re-attach since remote changed
455
- conn.termActive()
456
- } else
457
- conn.db.detach(target) // nothing left to debug
458
- }
459
- target.execReset() // reset our parent class
460
- }
461
-
462
- // targetClose
463
- //
464
- // Mark the target window as closed.
465
- //
466
- target.targetClose = function targetClose(local conn) {
467
- for conn in connected {
468
- conn.db.detach(target)
469
- conn.WriteLn("\x1b[90m\x1b[3m".concat("\ntarget closed", "\x1b[0m"))
470
- }
471
- target.execReset()
472
- naancont.ioctl_close()
473
- target.naancont = naancont = false
474
- }
475
-
476
- // setCheckStatus
477
- //
478
- // Begin or end checking status on the worker to see if stopped responding. The challenge
479
- // here is that we open vsite windows in the main thread, but there is no reliable event to learn
480
- // when they are closed. The solution is to start checking if the window is closed after it gets
481
- // a visibilityChange event to hidden. This terminates when the window gets marked closed or when
482
- // it becomes visible again--which is quite unlikely unless someone uses the explicit hide/show
483
- // window methods.
484
- //
485
- target.setCheckStatus = closure setCheckStatus(hidden, window) {
486
- if hidden {
487
- if !target.statusPoll
488
- target.statusPoll = future(function() {
489
- while target.statusPoll {
490
- if window.closed {
491
- targetClose()
492
- target.statusPoll = false
493
- break
494
- } else
495
- sleep(100) // check 10x/second
496
- }
497
- }, 10) // start after 10 msec
498
- } else
499
- target.statusPoll = false
500
- }
501
-
502
- // vsiteRefresh
503
- //
504
- // The vsite upon which we are based has changed.
505
- //
506
- target.vsiteRefresh = function vsiteRefresh(url_origin) {
507
- naancont.VsiteRefresh(url_origin)
508
- }
509
-
510
458
  // destroy
511
459
  //
512
460
  // Destroy the execution instance.
@@ -516,7 +464,6 @@ closure termIDE(track, name, workerID, naancont, title, local target, connected)
516
464
  track.delete(target)
517
465
  }
518
466
 
519
- js.t.OnReplyHook(replyHook.proc)
520
467
  track.add(target)
521
468
 
522
469
  // finis
@@ -534,17 +481,19 @@ closure termIDE(track, name, workerID, naancont, title, local target, connected)
534
481
  */
535
482
 
536
483
  closure termInstallVirtualWatcher(track, naancont) {
537
- global()
484
+ global(js)
538
485
 
539
486
  function watchVsites(msg, local error, target) {
540
487
  if msg.op == "VsiteOpen" {
541
- `(error, target) = termIDE(track, msg.name, "NaanVsite", msg.naancont, msg.title)
488
+ `(error, target) = TermLocal(track, msg.name, {
489
+ workerID: "NaanVsite", worker: msg.window, title: msg.title, naancont: msg.naancont
490
+ })
542
491
  target.attention()
543
492
  }
544
493
  else if msg.op == "VsiteClose" {
545
494
  target = findIDEtarget(track, msg.name, "NaanVsite", msg.title, msg.naancont)
546
495
  if target
547
- target.updateController()
496
+ target.updateController({ naancont: false }) // allow re-use of instance
548
497
  }
549
498
  else if msg.op == "VsiteVisibilityChange" {
550
499
  target = findIDEtarget(track, msg.name, "NaanVsite", msg.title, msg.naancont)
@@ -553,7 +502,7 @@ closure termInstallVirtualWatcher(track, naancont) {
553
502
  }
554
503
  }
555
504
 
556
- require("../running/executors.nlg").TaskOnMessageHook(watchVsites)
505
+ js.t.OnMessage(watchVsites.proc)
557
506
  };
558
507
 
559
508
 
@@ -653,8 +602,8 @@ closure relayTab(destID, local comMod, relay, error, found, dest, xc, reterm, or
653
602
  if error
654
603
  return (list(Error("cannot get remote terminal", error)))
655
604
  originID = App.imp.us.instanceID
656
- `(error, inbot) = xc.evalq(InBot(window, {
657
- name: "inbot"
605
+ `(error, inbot) = xc.evalq(MewBot(window, {
606
+ name: "mewbot"
658
607
  type: reterm.workerID
659
608
  topOriginID: originID
660
609
  }), `(reterm, originID))