@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.
- package/LICENSE.md +2 -2
- package/README.md +2 -2
- package/bin/index.js +7 -3
- package/dist/env_web.js +162 -48
- package/dist/naan.min.js +11 -11
- package/frameworks/browser/https_request.nlg +2 -2
- package/frameworks/browser/sworker.js +28 -26
- package/frameworks/browser/terminals.nlg +295 -737
- package/frameworks/browser/worker.nlg +295 -0
- package/frameworks/browser/workers.nlg +6 -6
- package/frameworks/browser/ws_client.nlg +15 -10
- package/frameworks/client/apiclient.nlg +211 -9
- package/frameworks/client/psm_client.nlg +10 -14
- package/frameworks/client/relaycon.nlg +87 -161
- package/frameworks/common/common.nlg +2 -0
- package/frameworks/common/events.nlg +101 -0
- package/frameworks/common/repltools.nlg +80 -1
- package/frameworks/node/apiserver.nlg +38 -246
- package/frameworks/node/filesystem.nlg +31 -6
- package/frameworks/node/http_request.nlg +34 -13
- package/frameworks/node/https_request.nlg +8 -3
- package/frameworks/node/node.nlg +3 -0
- package/frameworks/node/pty.nlg +346 -0
- package/frameworks/node/shell.nlg +26 -3
- package/frameworks/node/worker.nlg +504 -560
- package/frameworks/node/ws_client.nlg +2 -2
- package/frameworks/project/build.nlg +56 -14
- package/frameworks/project/projects.nlg +1 -1
- package/frameworks/running/debugcom.nlg +20 -3
- package/frameworks/running/debugnub.nlg +33 -11
- package/frameworks/running/executors.nlg +40 -285
- package/frameworks/running/instances.nlg +394 -0
- package/frameworks/running/remote_req.nlg +139 -0
- package/frameworks/running/remote_res.nlg +89 -0
- package/frameworks/running/sourcecode.nlg +3 -2
- package/frameworks/running/taskexec.nlg +16 -59
- package/frameworks/service/imp.nlg +751 -0
- package/frameworks/service/model.nlg +71 -0
- package/frameworks/service/nubnode.nlg +136 -0
- package/frameworks/service/nubweb.nlg +124 -0
- package/frameworks/service/service.nlg +28 -0
- package/frameworks/storage/file_manager.nlg +3 -2
- package/lib/browser/env_web.js +169 -55
- package/lib/browser/env_webworker.js +89 -31
- package/lib/core/naanlib.js +11 -11
- package/lib/env_node.js +186 -27
- package/lib/env_nodeworker.js +82 -44
- package/lib/node_server_init.nlg +149 -0
- package/lib/node_worker.js +36 -0
- package/lib/node_worker_init.nlg +43 -0
- package/package.json +1 -1
- package/plugins/openSearch/openSearch.nlg +3 -2
- package/plugins/openSearch/os_dynamo.nlg +3 -2
- package/plugins/serviceAws/aws_cloudwatchlogs.nlg +44 -2
- package/plugins/serviceAws/aws_dynamo.nlg +144 -63
- package/plugins/serviceAws/aws_utils.nlg +6 -11
- package/plugins/serviceAws/serviceAws.nlg +3 -2
- package/plugins/serviceNexara/speechrec.nlg +10 -6
- package/test/test_01_core.nlg +2 -2
- package/test/test_02_context.nlg +32 -9
- package/test/test_03_jsinterop.nlg +3 -3
- package/test/test_07_lingo.nlg +1 -1
|
@@ -6,11 +6,16 @@
|
|
|
6
6
|
*
|
|
7
7
|
* column positioning: // // !
|
|
8
8
|
*
|
|
9
|
-
* Copyright (c) 2017-
|
|
9
|
+
* Copyright (c) 2017-2026 by Richard C. Zulch
|
|
10
10
|
*
|
|
11
11
|
*/
|
|
12
12
|
|
|
13
13
|
|
|
14
|
+
// Globals
|
|
15
|
+
|
|
16
|
+
serviceMod;;
|
|
17
|
+
|
|
18
|
+
|
|
14
19
|
/*
|
|
15
20
|
* APIServer
|
|
16
21
|
*
|
|
@@ -25,18 +30,21 @@
|
|
|
25
30
|
* basePort: <number> // starting point for search
|
|
26
31
|
* gateway: <string> // websocket gateway URL
|
|
27
32
|
* statics: [<string>, ...] // search paths for static content
|
|
33
|
+
* debug: <boolean> // verbose logging
|
|
28
34
|
* }
|
|
29
35
|
*
|
|
30
36
|
*/
|
|
31
37
|
|
|
32
38
|
closure APIServer(options, local server, chroot) {
|
|
33
|
-
global(App, JSpath, js, bodyParser, express, psmServerMod, workerMod)
|
|
39
|
+
global(App, serviceMod, JSpath, js, bodyParser, express, psmServerMod, workerMod)
|
|
34
40
|
apisLoadLibs()
|
|
35
41
|
server = new(object, this)
|
|
42
|
+
server.imp = App.imp
|
|
36
43
|
server.app = express()
|
|
37
44
|
server.guid = options.guid
|
|
38
45
|
server.notifyq = []
|
|
39
46
|
server.responseq = []
|
|
47
|
+
server.instanceID = UUID()
|
|
40
48
|
options = merge({
|
|
41
49
|
relpath: ""
|
|
42
50
|
name: "NaanServer"
|
|
@@ -94,6 +102,7 @@ closure APIServer(options, local server, chroot) {
|
|
|
94
102
|
return (result)
|
|
95
103
|
}
|
|
96
104
|
updatePort(port)
|
|
105
|
+
|
|
97
106
|
if server.guid
|
|
98
107
|
server.oururl = server.oururl.concat("?guid=", server.guid)
|
|
99
108
|
App.api = server // used remotely by client/relaycon.nlg
|
|
@@ -107,6 +116,7 @@ closure APIServer(options, local server, chroot) {
|
|
|
107
116
|
}
|
|
108
117
|
} else // default is native websocket protocols
|
|
109
118
|
server.ws = WebSocketServer(server)
|
|
119
|
+
|
|
110
120
|
WesRelay(server) // registers as subsystem
|
|
111
121
|
server.psm = psmServerMod.MakeServerPSM(server, options.name)
|
|
112
122
|
`(error, hostfs) = server.psm.conns.NodeFS.connect("Host", "NideFS", list(""))
|
|
@@ -116,7 +126,8 @@ closure APIServer(options, local server, chroot) {
|
|
|
116
126
|
return (list(error))
|
|
117
127
|
}
|
|
118
128
|
server.hostfs = hostfs
|
|
119
|
-
server.workco
|
|
129
|
+
server.Register(server.workco.serverID, server.workco)
|
|
130
|
+
|
|
120
131
|
list(false, port)
|
|
121
132
|
}
|
|
122
133
|
|
|
@@ -431,15 +442,8 @@ closure WebSocketConn(wsgate, connID, local wsconn) {
|
|
|
431
442
|
wsconn.msgin = closure msgin(message, local error) {
|
|
432
443
|
if wsgate.guid && message.guid != wsgate.guid
|
|
433
444
|
error = Error("unauthorized")
|
|
434
|
-
else if message.init
|
|
435
|
-
if message.init.destID {
|
|
436
|
-
wsconn.relay = true
|
|
437
|
-
wsgate.subsystems.Relay.wsChangeDestID(conn, wsconn.info.destID, message.init.destID)
|
|
438
|
-
}
|
|
445
|
+
else if message.init
|
|
439
446
|
wsconn.info = merge(wsconn.info, message.init)
|
|
440
|
-
}
|
|
441
|
-
else if message.respOp && wsgate.subsystems.Relay
|
|
442
|
-
wsgate.subsystems.Relay.wsReceive(message, wsconn) // with respOp, must be a relay
|
|
443
447
|
else if message.clientID && wsgate.subsystems[message.serverID]
|
|
444
448
|
wsgate.subsystems[message.serverID].wsReceive(message, wsconn)
|
|
445
449
|
else
|
|
@@ -510,11 +514,11 @@ closure WebSocketServer(server, local websocks) {
|
|
|
510
514
|
websocks.subsystems[serverID].wsOpen(conn) // notify of our openings
|
|
511
515
|
})
|
|
512
516
|
|
|
513
|
-
|
|
517
|
+
websocks.wss.on("error", function(error) {
|
|
514
518
|
ErrorDebuglog(Error("WebSocketServer: connection error", error))
|
|
515
519
|
})
|
|
516
520
|
|
|
517
|
-
|
|
521
|
+
websocks.wss.on("close", function() {
|
|
518
522
|
debuglog("WebSocketServer has closed")
|
|
519
523
|
websocks.closed = true // note that we are closed
|
|
520
524
|
})
|
|
@@ -557,37 +561,31 @@ closure WesCon(server, websocks, socket, request, local wescon) {
|
|
|
557
561
|
destID: UUID()
|
|
558
562
|
address: new(socket._socket.address())
|
|
559
563
|
}
|
|
564
|
+
|
|
565
|
+
wescon.impconn = server.imp.responder(function(data) {
|
|
566
|
+
if wescon.closed
|
|
567
|
+
return
|
|
568
|
+
socket.send(JSONstringify(data)),
|
|
569
|
+
list(false, { sent: true })
|
|
570
|
+
}, {
|
|
571
|
+
secret: server.guid
|
|
572
|
+
label: "api-client"
|
|
573
|
+
})
|
|
560
574
|
|
|
561
575
|
// on message
|
|
562
576
|
//
|
|
563
577
|
// Incoming data.
|
|
564
578
|
//
|
|
565
|
-
socket.on("message", closure
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
if message.init.destID {
|
|
572
|
-
wescon.relay = true
|
|
573
|
-
websocks.subsystems.Relay.wsChangeDestID(wescon, wescon.info.destID, message.init.destID)
|
|
574
|
-
}
|
|
575
|
-
wescon.info = merge(wescon.info, message.init)
|
|
576
|
-
}
|
|
577
|
-
else if message.respOp && websocks.subsystems.Relay
|
|
578
|
-
websocks.subsystems.Relay.wsReceive(message, wescon) // with respOp, must be a relay
|
|
579
|
-
else if message.clientID && websocks.subsystems[message.serverID]
|
|
580
|
-
websocks.subsystems[message.serverID].wsReceive(message, wescon)
|
|
581
|
-
else
|
|
582
|
-
error = Error("can't route message")
|
|
583
|
-
} catch {
|
|
584
|
-
if true
|
|
585
|
-
error = Error("can't decode message JSON", exception)
|
|
579
|
+
socket.on("message", closure(text, local error, message) {
|
|
580
|
+
`(error, message) = JsonParse(text)
|
|
581
|
+
if !error {
|
|
582
|
+
message = new(message)
|
|
583
|
+
if wescon.impconn.dispatch(message)
|
|
584
|
+
return
|
|
586
585
|
}
|
|
587
|
-
|
|
588
|
-
socket.send(JSONstringify([error]))
|
|
586
|
+
debuglog("socket message:", text)
|
|
589
587
|
})
|
|
590
|
-
|
|
588
|
+
|
|
591
589
|
// on error
|
|
592
590
|
//
|
|
593
591
|
// Error has occurred on this connection.
|
|
@@ -607,222 +605,15 @@ closure WesCon(server, websocks, socket, request, local wescon) {
|
|
|
607
605
|
code: code
|
|
608
606
|
reason: reason
|
|
609
607
|
}
|
|
608
|
+
wescon.impconn.destroy()
|
|
610
609
|
websocks.closeConn(wescon)
|
|
611
610
|
})
|
|
612
|
-
|
|
613
|
-
// send
|
|
614
|
-
//
|
|
615
|
-
// Send a dictionary, which must have a clientID defined.
|
|
616
|
-
//
|
|
617
|
-
wescon.send = function send(message) {
|
|
618
|
-
if !message.clientID || !message.serverID
|
|
619
|
-
throw("Wescon.send: client and server IDs required")
|
|
620
|
-
if wescon.closed
|
|
621
|
-
list(Error("Socket connection closed", wescon.closed))
|
|
622
|
-
socket.send(JSONstringify(message)),
|
|
623
|
-
[false, {ok: true}]
|
|
624
|
-
}
|
|
625
611
|
|
|
626
612
|
// finis
|
|
627
613
|
wescon
|
|
628
614
|
};
|
|
629
615
|
|
|
630
616
|
|
|
631
|
-
/*
|
|
632
|
-
* WesRelay
|
|
633
|
-
*
|
|
634
|
-
* Web socket relay controller. This allows apiserver clients to discover each other and connect
|
|
635
|
-
* for remote evaluation, etc. A source connection makes a request of a destination connection, and
|
|
636
|
-
* the response is routed back to the original connection.
|
|
637
|
-
*
|
|
638
|
-
* This uses the following message fields for the requesting source:
|
|
639
|
-
* guid: security token
|
|
640
|
-
* clientID: defined by the source, this string defines where replies should be sent
|
|
641
|
-
* serverID: "Relay"
|
|
642
|
-
* destID: the destination connection
|
|
643
|
-
* endServerID: the serverID to use at the destination
|
|
644
|
-
* The message is modified with a virtual clientID to send to the destination, and then changed back
|
|
645
|
-
* for return to the requester.
|
|
646
|
-
*
|
|
647
|
-
* To discover the available destination connections a source should use:
|
|
648
|
-
* clientID: requester
|
|
649
|
-
* serverID: "Relay"
|
|
650
|
-
* relayOp: "getdests"
|
|
651
|
-
* which returns:
|
|
652
|
-
* relayOp: "destlist"
|
|
653
|
-
* destinations: [
|
|
654
|
-
* destID: guid for the connection
|
|
655
|
-
* address: socket port / family / ip address
|
|
656
|
-
* name: <string>
|
|
657
|
-
* workerID: id of destination worker
|
|
658
|
-
* ]
|
|
659
|
-
* New and closed destinations are sent asynchronously to each source:
|
|
660
|
-
* relayOp: "opened" / "closed"
|
|
661
|
-
* info: {
|
|
662
|
-
* destID: guid for the connection
|
|
663
|
-
* address: socket port / family / ip address
|
|
664
|
-
* name: <string>
|
|
665
|
-
* workerID: id of destination worker
|
|
666
|
-
* }
|
|
667
|
-
*
|
|
668
|
-
*/
|
|
669
|
-
|
|
670
|
-
closure WesRelay(server, local welay) {
|
|
671
|
-
global()
|
|
672
|
-
welay = new(object, this)
|
|
673
|
-
welay.serverID = "Relay" // our serverID as a subsystem
|
|
674
|
-
welay.destIDs = { } // destination conns index
|
|
675
|
-
welay.virtualIDs = { } // virtual clientID index
|
|
676
|
-
welay.links = new(weakmap) // source and dest connections
|
|
677
|
-
server.Register(welay.serverID, welay)
|
|
678
|
-
|
|
679
|
-
// getVirtualID
|
|
680
|
-
// Return the virtual clientID for a requesting source/clientID and destination.
|
|
681
|
-
function getVirtualID(sconn, clientID, dconn, local sdict, ddict, vid) {
|
|
682
|
-
sdict = welay.links[sconn]
|
|
683
|
-
if !sdict
|
|
684
|
-
welay.links[sconn] = sdict = {
|
|
685
|
-
virtualIDs: { }
|
|
686
|
-
}
|
|
687
|
-
ddict = welay.links[dconn]
|
|
688
|
-
if !ddict
|
|
689
|
-
welay.links[dconn] = ddict = {
|
|
690
|
-
virtualIDs: { }
|
|
691
|
-
}
|
|
692
|
-
vid = ddict.virtualIDs[clientID]
|
|
693
|
-
if !vid {
|
|
694
|
-
sdict.virtualIDs[clientID] = vid = UUID()
|
|
695
|
-
welay.virtualIDs[vid] = {
|
|
696
|
-
sconn: sconn
|
|
697
|
-
dconn: dconn
|
|
698
|
-
clientID: clientID
|
|
699
|
-
}
|
|
700
|
-
}
|
|
701
|
-
vid
|
|
702
|
-
}
|
|
703
|
-
|
|
704
|
-
// addConnection
|
|
705
|
-
// Record a new connection as a possible destination.
|
|
706
|
-
function addConnection(conn) {
|
|
707
|
-
welay.destIDs[conn.info.destID] = conn
|
|
708
|
-
}
|
|
709
|
-
|
|
710
|
-
// removeConnection
|
|
711
|
-
// Cleanup for a closed connection, be it source or destination or both.
|
|
712
|
-
function removeConnection(conn, local vid, cdict, did, dconn) {
|
|
713
|
-
welay.links[conn] = undefined
|
|
714
|
-
for `(vid, cdict) in welay.virtualIDs
|
|
715
|
-
if cdict.sconn === conn || cdict.dconn === conn
|
|
716
|
-
welay.virtualIDs[vid] = undefined
|
|
717
|
-
for `(did, dconn) in welay.destIDs
|
|
718
|
-
if dconn === conn
|
|
719
|
-
welay.destIDs[did] = undefined
|
|
720
|
-
}
|
|
721
|
-
|
|
722
|
-
// destList
|
|
723
|
-
// Make an array of destination connections, excluding the specified one.
|
|
724
|
-
//
|
|
725
|
-
welay.destList = function destList(conn, local output, did, dconn) {
|
|
726
|
-
output = []
|
|
727
|
-
for `(did, dconn) in welay.destIDs
|
|
728
|
-
if dconn !== conn && dconn.relay
|
|
729
|
-
output.push(dconn.info)
|
|
730
|
-
output
|
|
731
|
-
}
|
|
732
|
-
|
|
733
|
-
// wsReceive
|
|
734
|
-
//
|
|
735
|
-
// Process a message from the websocket API.
|
|
736
|
-
//
|
|
737
|
-
welay.wsReceive = function wsReceive(message, sconn, local dconn, error, cdict) {
|
|
738
|
-
if message.relayOp == "getdests" { // get destination list
|
|
739
|
-
message.relayOp = "destlist"
|
|
740
|
-
message.destinations = destList(sconn)
|
|
741
|
-
sconn.send(message)
|
|
742
|
-
return
|
|
743
|
-
}
|
|
744
|
-
else if message.destID && message.endServerID { // request from a source
|
|
745
|
-
dconn = welay.destIDs[message.destID]
|
|
746
|
-
if !dconn
|
|
747
|
-
error = Error("destID or endServerID invalid", message.relayOp)
|
|
748
|
-
else {
|
|
749
|
-
message.serverID = message.endServerID
|
|
750
|
-
message.clientID = getVirtualID(sconn, message.clientID, dconn)
|
|
751
|
-
message.endServerID = undefined
|
|
752
|
-
message.destID = undefined
|
|
753
|
-
dconn.send(message)
|
|
754
|
-
return
|
|
755
|
-
}
|
|
756
|
-
}
|
|
757
|
-
else { // response from a destination
|
|
758
|
-
cdict = welay.virtualIDs[message.clientID]
|
|
759
|
-
dconn = cdict.sconn // this is original source
|
|
760
|
-
if !cdict || !dconn
|
|
761
|
-
error = Error("cannot route reply", message.relayOp)
|
|
762
|
-
else {
|
|
763
|
-
message.endServerID = message.serverID
|
|
764
|
-
message.serverID = welay.serverID
|
|
765
|
-
message.clientID = cdict.clientID
|
|
766
|
-
message.destID = dconn.info.destID
|
|
767
|
-
dconn.send(message)
|
|
768
|
-
return
|
|
769
|
-
}
|
|
770
|
-
}
|
|
771
|
-
sconn.send({
|
|
772
|
-
serverID: message.serverID
|
|
773
|
-
clientID: message.clientID
|
|
774
|
-
respOp: "error"
|
|
775
|
-
payload: [error]
|
|
776
|
-
})
|
|
777
|
-
}
|
|
778
|
-
|
|
779
|
-
// wsOpen
|
|
780
|
-
//
|
|
781
|
-
// Note that a new connection was opened.
|
|
782
|
-
//
|
|
783
|
-
welay.wsOpen = function wsOpen(conn) {
|
|
784
|
-
addConnection(conn)
|
|
785
|
-
}
|
|
786
|
-
|
|
787
|
-
// wsClose
|
|
788
|
-
//
|
|
789
|
-
// Note that an existing connection was closed.
|
|
790
|
-
//
|
|
791
|
-
welay.wsClose = function wsClose(conn, local destID, sconn) {
|
|
792
|
-
removeConnection(conn)
|
|
793
|
-
if conn.relay
|
|
794
|
-
for `(destID, sconn) in welay.destIDs
|
|
795
|
-
sconn.send({
|
|
796
|
-
serverID: welay.serverID
|
|
797
|
-
clientID: "*"
|
|
798
|
-
relayOp: "closed"
|
|
799
|
-
info: conn.info
|
|
800
|
-
})
|
|
801
|
-
}
|
|
802
|
-
|
|
803
|
-
// wsChangeDestID
|
|
804
|
-
//
|
|
805
|
-
// The destID has changed (via the client init message.)
|
|
806
|
-
//
|
|
807
|
-
welay.wsChangeDestID = function wsChangeDestID(conn, prevID, newID, local destID, sconn) {
|
|
808
|
-
welay.destIDs[prevID] = undefined
|
|
809
|
-
welay.destIDs[newID] = conn
|
|
810
|
-
conn.info.destID = newID
|
|
811
|
-
for `(destID, sconn) in welay.destIDs
|
|
812
|
-
if destID != newID
|
|
813
|
-
sconn.send({
|
|
814
|
-
serverID: welay.serverID
|
|
815
|
-
clientID: "*"
|
|
816
|
-
relayOp: "opened"
|
|
817
|
-
info: conn.info
|
|
818
|
-
})
|
|
819
|
-
}
|
|
820
|
-
|
|
821
|
-
// finis
|
|
822
|
-
welay
|
|
823
|
-
};
|
|
824
|
-
|
|
825
|
-
|
|
826
617
|
/*
|
|
827
618
|
* ApisInit
|
|
828
619
|
*
|
|
@@ -840,7 +631,7 @@ function apisLoadLibs() {
|
|
|
840
631
|
};
|
|
841
632
|
|
|
842
633
|
function ApisInit(local manifest) {
|
|
843
|
-
manifest = `(APIServer, WebSocketGatewayServer, WebSocketConn, WebSocketServer, WesCon,
|
|
634
|
+
manifest = `(APIServer, WebSocketGatewayServer, WebSocketConn, WebSocketServer, WesCon,
|
|
844
635
|
apisLoadLibs, ApisInit)
|
|
845
636
|
|
|
846
637
|
Naan.module.build(module.id, "apiserver", function(modobj, compobj) {
|
|
@@ -851,4 +642,5 @@ function ApisInit(local manifest) {
|
|
|
851
642
|
require("./filesystem.nlg")
|
|
852
643
|
psmServerMod = require("./psm_server.nlg")
|
|
853
644
|
workerMod = require("./worker.nlg")
|
|
645
|
+
serviceMod = require("naanlib:frameworks/service/imp.nlg")
|
|
854
646
|
}();
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
*
|
|
7
7
|
* column positioning: // // !
|
|
8
8
|
*
|
|
9
|
-
* Copyright (c) 2017-
|
|
9
|
+
* Copyright (c) 2017-2026 by Richard C. Zulch
|
|
10
10
|
*
|
|
11
11
|
*/
|
|
12
12
|
|
|
@@ -977,16 +977,41 @@ closure Filesystem(rootpath, local files, badCreatePathRegEx) {
|
|
|
977
977
|
//
|
|
978
978
|
// shellOpen
|
|
979
979
|
//
|
|
980
|
-
// Execute the
|
|
980
|
+
// Execute the platform's open utility, returning a standard tuple: `(error, result) which opens
|
|
981
|
+
// the specified path as a browser URL or invokes a shell script. This is used by the NaaN build
|
|
982
|
+
// system's "run" function.
|
|
983
|
+
// The args option has a dictionary that can override the "runner" utility and set arguments
|
|
984
|
+
// for specific platform(s):
|
|
985
|
+
// {
|
|
986
|
+
// darwin: {
|
|
987
|
+
// runner: "open" // default for platforms not mentioned
|
|
988
|
+
// // args: ["--args", <prog arg>] // program arguments if desired
|
|
989
|
+
// }
|
|
990
|
+
// linux / android: {
|
|
991
|
+
// runner: "bash" // for <path>.sh or <path>.tool
|
|
992
|
+
// runner: "xdg-open" // all other types
|
|
993
|
+
// }
|
|
994
|
+
// }
|
|
981
995
|
//
|
|
982
|
-
files.shellOpen = closure shellOpen(path, args, callback) {
|
|
996
|
+
files.shellOpen = closure shellOpen(path, args, callback, local platform, runner) {
|
|
983
997
|
if !callback
|
|
984
998
|
return (syncAdapter(shellOpen, path, args))
|
|
985
|
-
|
|
986
|
-
|
|
999
|
+
platform = js.g.process.platform
|
|
1000
|
+
runner = args[platform].runner
|
|
1001
|
+
if runner
|
|
1002
|
+
{ } // explicit runner
|
|
1003
|
+
else if platform == "linux" || platform == "android" {
|
|
1004
|
+
if RegExp("[.]((sh)|(tool))$").test(path)
|
|
1005
|
+
runner = "bash" // execute scripts
|
|
1006
|
+
else
|
|
1007
|
+
runner = "xdg-open" // "open" other things
|
|
1008
|
+
} else
|
|
1009
|
+
runner = "open" // default runner
|
|
1010
|
+
if args[platform]
|
|
1011
|
+
args = [path].concat(args[platform]) // has custom args
|
|
987
1012
|
else
|
|
988
1013
|
args = [path]
|
|
989
|
-
nodecp.execFile(
|
|
1014
|
+
nodecp.execFile(runner,
|
|
990
1015
|
args, // command line args to open
|
|
991
1016
|
{ }, // execution options
|
|
992
1017
|
function(err, stdout, stderr) {
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
*
|
|
6
6
|
* column positioning: // // !
|
|
7
7
|
*
|
|
8
|
-
* Copyright (c) 2024-
|
|
8
|
+
* Copyright (c) 2024-2026 by Richard C. Zulch
|
|
9
9
|
*
|
|
10
10
|
*/
|
|
11
11
|
|
|
@@ -19,8 +19,9 @@
|
|
|
19
19
|
* {
|
|
20
20
|
* method: <string> // HTTP method (defaults to GET)
|
|
21
21
|
* headers: <dictionary> // key/data pairs
|
|
22
|
-
* putdata: <data> // data to put
|
|
22
|
+
* putdata: <data> // data to put, either string or JSON
|
|
23
23
|
* json: <boolean> // ignore content-type of return and decode JSON
|
|
24
|
+
* debug: <boolean> // log errors and status results
|
|
24
25
|
* }
|
|
25
26
|
*
|
|
26
27
|
* The return is a result tuple comprising:
|
|
@@ -34,13 +35,31 @@
|
|
|
34
35
|
*/
|
|
35
36
|
|
|
36
37
|
closure HttpRequest(url, options,
|
|
37
|
-
local pending, chunks, params, request) {
|
|
38
|
+
local host, pending, chunks, params, request, headers, putdata) {
|
|
38
39
|
global(js, nodeHttp)
|
|
40
|
+
try {
|
|
41
|
+
host = xnew(js.g.URL, url).host
|
|
42
|
+
if host.length < 3
|
|
43
|
+
return (Error("httpRequest: host empty"))
|
|
44
|
+
} catch {
|
|
45
|
+
return (Error("httpRequest:", exception))
|
|
46
|
+
}
|
|
39
47
|
pending = new(nonce)
|
|
40
48
|
chunks = []
|
|
49
|
+
headers = new(options.headers || []) // modifiable copy or false
|
|
50
|
+
headers.push(list("Host", host))
|
|
51
|
+
putdata = options.putdata
|
|
52
|
+
if putdata {
|
|
53
|
+
if !string(putdata) {
|
|
54
|
+
putdata = JSONstringify(putdata)
|
|
55
|
+
headers.push(list('Content-Type', 'application/json'))
|
|
56
|
+
}
|
|
57
|
+
// set explicit content-length to avoid default chunked encoding
|
|
58
|
+
headers.push(list('Content-Length', putdata.length))
|
|
59
|
+
}
|
|
41
60
|
params = {
|
|
42
61
|
method: options.method || undefined
|
|
43
|
-
headers:
|
|
62
|
+
headers: headers || undefined
|
|
44
63
|
}
|
|
45
64
|
request = nodeHttp.request(url, params, closure (response) {
|
|
46
65
|
response.on("data", function (chunk) {
|
|
@@ -49,7 +68,12 @@ closure HttpRequest(url, options,
|
|
|
49
68
|
response.on("end", function (local content, error) {
|
|
50
69
|
content = js.g.Buffer.concat(chunks)
|
|
51
70
|
if response.statusCode < 200 || response.statusCode >= 299 { // 299 is "cancelled"
|
|
52
|
-
|
|
71
|
+
if options.debug {
|
|
72
|
+
debuglog("httpRequest status:", url, response.statusCode, "message:", response.statusMessage)
|
|
73
|
+
if string(putdata)
|
|
74
|
+
putdata = putdata.substr(0,250)
|
|
75
|
+
debuglog("httpRequest putdata:", putdata)
|
|
76
|
+
}
|
|
53
77
|
pending.signal(list(Error("httpRequest statusCode:", url, response.statusCode, {
|
|
54
78
|
status: response.statusCode
|
|
55
79
|
}), false, { status: response.statusCode }))
|
|
@@ -63,23 +87,20 @@ closure HttpRequest(url, options,
|
|
|
63
87
|
else
|
|
64
88
|
error = Error("httpRequest terminated prematurely:", url, response.statusCode)
|
|
65
89
|
pending.signal(list(error, content, {
|
|
66
|
-
headers: response.headers
|
|
90
|
+
headers: new(response.headers)
|
|
67
91
|
status: response.statusCode
|
|
68
92
|
contentType: response.headers["content-type"]
|
|
69
93
|
}))
|
|
70
94
|
})
|
|
71
95
|
})
|
|
72
96
|
request.on("error", function hre(error) {
|
|
73
|
-
|
|
97
|
+
if options.debug
|
|
98
|
+
debuglog("httpRequest error:", url, "error:", error)
|
|
74
99
|
error = Error("httpRequest failed:", url, error)
|
|
75
100
|
pending.signal(list(error))
|
|
76
101
|
})
|
|
77
|
-
if
|
|
78
|
-
|
|
79
|
-
request.write(options.putdata)
|
|
80
|
-
else
|
|
81
|
-
request.write(JSONstringify(options.putdata))
|
|
82
|
-
}
|
|
102
|
+
if putdata
|
|
103
|
+
request.write(putdata)
|
|
83
104
|
request.end()
|
|
84
105
|
pending.wait()
|
|
85
106
|
};
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
*
|
|
6
6
|
* column positioning: // // !
|
|
7
7
|
*
|
|
8
|
-
* Copyright (c) 2021-
|
|
8
|
+
* Copyright (c) 2021-2026 by Richard C. Zulch
|
|
9
9
|
*
|
|
10
10
|
*/
|
|
11
11
|
|
|
@@ -123,12 +123,17 @@ closure httpsApiReqOnce(url, options,
|
|
|
123
123
|
else
|
|
124
124
|
content = js.g.Buffer.concat(chunks)
|
|
125
125
|
if response.statusCode < 200 || response.statusCode >= 299 { // 299 is "cancelled"
|
|
126
|
-
if options.debug
|
|
126
|
+
if options.debug {
|
|
127
|
+
content = content.toString()
|
|
127
128
|
debuglog("HttpsApiRequest status:", url, response.statusCode, "message:", content)
|
|
129
|
+
if string(putdata)
|
|
130
|
+
putdata = putdata.substr(0,250)
|
|
131
|
+
debuglog("HttpsApiRequest putdata:", putdata)
|
|
132
|
+
}
|
|
128
133
|
pending.signal(list(Error("HttpsApiRequest statusCode:", url, response.statusCode, {
|
|
129
134
|
status: response.statusCode
|
|
130
135
|
}), false, {
|
|
131
|
-
headers: response.headers
|
|
136
|
+
headers: new(response.headers)
|
|
132
137
|
status: response.statusCode
|
|
133
138
|
}))
|
|
134
139
|
return
|
package/frameworks/node/node.nlg
CHANGED
|
@@ -124,6 +124,8 @@ function nodrInit(local manifest) {
|
|
|
124
124
|
throw("module frameworks/node cannot be used from a browser")
|
|
125
125
|
Naan.module.build(module.id, "node", function(modobj, compobj) {
|
|
126
126
|
require("../common/").LiveImport()
|
|
127
|
+
require("../common/events.nlg")
|
|
128
|
+
commonWatching = require("../common/watching.nlg")
|
|
127
129
|
compobj.manifest = manifest
|
|
128
130
|
function nodrReload() {
|
|
129
131
|
nodecp = js.r("child_process")
|
|
@@ -139,5 +141,6 @@ function nodrInit(local manifest) {
|
|
|
139
141
|
module.reload = nodrReload
|
|
140
142
|
module.exports.NaanlangDir = NaanlangDir
|
|
141
143
|
module.exports.NaanlangRC = NaanlangRC
|
|
144
|
+
module.exports.NodeStreamLiner = NodeStreamLiner
|
|
142
145
|
})
|
|
143
146
|
} ();
|