@naanlang/naan 1.0.0

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 (98) hide show
  1. package/LICENSE.md +21 -0
  2. package/README.md +46 -0
  3. package/dist/env_web.js +431 -0
  4. package/dist/naan.min.js +73 -0
  5. package/frameworks/browser/browser.nlg +30 -0
  6. package/frameworks/browser/pouchdb/pouchdb.min.js +7 -0
  7. package/frameworks/browser/spark-md5/spark-md5.min.js +1 -0
  8. package/frameworks/browser/sworker.js +192 -0
  9. package/frameworks/browser/terminals.nlg +787 -0
  10. package/frameworks/browser/workers.nlg +386 -0
  11. package/frameworks/client/apiclient.nlg +183 -0
  12. package/frameworks/client/client.nlg +29 -0
  13. package/frameworks/client/psm_client.nlg +572 -0
  14. package/frameworks/common/common.nlg +464 -0
  15. package/frameworks/common/preferences.nlg +131 -0
  16. package/frameworks/common/repltools.nlg +100 -0
  17. package/frameworks/common/watching.nlg +97 -0
  18. package/frameworks/node/apiserver.nlg +399 -0
  19. package/frameworks/node/filesystem.nlg +1012 -0
  20. package/frameworks/node/gitter.nlg +234 -0
  21. package/frameworks/node/node.nlg +81 -0
  22. package/frameworks/node/psm_server.nlg +465 -0
  23. package/frameworks/node/worker.nlg +560 -0
  24. package/frameworks/project/build.nlg +1229 -0
  25. package/frameworks/project/jszip.js +30 -0
  26. package/frameworks/project/jszip.nlg +87 -0
  27. package/frameworks/project/proj_cliser.nlg +139 -0
  28. package/frameworks/project/proj_console.nlg +137 -0
  29. package/frameworks/project/proj_folder.nlg +143 -0
  30. package/frameworks/project/proj_lambda.nlg +137 -0
  31. package/frameworks/project/proj_static.nlg +138 -0
  32. package/frameworks/project/project.nlg +29 -0
  33. package/frameworks/project/projects.nlg +587 -0
  34. package/frameworks/project/uglifyjs.js +1 -0
  35. package/frameworks/project/uglifyjs.nlg +79 -0
  36. package/frameworks/running/debugcom.nlg +163 -0
  37. package/frameworks/running/debugnub.nlg +565 -0
  38. package/frameworks/running/debugutil.nlg +510 -0
  39. package/frameworks/running/executors.nlg +767 -0
  40. package/frameworks/running/running.nlg +151 -0
  41. package/frameworks/running/sourcecode.nlg +346 -0
  42. package/frameworks/running/taskexec.nlg +196 -0
  43. package/frameworks/storage/dbt_pouch.nlg +773 -0
  44. package/frameworks/storage/file_manager.nlg +772 -0
  45. package/frameworks/storage/psm.nlg +326 -0
  46. package/frameworks/storage/psm_dbtables.nlg +814 -0
  47. package/frameworks/storage/resources.nlg +445 -0
  48. package/frameworks/storage/storage.nlg +52 -0
  49. package/lib/browser/env_web.js +431 -0
  50. package/lib/browser/env_webworker.js +146 -0
  51. package/lib/browser/require.js +1653 -0
  52. package/lib/core/naanlib.js +73 -0
  53. package/lib/env_node.js +282 -0
  54. package/lib/env_nodeworker.js +165 -0
  55. package/lib/node_repl.js +25 -0
  56. package/lib/node_repl_init.nlg +52 -0
  57. package/package.json +13 -0
  58. package/plugins/gitClient/clientops.nlg +317 -0
  59. package/plugins/gitClient/gitClient.nlg +63 -0
  60. package/plugins/gitClient/gitutils.nlg +1331 -0
  61. package/plugins/gitClient/minimatch.js +945 -0
  62. package/plugins/gitClient/minimatch_license.txt +15 -0
  63. package/plugins/gitClient/minimatch_readme.md +208 -0
  64. package/plugins/nodeLib/nodeLib.nlg +26 -0
  65. package/plugins/nodeLib/node_cp.nlg +65 -0
  66. package/plugins/nodeLib/node_fs.nlg +137 -0
  67. package/plugins/nodeLib/node_https.nlg +172 -0
  68. package/plugins/nodeLib/node_util.nlg +180 -0
  69. package/plugins/serviceAws/aws/aws-sdk.min.js +88 -0
  70. package/plugins/serviceAws/aws/lambda_rest_index.js +122 -0
  71. package/plugins/serviceAws/aws/lambda_rest_init.nlg +58 -0
  72. package/plugins/serviceAws/aws/lambda_ws_index.js +498 -0
  73. package/plugins/serviceAws/aws/lambda_ws_init.nlg +49 -0
  74. package/plugins/serviceAws/aws_cloudwatchlogs.nlg +122 -0
  75. package/plugins/serviceAws/aws_cognito.nlg +76 -0
  76. package/plugins/serviceAws/aws_dynamo.nlg +509 -0
  77. package/plugins/serviceAws/aws_lambda.nlg +95 -0
  78. package/plugins/serviceAws/aws_s3.nlg +134 -0
  79. package/plugins/serviceAws/aws_utils.nlg +86 -0
  80. package/plugins/serviceAws/dbt_aws.nlg +769 -0
  81. package/plugins/serviceAws/lambda_naan_control.nlg +175 -0
  82. package/plugins/serviceAws/psm_aws.nlg +258 -0
  83. package/plugins/serviceAws/serviceAws.nlg +38 -0
  84. package/plugins/serviceGitHub/gitops.nlg +522 -0
  85. package/plugins/serviceGitHub/psm_github.nlg +205 -0
  86. package/plugins/serviceGitHub/serviceGitHub.nlg +65 -0
  87. package/plugins/serviceGitLab/gitops.nlg +528 -0
  88. package/plugins/serviceGitLab/psm_gitlab.nlg +205 -0
  89. package/plugins/serviceGitLab/serviceGitLab.nlg +65 -0
  90. package/test/harness.nlg +312 -0
  91. package/test/node_test.js +33 -0
  92. package/test/test_01_core.nlg +768 -0
  93. package/test/test_02_context.nlg +269 -0
  94. package/test/test_03_jsinterop.nlg +137 -0
  95. package/test/test_04_numerics.nlg +450 -0
  96. package/test/test_05_strings.nlg +63 -0
  97. package/test/test_06_lingoparse.nlg +500 -0
  98. package/test/test_07_lingo.nlg +623 -0
@@ -0,0 +1,767 @@
1
+ /*
2
+ * executors.nlg
3
+ *
4
+ * Execution resource tracker.
5
+ *
6
+ * column positioning: // // !
7
+ *
8
+ * Copyright (c) 2020-2021 by Richard C. Zulch
9
+ *
10
+ */
11
+
12
+
13
+ /*
14
+ * ExecutorBase
15
+ *
16
+ * A base class for executor instances with the common code.
17
+ *
18
+ */
19
+
20
+ closure ExecutorBase(track, type, name, local exec) {
21
+ exec = new(object, this)
22
+ exec.type = type
23
+ exec.name = name
24
+
25
+ // execReset
26
+ // Initialize remote communications for a new or restarted instance.
27
+
28
+ exec.execReset = function execReset() {
29
+ exec.pending = { }
30
+ exec.nextSendID = toint(RandomBytes(3)) // keep our sequence code unique for shared servers
31
+ exec.nextContextID = 1
32
+ }
33
+ execReset()
34
+
35
+ // execSend
36
+ // Send a message to the running instance and return a nonce to wait on. If data is not a
37
+ // dictionary then it is ignored.
38
+
39
+ exec.execSend = closure execSend(msg, data, local pending) {
40
+ if !dictionary(data)
41
+ data = { }
42
+ data.xmsg = msg
43
+ data.xid = exec.nextSendID++
44
+ pending = new(nonce)
45
+ pending.msgout = data
46
+ exec.pending[data.xid] = pending
47
+ exec.PostMessage(data)
48
+ pending
49
+ }
50
+
51
+ // execReceived
52
+ // THe specified message was received from the instance, so signal it.
53
+
54
+ exec.execReceived = closure execReceived(data, local pending) {
55
+ pending = exec.pending[data.xid]
56
+ if !pending {
57
+ if data.xmsg == "xready"
58
+ exec.pending.ready = true
59
+ return
60
+ }
61
+ exec.pending[data.xid] = undefined
62
+ pending.signal(list(false, data))
63
+ }
64
+
65
+ // execClosed
66
+ // Note that the connection has closed, so signal all the waiters.
67
+
68
+ exec.execClosed = closure execClosed(error, local xid) {
69
+ for `(xid, pending) in exec.pending {
70
+ pending.signal(list(error))
71
+ pending[xid] = undefined
72
+ }
73
+ }
74
+
75
+ // context
76
+ // Return a context object for the instance, or an error, in a result tuple. Currently this does
77
+ // not ever reclaim old contexts on the instance end of things, but it should. ###
78
+
79
+ exec.context = closure context(local context, retries, ms) {
80
+ retries = 0
81
+ ms = milliseconds()
82
+ while !exec.pending.ready {
83
+ exec.PostMessage({
84
+ xmsg: "xstart"
85
+ })
86
+ if ++retries > 100
87
+ return (list(Error("timeout creating remote worker context", type, name)))
88
+ sleep(100) }
89
+ context = ExecutorContext(exec, exec.nextContextID++)
90
+ context.register()
91
+ }
92
+
93
+ // attention
94
+ // Focus the UI on this instance because something needs attention.
95
+
96
+ exec.attention = function attention() {
97
+ track.attention(exec)
98
+ }
99
+
100
+ // finis
101
+ exec
102
+ };
103
+
104
+
105
+ /*
106
+ * ExecutorContext
107
+ *
108
+ * Contexts for remote execution. Remote evaluation requires a namespace context, but there is no
109
+ * easy, general way to specify the context between instances by default. This presents a challenge
110
+ * for accessing different modules, but can be even more difficult when arbitrary namespaces are
111
+ * being created.
112
+ * Execution contexts provide a means for remote evaluation in a specific context, including the
113
+ * ability to track namespace changes as the result of evaluating an expression. They do not override
114
+ * normal namespace protections. The contexts exposed here preserve the active namespace after the
115
+ * expression is evaluated.
116
+ *
117
+ */
118
+
119
+ closure ExecutorContext(exec, contextID, local context, util) {
120
+ context = new(object, this)
121
+ util = modlist().Util.exports
122
+
123
+ // register
124
+ // Register or re-register our context with the worker.
125
+
126
+ context.register = closure register(local pending, result) {
127
+ pending = exec.execSend("register", {
128
+ contextID: contextID
129
+ })
130
+ result = pending.wait()
131
+ if result.1
132
+ list(false, context)
133
+ else
134
+ result
135
+ }
136
+
137
+ // eval
138
+ // Evaluate the specified expression in the current worker context. The optional put argument
139
+ // if non-false is a tuple of symbols that should be transfered to the remote end, while get is
140
+ // an optional tuple of symbols to retrieve after evaluation.
141
+
142
+ context.eval = closure evalf(expr, put, get, local roots, pkg, data, pending, result) {
143
+ if tuple(put)
144
+ roots = cons(`expr, put)
145
+ else
146
+ roots = `(expr)
147
+ pkg = util.pkgSave(`expr, roots, {
148
+ nsignore: true
149
+ comments: true })
150
+ data = {
151
+ contextID: contextID
152
+ expr: pkg }
153
+ if tuple(get)
154
+ data.get = get
155
+ pending = exec.execSend("eval", data)
156
+ result = pending.wait()
157
+ if result.1.error
158
+ list(Error(result.1.error))
159
+ else if result.1.result
160
+ list(false, caar(util.pkgLoad(result.1.result, {
161
+ localroots: false
162
+ intern: false
163
+ execute: false
164
+ })))
165
+ else
166
+ result
167
+ }
168
+
169
+ // evalq
170
+ // Evaluate the specified QUOTED expression in the current worker context.
171
+
172
+ context.evalq = macro evalq(expr, put, get) {
173
+ evalf(expr, eval(put), eval(get))
174
+ }
175
+
176
+ // rpc
177
+ // Execute a remote procedure call without package translation, to reduce overhead. This will not
178
+ // properly transfer Naan-specific types like symbols, and the results will be native JavaScript.
179
+ // The procedure must be specified as a symbol or string.
180
+
181
+ context.rpc = closure rpc(proc, args, local data, result) {
182
+ data = {
183
+ contextID: contextID
184
+ proc: proc
185
+ args: args }
186
+ pending = exec.execSend("rpc", data)
187
+ result = pending.wait()
188
+ if result.1.error
189
+ list(Error(result.1.error))
190
+ else
191
+ list(false, totuple(result.1.result))
192
+ }
193
+
194
+ // finis
195
+ context
196
+ };
197
+
198
+
199
+ /*
200
+ * ExecutorParallel
201
+ *
202
+ * Evaluate expressions in parallel. Given a maximum number of workers, this delegates processing
203
+ * to an available worker or enqueues the work to be done on the next available worker, blocking the
204
+ * caller until the work is complete. Destroying this object releases the workers and terminates any
205
+ * pending work with errors.
206
+ * Creating a worker takes 200-300 msec, so this acts like a worker pool and allows them to be
207
+ * saved and reused when needed. At the moment there is no affinity feature, so the actual worker
208
+ * assigned for each task is not selectable.
209
+ * The eval() method can be quite slow because the arguments and result are converted four times
210
+ * through the package manager for each call. Thefore it should only be used for small requests or
211
+ * when Naan semantics must be maintained across the address space transition to the worker.
212
+ * The rpc() method has a very low overhead, but converts everything to JavaScript before making
213
+ * the call. The procedure is specified as a name and must exist as a symbol in the current
214
+ * namespace of the worker. The arguments are specified as a tuple, and will be converted using the
215
+ * normal Naan exporting protocol. So for example, tuples become arrays and symbols become strings.
216
+ * The result will also be in JavaScript types.
217
+ *
218
+ * Allowable options are:
219
+ * {
220
+ * maxcount: <integer> // maximum workers, default 4
221
+ * initeval: `(<expr>, <put>, <get>) // initializes each new worker
222
+ * basename: <string> // worker label for UI, default "batch"
223
+ * }
224
+ *
225
+ */
226
+
227
+ closure ExecutorParallel(options, local maxcount, basename, parallel, exqueue, crValue) {
228
+ maxcount = options.maxcount
229
+ if !maxcount
230
+ maxcount = 4 // default is 4 workers
231
+ basename = options.basename
232
+ if !string(basename)
233
+ basename = "batch"
234
+ exqueue = [] // waiting for execution
235
+ parallel = new(object, this)
236
+ parallel.workers = [] // array of worker executors
237
+ parallel.contexts = new(weakmap) // map workers to contexts
238
+ parallel.available = [] // array of available workers
239
+
240
+ // acquireWorker
241
+ //
242
+ // Return the next available worker. If no workers are available and we haven't hit the maximum
243
+ // then create an additional worker and return it. If we cannot allocate another worker then this
244
+ // returns false.
245
+
246
+ closure acquireWorker(local workdex, name, worker, context, result) {
247
+ if parallel.available.length > 0
248
+ return (parallel.available.pop())
249
+ workdex = parallel.workers.length
250
+ if workdex >= maxcount
251
+ return (false)
252
+ parallel.workers[workdex] = false // reserve our spot
253
+ name = basename.concat("-", workdex+1)
254
+ worker = App.nide.track.spawn("Local", name, "ExecutorParallel")
255
+ if worker.0 { // ### wasting space on workers list
256
+ debuglog("execParallel: cannot spawn worker:", ErrorString(worker.0))
257
+ return (false)
258
+ }
259
+ worker = worker.1
260
+ context = worker.context()
261
+ if context.0 {
262
+ debuglog("execParallel: cannot create worker context:", ErrorString(context.0))
263
+ worker.destroy()
264
+ return (false)
265
+ }
266
+ context = context.1
267
+ parallel.workers[workdex] = worker
268
+ parallel.contexts[worker] = context
269
+ if tuple(options.initeval) {
270
+ result = apply(context.eval, options.initeval)
271
+ if result.0
272
+ debuglog("execParallel: cannot initialize worker", name, ErrorString(result.0)) }
273
+ return (worker)
274
+ }
275
+
276
+ // releaseWorker
277
+ //
278
+ // Release the specified worker to the pool.
279
+
280
+ closure releaseWorker(worker) {
281
+ parallel.available.push(worker)
282
+ }
283
+
284
+ // execNext
285
+ //
286
+ // Run the next operation, if any are pending. It's possible that this will acquire a worker and
287
+ // during that process another worker completes and leaves us with nothing to do. In that case we
288
+ // release the worker and do nothing. Another case is where this tries to acquire a worker and
289
+ // cannot at this time, because they are all busy and there is no room for more. This is why we
290
+ // don't remove work from the queue until we already have a worker.
291
+ //
292
+
293
+ closure execNext(local worker, result) {
294
+ if exqueue.length > 0 {
295
+ worker = acquireWorker() // false if none available
296
+ if !worker {
297
+ if maxcount > 0 && parallel.workers.length == 0 // maxcount zero when being destroyed
298
+ throw("execParallel: cannot allocate any workers at all")
299
+ return // we're busy, so try again later
300
+ }
301
+ future(function(local next, context) {
302
+ next = exqueue.splice(0, 1).0 // remove oldest entry, from start
303
+ if !next {
304
+ releaseWorker(worker) // someone else already processed this
305
+ return
306
+ }
307
+ context = parallel.contexts[worker]
308
+ if next.eval
309
+ result = apply(context.eval, next.args)
310
+ else if next.proc
311
+ result = context.rpc(next.proc, next.args)
312
+ else
313
+ debuglog("execNext: exqueue item without task", next.*)
314
+ next.pending.signal(result)
315
+ releaseWorker(worker)
316
+ execNext() // start the next one, if there is one
317
+ }, 1)
318
+ }
319
+ }
320
+
321
+ // eval
322
+ //
323
+ // Evaluate the specified expression in the next available worker, creating workers as required.
324
+ // This blocks the caller until the operation is complete, and returns the result.
325
+ //
326
+
327
+ parallel.eval = closure evalf(expr, put, get, local pending) {
328
+ if !maxcount
329
+ return (crValue) // already destroyed
330
+ pending = new(nonce)
331
+ exqueue.push({
332
+ eval: list(expr, put, get)
333
+ pending: pending
334
+ })
335
+ execNext()
336
+ pending.wait()
337
+ }
338
+
339
+ // evalq
340
+ //
341
+ // Evaluate the specified QUOTED expression in a remote worker.
342
+ //
343
+
344
+ parallel.evalq = macro evalq(expr, put, get) {
345
+ evalf(expr, eval(put), eval(get))
346
+ }
347
+
348
+ // rpc
349
+ //
350
+ // Execute a procedure call in a remote worker.
351
+ //
352
+
353
+ parallel.rpc = closure rpc(proc, args, local pending) {
354
+ if !maxcount
355
+ return (crValue) // already destroyed
356
+ pending = new(nonce)
357
+ exqueue.push({
358
+ proc: proc
359
+ args: args
360
+ pending: pending
361
+ })
362
+ execNext()
363
+ pending.wait()
364
+ }
365
+
366
+ // destroy
367
+ //
368
+ // Destroy the object by destroying the workers and failing pending requests with cancelResult.
369
+ //
370
+
371
+ parallel.destroy = closure destroy(cancelResult, local worker, next) {
372
+ if !maxcount
373
+ return (false) // already destroyed
374
+ crValue = cancelResult
375
+ maxcount = 0
376
+ parallel.available = false
377
+ parallel.contexts = false
378
+ while parallel.workers.length > 0 {
379
+ worker = parallel.workers.pop()
380
+ parallel.contexts[worker] = false
381
+ worker.destroy()
382
+ }
383
+ while exqueue.length > 0 {
384
+ next = exqueue.pop()
385
+ next.pending.signal(crValue)
386
+ }
387
+ true
388
+ }
389
+
390
+ // finis
391
+
392
+ parallel
393
+ };
394
+
395
+
396
+ /*
397
+ * ExecutorTracker
398
+ *
399
+ * Track Naan execution instances.
400
+ *
401
+ */
402
+
403
+ closure ExecutorTracker(local xtrak) {
404
+ xtrak = new(object, this)
405
+ xtrak.instances = []
406
+ xtrak.watchers = []
407
+ xtrak.makers = {}
408
+
409
+ // notify
410
+ // Notify the watchers by calling a named procedure
411
+
412
+ closure notify(changes, local watch) {
413
+ for watch in xtrak.watchers
414
+ call(watch, changes)
415
+ }
416
+
417
+ // add
418
+ // Add an execution instance at the specified location.
419
+
420
+ xtrak.add = closure add(executor, local instance) {
421
+ instance = new(nonce)
422
+ instance.executor = executor
423
+ xtrak.instances.push(instance)
424
+ notify({ added: [executor] })
425
+ }
426
+
427
+ // delete
428
+ // Delete an execution instance.
429
+
430
+ xtrak.delete = closure delete(executor) {
431
+ xtrak.instances = xtrak.instances.filter(function(item){
432
+ !(item.executor eq executor)
433
+ })
434
+ notify({ deleted: [executor] })
435
+ }
436
+
437
+ // update
438
+ // Notify watchers of an update on an execution instance.
439
+
440
+ xtrak.update = closure update(executor) {
441
+ notify({ updated: [executor] })
442
+ }
443
+
444
+ // attention
445
+ // Notify watchers that our instance wants attention.
446
+
447
+ xtrak.attention = closure attention(executor) {
448
+ notify({ attention: [executor] })
449
+ }
450
+
451
+ // enumlist
452
+ // Enumerate the list of executors.
453
+
454
+ xtrak.enumlist = function enumlist(local results) {
455
+ results = []
456
+ for instance in xtrak.instances
457
+ results.push(instance.executor)
458
+ results
459
+ }
460
+
461
+ // watch
462
+ // Watch for changes on execution instance status.
463
+
464
+ xtrak.watch = function watch(watcher) {
465
+ if xtrak.watchers.indexOf(watcher) < 0
466
+ xtrak.watchers.push(watcher)
467
+ }
468
+
469
+ // unwatch
470
+ // Stop watching for changes on execution instance status.
471
+
472
+ xtrak.unwatch = function unwatch(watcher) {
473
+ xtrak.watchers.filter(function(item){
474
+ !(item eq watcher)
475
+ })
476
+ }
477
+
478
+ // register
479
+ // Register an executor type.
480
+
481
+ xtrak.register = function register(maker, type) {
482
+ xtrak.makers[type] = maker
483
+ }
484
+
485
+ // spawn
486
+ // Spawn a new executor with (type, args), returning a standard (error, result) tuple.
487
+
488
+ xtrak.spawn = closure spawn args {
489
+ function spawnit(type, args) {
490
+ if !xtrak.makers[type]
491
+ list(Error("unknown executor type", type))
492
+ else
493
+ apply(xtrak.makers[type], cons(xtrak, args))
494
+ } (pop(args), args)
495
+ }
496
+
497
+ xtrak.register(execLambda, "Lambda")
498
+
499
+ // finis
500
+ xtrak
501
+ };
502
+
503
+
504
+ /*
505
+ * execLambda
506
+ *
507
+ * Make a Lambda executor connected through web sockets.
508
+ *
509
+ */
510
+
511
+ closure execLambda(track, url, name, workerID, local target, nlregex, clientID, serverID) {
512
+ target = ExecutorBase(track, "Lambda", name)
513
+ clientID = "DebugWorkers"
514
+ serverID = "Workers"
515
+ nlregex = RegExp("\\n", "g")
516
+ if !workerID
517
+ workerID = "myAwsDebugWorker"
518
+ target.workerID = workerID
519
+ target.msgQueue = []
520
+
521
+ // connect
522
+ // Connect with the host if not already connected.
523
+ function connect() {
524
+ if !target.ws
525
+ target.ws = xnew(js.w.WebSocket, "wss://8h5htw8bfj.execute-api.us-east-1.amazonaws.com/dev")
526
+
527
+ // onopen
528
+ // The WebSocket connection is now open.
529
+ target.ws.onopen = function onopen(e) {
530
+ target.msgCounter = 1
531
+ sendControl("spawn", {
532
+ reset: true
533
+ options: {
534
+ }
535
+ })
536
+ }
537
+
538
+ // onmessage
539
+ // A message was received from the worker via WebSockets.
540
+
541
+ target.ws.onmessage = function onmessage(e, local message, msg) {
542
+ if target.msgQueue
543
+ target.msgQueue.push(e.data)
544
+ else
545
+ target.doMessage(e.data)
546
+ }
547
+
548
+ // onerror
549
+ // An error occurred on the WebSocket connection.
550
+ target.ws.onerror = function onerror(e) {
551
+ target.debugWrite("connection error: ".concat(e.toString()), 3)
552
+ }
553
+
554
+ // onclose
555
+ // The WebSocket connection was closed.
556
+ target.ws.onclose = function onclose(e) {
557
+ target.debugWrite("connection closed: ".concat(e.code, " ", e.reason), 3)
558
+ target.ws = false
559
+ }
560
+ }
561
+
562
+ //
563
+ // doOneMessage
564
+ //
565
+ // Process the specified undecoded message.
566
+ function doOneMessage(message, local msg) {
567
+ if message.respOp == "msgarray" {
568
+ for msg in message.payload
569
+ doOneMessage(msg)
570
+ } else if message.respOp == "msgout" {
571
+ msg = message.payload
572
+ if msg.id == "textout" {
573
+ target.written = true
574
+ target.term.Write(msg.text.replace(nlregex, "\r\n")) }
575
+ else if msg.id == "debugtext" {
576
+ target.written = true
577
+ target.debugWrite(msg.text, msg.level) }
578
+ else if msg.id == "msgout"
579
+ target.listener(msg.data)
580
+ else if msg.id == "started"
581
+ { }
582
+ else if msg.id == "typed"
583
+ target.term.Write(msg.text.replace(nlregex, "\r\n"))
584
+ else if msg.id == "status"
585
+ target.statusCB(target, msg.status)
586
+ else
587
+ debuglog("unknown AWS worker message:", msg.id)
588
+ } else if message.respOp == "error"
589
+ debuglog("worker controller error:", ErrorString(message.payload[0]))
590
+ else if message.respOp == "linked"
591
+ future(function termLinked(){
592
+ if !target.written
593
+ target.term.WriteLn("(reconnected)")
594
+ }, 1000).run()
595
+ else
596
+ debuglog("unknown AWS response message:", message.respOp)
597
+ }
598
+
599
+ //
600
+ // doMessage
601
+ //
602
+ // Process the specified undecoded message.
603
+ target.doMessage = function doMessage(text, local message) {
604
+ try {
605
+ message = new(js.w.JSON.parse(text))
606
+ if message.connectionId && string(message.message)
607
+ target.debugWrite("AWS response: ".concat(message.message), 3)
608
+ else if message.clientID != clientID || message.serverID != serverID || message.workerID != target.workerID
609
+ debuglog("AWS response doesn't match:", message.clientID, message.serverID, message.workerID)
610
+ else
611
+ doOneMessage(message)
612
+ } catch {
613
+ if true
614
+ return (debuglog("can't decode incoming ws message:", exception))
615
+ }
616
+ }
617
+
618
+ //
619
+ // sendControl
620
+ //
621
+ // Send a message to the worker controller.
622
+
623
+ target.sendControl = function sendControl(workerOp, payload) {
624
+ target.ws.send(js.w.JSON.stringify({
625
+ clientID: clientID
626
+ serverID: serverID
627
+ workerID: target.workerID
628
+ workerOp: workerOp
629
+ payload: payload
630
+ msgCounter: target.msgCounter++
631
+ }))
632
+ }
633
+
634
+ //
635
+ // send
636
+ //
637
+ // Send a message to the worker.
638
+
639
+ target.send = function send(msg) {
640
+ // msg.save = true // save state for this invocation
641
+ sendControl("msgin", msg)
642
+ }
643
+
644
+ //
645
+ // oninterrupt
646
+ //
647
+
648
+ function oninterrupt() {
649
+ send({ // send interrupt to worker
650
+ id: "interrupt"
651
+ })
652
+ }
653
+
654
+ //
655
+ // onreturn
656
+ //
657
+
658
+ function onreturn(local text) {
659
+ text = target.term.TakeText()
660
+ send({ // send user-entered text to worker
661
+ id: "keyline",
662
+ text: text,
663
+ typed: "\x1b[90m\x1b[3m".concat(text, "\x1b[0m\n") // dark-grey, italic
664
+ })
665
+ }
666
+
667
+ //
668
+ // target.PostMessage
669
+ //
670
+ // Post a message to the target.
671
+ //
672
+
673
+ target.PostMessage = function PostMessage(data) {
674
+ target.ws.send({ // send user-entered text to worker
675
+ id: "msgin",
676
+ data: data
677
+ })
678
+ }
679
+
680
+ //
681
+ // target.debugWrite
682
+ //
683
+ // Write a debug message to the repl.
684
+ //
685
+
686
+ target.debugWrite = function(text, level) {
687
+ if (level >= 5)
688
+ target.term.WriteLn(text, target.term.Cyan) // cyan for builtin logging
689
+ else if (level >= 4)
690
+ target.term.WriteLn(text, target.term.Blue) // blue for Naan function logging
691
+ else if (level >= 3)
692
+ target.term.WriteLn(text, target.term.Red) // light red for warnings
693
+ else if (level >= 2)
694
+ target.term.WriteLn(text, target.term.Green) // green for Naan.debug.debuglog logging
695
+ else
696
+ target.term.WriteLn(text, target.term.Red+target.term.Bold) // heavy red for errors
697
+ }
698
+
699
+ //
700
+ // termAttach
701
+ //
702
+ // A terminal was attached to our instance.
703
+
704
+ target.termAttach = function termAttach(repl, db, statusCB, local msg) {
705
+ connect() // ensure we are connected
706
+ target.term = repl
707
+ target.debugger = db
708
+ target.statusCB = statusCB
709
+ if target.termSaved {
710
+ target.term.StateLoad(target.termSaved)
711
+ target.termSaved = false }
712
+ else
713
+ target.term.Reset()
714
+ while target.msgQueue.length > 0 {
715
+ for msg in target.msgQueue.splice(0) // all current messages
716
+ target.doMessage(msg)
717
+ }
718
+ target.msgQueue = false
719
+ target.term.On("interrupt", oninterrupt.proc)
720
+ target.term.On("return", onreturn.proc)
721
+ target.term.Focus()
722
+ }
723
+
724
+ //
725
+ // termDetach
726
+ //
727
+ // The terminal is being deattached from our instance.
728
+
729
+ target.termDetach = function termDetach(repl) {
730
+ target.term.On("interrupt")
731
+ target.term.On("return")
732
+ target.msgQueue = []
733
+ target.termSaved = target.term.StateSave()
734
+ target.statusCB = false
735
+ target.debugger = false
736
+ target.term = false
737
+ }
738
+
739
+ track.add(target)
740
+ connect() // connect right away to start receiving messages
741
+
742
+ // finis
743
+
744
+ list(false, target)
745
+ };
746
+
747
+
748
+ /*
749
+ * execInit
750
+ *
751
+ * Initialize the component.
752
+ *
753
+ */
754
+
755
+ function execInit(local manifest) {
756
+
757
+ manifest = `(ExecutorBase, ExecutorContext, ExecutorParallel, ExecutorTracker, execLambda, execInit)
758
+
759
+ Naan.module.build(module.id, "executors", function(modobj, compobj) {
760
+ require("./running.nlg")
761
+ compobj.manifest = manifest
762
+ modobj.exports.ExecutorBase = ExecutorBase
763
+ modobj.exports.ExecutorContext = ExecutorContext
764
+ modobj.exports.ExecutorParallel = ExecutorParallel
765
+ modobj.exports.ExecutorTracker = ExecutorTracker
766
+ })
767
+ } ();