@naanlang/naan 1.5.0 → 1.7.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 (62) hide show
  1. package/LICENSE.md +2 -2
  2. package/README.md +2 -2
  3. package/bin/index.js +7 -3
  4. package/dist/env_web.js +162 -48
  5. package/dist/naan.min.js +11 -11
  6. package/frameworks/browser/https_request.nlg +2 -2
  7. package/frameworks/browser/sworker.js +28 -26
  8. package/frameworks/browser/terminals.nlg +295 -737
  9. package/frameworks/browser/worker.nlg +295 -0
  10. package/frameworks/browser/workers.nlg +6 -6
  11. package/frameworks/browser/ws_client.nlg +15 -10
  12. package/frameworks/client/apiclient.nlg +211 -9
  13. package/frameworks/client/psm_client.nlg +10 -14
  14. package/frameworks/client/relaycon.nlg +87 -161
  15. package/frameworks/common/common.nlg +2 -0
  16. package/frameworks/common/events.nlg +101 -0
  17. package/frameworks/common/repltools.nlg +80 -1
  18. package/frameworks/node/apiserver.nlg +38 -246
  19. package/frameworks/node/filesystem.nlg +31 -6
  20. package/frameworks/node/http_request.nlg +34 -13
  21. package/frameworks/node/https_request.nlg +8 -3
  22. package/frameworks/node/node.nlg +3 -0
  23. package/frameworks/node/pty.nlg +346 -0
  24. package/frameworks/node/shell.nlg +26 -3
  25. package/frameworks/node/worker.nlg +504 -560
  26. package/frameworks/node/ws_client.nlg +2 -2
  27. package/frameworks/project/build.nlg +56 -14
  28. package/frameworks/project/projects.nlg +1 -1
  29. package/frameworks/running/debugcom.nlg +20 -3
  30. package/frameworks/running/debugnub.nlg +33 -11
  31. package/frameworks/running/executors.nlg +40 -285
  32. package/frameworks/running/instances.nlg +394 -0
  33. package/frameworks/running/remote_req.nlg +139 -0
  34. package/frameworks/running/remote_res.nlg +89 -0
  35. package/frameworks/running/sourcecode.nlg +3 -2
  36. package/frameworks/running/taskexec.nlg +16 -59
  37. package/frameworks/service/imp.nlg +751 -0
  38. package/frameworks/service/model.nlg +71 -0
  39. package/frameworks/service/nubnode.nlg +136 -0
  40. package/frameworks/service/nubweb.nlg +124 -0
  41. package/frameworks/service/service.nlg +28 -0
  42. package/frameworks/storage/file_manager.nlg +3 -2
  43. package/lib/browser/env_web.js +169 -55
  44. package/lib/browser/env_webworker.js +89 -31
  45. package/lib/core/naanlib.js +11 -11
  46. package/lib/env_node.js +186 -27
  47. package/lib/env_nodeworker.js +82 -44
  48. package/lib/node_server_init.nlg +149 -0
  49. package/lib/node_worker.js +36 -0
  50. package/lib/node_worker_init.nlg +43 -0
  51. package/package.json +1 -1
  52. package/plugins/openSearch/openSearch.nlg +3 -2
  53. package/plugins/openSearch/os_dynamo.nlg +3 -2
  54. package/plugins/serviceAws/aws_cloudwatchlogs.nlg +44 -2
  55. package/plugins/serviceAws/aws_dynamo.nlg +144 -63
  56. package/plugins/serviceAws/aws_utils.nlg +6 -11
  57. package/plugins/serviceAws/serviceAws.nlg +3 -2
  58. package/plugins/serviceNexara/speechrec.nlg +10 -6
  59. package/test/test_01_core.nlg +2 -2
  60. package/test/test_02_context.nlg +32 -9
  61. package/test/test_03_jsinterop.nlg +3 -3
  62. package/test/test_07_lingo.nlg +1 -1
@@ -5,7 +5,7 @@
5
5
  *
6
6
  * column positioning: // // !
7
7
  *
8
- * Copyright (c) 2020-2024 by Richard C. Zulch
8
+ * Copyright (c) 2020-2026 by Richard C. Zulch
9
9
  *
10
10
  */
11
11
 
@@ -65,7 +65,7 @@ closure ExecutorBase(track, type, name, local exec) {
65
65
  exec.reverseDispatch = require("./taskexec.nlg").TaskDispatcher(function(data) {
66
66
  data.reverse = true
67
67
  exec.PostMessage(data)
68
- }, exec.contexts[data.contextID].coder)
68
+ }, exec.contexts[data.contextID].coder, "execReceived")
69
69
  data.reverse = false
70
70
  exec.reverseDispatch(data)
71
71
  return
@@ -73,7 +73,7 @@ closure ExecutorBase(track, type, name, local exec) {
73
73
  pending = exec.pending[data.xid]
74
74
  if !pending { // not waiting on message
75
75
  if data.xmsg == "xready"
76
- exec.pending.ready = true
76
+ exec.inst_ready = true
77
77
  if data.xmsg == "xattention"
78
78
  { }
79
79
  return
@@ -99,7 +99,7 @@ closure ExecutorBase(track, type, name, local exec) {
99
99
  // Communication has failed.
100
100
  //
101
101
  exec.execFailed = closure execFailed(error, local xid, pending) {
102
- exec.pending.error = error
102
+ exec.inst_error = error
103
103
  for `(xid, pending) in exec.pending
104
104
  pending.signal(list(error))
105
105
  }
@@ -112,7 +112,7 @@ closure ExecutorBase(track, type, name, local exec) {
112
112
  exec.execClosed = closure execClosed(error, local xid, pending) {
113
113
  for `(xid, pending) in exec.pending {
114
114
  pending.signal(list(error))
115
- pending[xid] = undefined
115
+ exec.pending[xid] = undefined
116
116
  }
117
117
  }
118
118
 
@@ -127,7 +127,7 @@ closure ExecutorBase(track, type, name, local exec) {
127
127
  retries = 0
128
128
  ms = milliseconds()
129
129
  delta = 1
130
- while !exec.pending.ready {
130
+ while !exec.inst_ready {
131
131
  `(error) = exec.PostMessage({
132
132
  xmsg: "xstart"
133
133
  })
@@ -135,8 +135,8 @@ closure ExecutorBase(track, type, name, local exec) {
135
135
  return (Error("exec.context failed", error))
136
136
  if ++retries > 100
137
137
  return (list(Error("timeout creating remote context", type, name)))
138
- if exec.pending.error
139
- return (list(Error("cannot create remote context", exec.pending.error)))
138
+ if exec.inst_error
139
+ return (list(Error("cannot create remote context", exec.inst_error)))
140
140
  sleep(delta)
141
141
  if delta < 100
142
142
  delta *= 2 }
@@ -338,7 +338,7 @@ closure ExecutorContext(exec, state, coder, local context, util) {
338
338
  *
339
339
  */
340
340
 
341
- closure ExecutorParallel(track, options, local maxcount, parallel, exqueue, crValue) {
341
+ closure ExecutorParallel(track, options, local maxcount, parallel, state, exqueue, crValue) {
342
342
  global()
343
343
  options = merge({
344
344
  spawnLoc: "Local"
@@ -348,9 +348,10 @@ closure ExecutorParallel(track, options, local maxcount, parallel, exqueue, crVa
348
348
  maxcount = options.maxcount
349
349
  exqueue = [] // waiting for execution
350
350
  parallel = new(object, this)
351
- parallel.workers = [] // array of worker executors
351
+ parallel.state = state = new(nonce) // volatile state
352
352
  parallel.contexts = new(weakmap) // map workers to contexts
353
- parallel.available = [] // array of available workers
353
+ state.workers = [] // array of worker executors
354
+ state.available = [] // array of available workers
354
355
 
355
356
  // acquireWorker
356
357
  //
@@ -359,31 +360,31 @@ closure ExecutorParallel(track, options, local maxcount, parallel, exqueue, crVa
359
360
  // returns { wait: true }.
360
361
 
361
362
  closure acquireWorker(local workdex, name, worker, context, result) {
362
- if parallel.available.length > 0
363
- return (list(false, parallel.available.pop()))
364
- workdex = parallel.workers.length
363
+ if state.available.length > 0
364
+ return (list(false, state.available.pop()))
365
+ workdex = state.workers.length
365
366
  if workdex >= maxcount
366
367
  return (list(false, { wait: true }))
367
- parallel.workers[workdex] = false // reserve our spot
368
+ state.workers[workdex] = false // reserve our spot
368
369
  name = options.basename.concat("-", workdex+1)
369
370
  worker = track.spawn(options.spawnLoc, name, {
370
371
  workerID: "ExecutorParallel"
371
372
  })
372
373
  if worker.0 {
373
- parallel.workers.splice(workdex, 1)
374
+ state.workers.splice(workdex, 1)
374
375
  debuglog("execParallel: cannot spawn worker:", ErrorString(worker.0))
375
376
  return (list(worker.0))
376
377
  }
377
378
  worker = worker.1
378
379
  context = worker.context()
379
380
  if context.0 {
380
- parallel.workers.splice(workdex, 1)
381
+ state.workers.splice(workdex, 1)
381
382
  worker.destroy()
382
383
  debuglog("execParallel: cannot create worker context:", ErrorString(context.0))
383
384
  return (list(context.0))
384
385
  }
385
386
  context = context.1
386
- parallel.workers[workdex] = worker
387
+ state.workers[workdex] = worker
387
388
  parallel.contexts[worker] = context
388
389
  if tuple(options.initeval) {
389
390
  result = apply(context.eval, options.initeval)
@@ -398,7 +399,7 @@ closure ExecutorParallel(track, options, local maxcount, parallel, exqueue, crVa
398
399
  // Release the specified worker to the pool.
399
400
 
400
401
  closure releaseWorker(worker) {
401
- parallel.available.push(worker)
402
+ state.available.push(worker)
402
403
  }
403
404
 
404
405
  // execNext
@@ -414,7 +415,7 @@ closure ExecutorParallel(track, options, local maxcount, parallel, exqueue, crVa
414
415
  if exqueue.length > 0 {
415
416
  `(error, worker) = acquireWorker()
416
417
  if error {
417
- if maxcount > 0 && parallel.workers.length == 0 {
418
+ if maxcount > 0 && state.workers.length == 0 {
418
419
  exqueue = []
419
420
  throw("execParallel: cannot allocate any workers at all") }
420
421
  return // one failed, so try again later
@@ -448,8 +449,10 @@ closure ExecutorParallel(track, options, local maxcount, parallel, exqueue, crVa
448
449
  //
449
450
 
450
451
  parallel.eval = closure evalf(expr, put, get, local pending) {
451
- if maxcount == 0
452
+ if maxcount == 0 || !parallel.state {
453
+ destroy(list(Error("volatile execution terminated"))) // in case of no state
452
454
  return (crValue) // already destroyed
455
+ }
453
456
  pending = new(nonce)
454
457
  exqueue.push({
455
458
  eval: list(expr, put, get)
@@ -516,8 +519,10 @@ closure ExecutorParallel(track, options, local maxcount, parallel, exqueue, crVa
516
519
  //
517
520
 
518
521
  parallel.rpc = closure rpc(proc, args, local pending) {
519
- if maxcount == 0
522
+ if maxcount == 0 || !parallel.state {
523
+ destroy(list(Error("volatile execution terminated"))) // in case of no state
520
524
  return (crValue) // already destroyed
525
+ }
521
526
  pending = new(nonce)
522
527
  exqueue.push({
523
528
  proc: proc
@@ -539,11 +544,11 @@ closure ExecutorParallel(track, options, local maxcount, parallel, exqueue, crVa
539
544
 
540
545
  parallel.status = function status(local output, worker) {
541
546
  output = []
542
- for worker in parallel.workers {
547
+ for worker in state.workers {
543
548
  output.push({
544
549
  name: worker.name
545
550
  type: worker.type
546
- state: if parallel.available.indexOf(worker) >= 0
551
+ state: if state.available.indexOf(worker) >= 0
547
552
  "idle" else "active"
548
553
  status: worker.xstatus
549
554
  })
@@ -561,13 +566,13 @@ closure ExecutorParallel(track, options, local maxcount, parallel, exqueue, crVa
561
566
  return (false) // already destroyed
562
567
  crValue = cancelResult
563
568
  maxcount = 0
564
- parallel.available = false
565
- parallel.contexts = false
566
- while parallel.workers.length > 0 {
567
- worker = parallel.workers.pop()
569
+ while state.workers.length > 0 {
570
+ worker = state.workers.pop()
568
571
  parallel.contexts[worker] = false
569
572
  worker.destroy()
570
573
  }
574
+ state.available = false
575
+ parallel.contexts = false
571
576
  while exqueue.length > 0 {
572
577
  next = exqueue.pop()
573
578
  next.pending.signal(crValue)
@@ -584,7 +589,7 @@ closure ExecutorParallel(track, options, local maxcount, parallel, exqueue, crVa
584
589
  /*
585
590
  * ExecutorTracker
586
591
  *
587
- * Track Naan execution instances.
592
+ * Track Naan execution instances.
588
593
  *
589
594
  */
590
595
 
@@ -599,8 +604,10 @@ closure ExecutorTracker(local xtrak) {
599
604
  // Notify the watchers by calling a named procedure
600
605
 
601
606
  closure notify(changes, local watch) {
602
- for watch in xtrak.watchers
603
- call(watch, changes)
607
+ future(function(){
608
+ for watch in xtrak.watchers
609
+ call(watch, changes)
610
+ }, 10)
604
611
  }
605
612
 
606
613
  // add
@@ -667,7 +674,7 @@ closure ExecutorTracker(local xtrak) {
667
674
  // register
668
675
  // Register an executor type.
669
676
 
670
- xtrak.register = function register(maker, type) {
677
+ xtrak.register = function register(type, maker) {
671
678
  xtrak.makers[type] = maker
672
679
  }
673
680
 
@@ -690,262 +697,11 @@ closure ExecutorTracker(local xtrak) {
690
697
  ExecutorParallel(xtrak, options)
691
698
  }
692
699
 
693
- xtrak.register(execLambda, "Lambda")
694
-
695
700
  // finis
696
701
  xtrak
697
702
  };
698
703
 
699
704
 
700
- /*
701
- * execLambda
702
- *
703
- * Make a Lambda executor connected through web sockets.
704
- *
705
- */
706
-
707
- closure execLambda(track, url, name, workerID, local target, nlregex, clientID, serverID) {
708
- global(js)
709
- target = ExecutorBase(track, "Lambda", name)
710
- clientID = "DebugWorkers"
711
- serverID = "Workers"
712
- nlregex = RegExp("\\n", "g")
713
- if !workerID
714
- workerID = "myAwsDebugWorker"
715
- target.workerID = workerID
716
- target.msgQueue = []
717
-
718
- // connect
719
- // Connect with the host if not already connected.
720
- function connect() {
721
- if !target.ws
722
- target.ws = xnew(js.w.WebSocket, "wss://8h5htw8bfj.execute-api.us-east-1.amazonaws.com/dev")
723
-
724
- // onopen
725
- // The WebSocket connection is now open.
726
- target.ws.onopen = function onopen(e) {
727
- target.msgCounter = 1
728
- sendControl("spawn", {
729
- reset: true
730
- options: {
731
- }
732
- })
733
- }
734
-
735
- // onmessage
736
- // A message was received from the worker via WebSockets.
737
-
738
- target.ws.onmessage = function onmessage(e) {
739
- if target.msgQueue
740
- target.msgQueue.push(e.data)
741
- else
742
- target.doMessage(e.data)
743
- }
744
-
745
- // onerror
746
- // An error occurred on the WebSocket connection.
747
- target.ws.onerror = function onerror(e) {
748
- target.debugWrite("connection error: ".concat(e.toString()), 3)
749
- }
750
-
751
- // onclose
752
- // The WebSocket connection was closed.
753
- target.ws.onclose = function onclose(e) {
754
- target.debugWrite("connection closed: ".concat(e.code, " ", e.reason), 3)
755
- target.ws = false
756
- }
757
- }
758
-
759
- //
760
- // doOneMessage
761
- //
762
- // Process the specified undecoded message.
763
- function doOneMessage(message, local msg) {
764
- if message.respOp == "msgarray" {
765
- for msg in message.payload
766
- doOneMessage(msg)
767
- } else if message.respOp == "msgout" {
768
- msg = message.payload
769
- if msg.id == "textout" {
770
- target.written = true
771
- target.term.Write(msg.text.replace(nlregex, "\r\n")) }
772
- else if msg.id == "debugtext" {
773
- target.written = true
774
- target.debugWrite(msg.text, msg.level) }
775
- else if msg.id == "msgout"
776
- target.listener(msg.data)
777
- else if msg.id == "started"
778
- { }
779
- else if msg.id == "typed"
780
- target.term.Write(msg.text.replace(nlregex, "\r\n"))
781
- else if msg.id == "status"
782
- target.statusCB(target, msg.status)
783
- else
784
- debuglog("unknown AWS worker message:", msg.id)
785
- } else if message.respOp == "error"
786
- debuglog("worker controller error:", ErrorString(message.payload[0]))
787
- else if message.respOp == "linked"
788
- future(function termLinked(){
789
- if !target.written
790
- target.term.WriteLn("(reconnected)")
791
- }, 1000).run()
792
- else
793
- debuglog("unknown AWS response message:", message.respOp)
794
- }
795
-
796
- //
797
- // doMessage
798
- //
799
- // Process the specified undecoded message.
800
- target.doMessage = function doMessage(text, local message) {
801
- try {
802
- message = new(js.w.JSON.parse(text))
803
- if message.connectionId && string(message.message)
804
- target.debugWrite("AWS response: ".concat(message.message), 3)
805
- else if message.clientID != clientID || message.serverID != serverID || message.workerID != target.workerID
806
- debuglog("AWS response doesn't match:", message.clientID, message.serverID, message.workerID)
807
- else
808
- doOneMessage(message)
809
- } catch {
810
- if true
811
- return (debuglog("can't decode incoming ws message:", exception))
812
- }
813
- }
814
-
815
- //
816
- // sendControl
817
- //
818
- // Send a message to the worker controller.
819
-
820
- target.sendControl = function sendControl(workerOp, payload) {
821
- target.ws.send(js.w.JSON.stringify({
822
- clientID: clientID
823
- serverID: serverID
824
- workerID: target.workerID
825
- workerOp: workerOp
826
- payload: payload
827
- msgCounter: target.msgCounter++
828
- }))
829
- }
830
-
831
- //
832
- // send
833
- //
834
- // Send a message to the worker.
835
-
836
- target.send = function send(msg) {
837
- // msg.save = true // save state for this invocation
838
- sendControl("msgin", msg)
839
- }
840
-
841
- //
842
- // oninterrupt
843
- //
844
-
845
- function oninterrupt() {
846
- send({ // send interrupt to worker
847
- id: "interrupt"
848
- })
849
- }
850
-
851
- //
852
- // onreturn
853
- //
854
-
855
- function onreturn(local text) {
856
- text = target.term.TakeText()
857
- send({ // send user-entered text to worker
858
- id: "keyline",
859
- text: text,
860
- typed: "\x1b[90m\x1b[3m".concat(text, "\x1b[0m\n") // dark-grey, italic
861
- })
862
- }
863
-
864
- //
865
- // target.PostMessage
866
- //
867
- // Post a message to the target.
868
- //
869
-
870
- target.PostMessage = function PostMessage(data, local result) {
871
- result = connect()
872
- if result.0
873
- return (result)
874
- target.ws.send({ // send user-entered text to worker
875
- id: "msgin",
876
- data: data
877
- })
878
- list(false, { posted: true })
879
- }
880
-
881
- //
882
- // target.debugWrite
883
- //
884
- // Write a debug message to the repl.
885
- //
886
-
887
- target.debugWrite = function(text, level) {
888
- if (level >= 5)
889
- target.term.WriteLn(text, target.term.Cyan) // cyan for builtin logging
890
- else if (level >= 4)
891
- target.term.WriteLn(text, target.term.Blue) // blue for Naan function logging
892
- else if (level >= 3)
893
- target.term.WriteLn(text, target.term.Red) // light red for warnings
894
- else if (level >= 2)
895
- target.term.WriteLn(text, target.term.Green) // green for Naan.debug.debuglog logging
896
- else
897
- target.term.WriteLn(text, target.term.Red+target.term.Bold) // heavy red for errors
898
- }
899
-
900
- //
901
- // termAttach
902
- //
903
- // A terminal was attached to our instance.
904
-
905
- target.termAttach = function termAttach(repl, db, statusCB, local msg) {
906
- connect() // ensure we are connected
907
- target.term = repl
908
- target.debugger = db
909
- target.statusCB = statusCB
910
- if target.termSaved {
911
- target.term.StateLoad(target.termSaved)
912
- target.termSaved = false }
913
- else
914
- target.term.Reset()
915
- while target.msgQueue.length > 0 {
916
- for msg in target.msgQueue.splice(0) // all current messages
917
- target.doMessage(msg)
918
- }
919
- target.msgQueue = false
920
- target.term.On("interrupt", oninterrupt.proc)
921
- target.term.On("return", onreturn.proc)
922
- target.term.Focus()
923
- }
924
-
925
- //
926
- // termDetach
927
- //
928
- // The terminal is being deattached from our instance.
929
-
930
- target.termDetach = function termDetach(repl) {
931
- target.term.On("interrupt")
932
- target.term.On("return")
933
- target.msgQueue = []
934
- target.termSaved = target.term.StateSave()
935
- target.statusCB = false
936
- target.debugger = false
937
- target.term = false
938
- }
939
-
940
- track.add(target)
941
- connect() // connect right away to start receiving messages
942
-
943
- // finis
944
-
945
- list(false, target)
946
- };
947
-
948
-
949
705
  /*
950
706
  * execInit
951
707
  *
@@ -954,8 +710,7 @@ closure execLambda(track, url, name, workerID, local target, nlregex, clientID,
954
710
  */
955
711
 
956
712
  function execInit(local manifest) {
957
- manifest = `(ExecutorBase, ExecutorContext, ExecutorParallel, ExecutorTracker, execLambda,
958
- execInit)
713
+ manifest = `(ExecutorBase, ExecutorContext, ExecutorParallel, ExecutorTracker, execInit)
959
714
 
960
715
  Naan.module.build(module.id, "executors", function(modobj, compobj) {
961
716
  require("./running.nlg")