@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,711 +6,656 @@
|
|
|
6
6
|
*
|
|
7
7
|
* column positioning: // // !
|
|
8
8
|
*
|
|
9
|
-
* Copyright (c) 2019-
|
|
9
|
+
* Copyright (c) 2019-2026 by Richard C. Zulch
|
|
10
10
|
*
|
|
11
11
|
*/
|
|
12
12
|
|
|
13
|
-
/*
|
|
14
|
-
* globals
|
|
15
|
-
*
|
|
16
|
-
*/
|
|
17
|
-
|
|
18
|
-
gWorkers;
|
|
19
|
-
|
|
20
13
|
|
|
21
14
|
/*
|
|
22
|
-
*
|
|
15
|
+
* CurBot
|
|
23
16
|
*
|
|
24
|
-
*
|
|
17
|
+
* Attach a remote terminal interface to the current NodeJS thread.
|
|
18
|
+
*
|
|
19
|
+
* Options:
|
|
20
|
+
* {
|
|
21
|
+
* name: <string> // target name, e.g. "Play"
|
|
22
|
+
* type: <string> // target category, e.g. "Local"
|
|
23
|
+
* }
|
|
25
24
|
*
|
|
26
25
|
*/
|
|
27
26
|
|
|
28
|
-
closure
|
|
29
|
-
global(js)
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
27
|
+
closure CurBot(options, local curbot) {
|
|
28
|
+
global(App, js)
|
|
29
|
+
curbot = new(object, this)
|
|
30
|
+
curbot.topsubs = []
|
|
31
|
+
options = merge({
|
|
32
|
+
type: "Host"
|
|
33
|
+
}, options)
|
|
34
|
+
curbot.type = options.type
|
|
35
|
+
curbot.name = options.name
|
|
36
|
+
|
|
37
|
+
curbot.termif = xnew({
|
|
35
38
|
textout: ONtextOut.proc
|
|
36
39
|
debugtext: ONdebugText.proc
|
|
37
40
|
status: ONstatus.proc
|
|
38
41
|
debugout: ONdebugOut.proc
|
|
39
|
-
|
|
42
|
+
ioctl: ONioctl.proc
|
|
40
43
|
})
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
44
|
+
curbot.guid = 1
|
|
45
|
+
curbot.host = js.t // our magic Naan controller reference
|
|
46
|
+
|
|
47
|
+
curbot.instanceID = UUID()
|
|
48
|
+
curbot.sender = App.imp.register(curbot, {
|
|
49
|
+
name: curbot.name
|
|
50
|
+
type: curbot.type
|
|
51
|
+
instanceID: curbot.instanceID
|
|
52
|
+
services: ["naanide-server-main"]
|
|
53
|
+
})
|
|
54
|
+
|
|
55
|
+
// subscribe
|
|
45
56
|
//
|
|
46
|
-
//
|
|
57
|
+
// Add an InTop to our subscribers if not already known.
|
|
47
58
|
//
|
|
48
|
-
function
|
|
49
|
-
if
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
59
|
+
function subscribe(destID) {
|
|
60
|
+
if !curbot.topsubs.find(function(item) { item == destID }) {
|
|
61
|
+
curbot.topsubs.push(destID)
|
|
62
|
+
curbot.sender(destID, {
|
|
63
|
+
id: "workerDestID"
|
|
64
|
+
workerDestID: App.imp.us.instanceID // our remote responder
|
|
53
65
|
})
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// unsubscribe
|
|
70
|
+
//
|
|
71
|
+
// Remove an InTop from our subscribers if present.
|
|
72
|
+
//
|
|
73
|
+
function unsubscribe(destID) {
|
|
74
|
+
curbot.topsubs = curbot.topsubs.filter(function(item) { item != destID })
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// notifyAll
|
|
78
|
+
//
|
|
79
|
+
// Send the message to all our subscribers.
|
|
80
|
+
//
|
|
81
|
+
curbot.notifyAll = function notifyAll(message, exceptID, local topDestID) {
|
|
82
|
+
for topDestID in curbot.topsubs
|
|
83
|
+
if topDestID != exceptID
|
|
84
|
+
curbot.sender(topDestID, message)
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// textEntry
|
|
88
|
+
//
|
|
89
|
+
// Simulate text entry for subprocess support.
|
|
90
|
+
//
|
|
91
|
+
curbot.textEntry = function textEntry(text) {
|
|
92
|
+
curbot.host.DispatchMessage({
|
|
93
|
+
id: "keyline"
|
|
94
|
+
text: text
|
|
95
|
+
})
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
// rawStart
|
|
99
|
+
//
|
|
100
|
+
// Configure ioctls for raw terminal operation using the spawned PTY process.
|
|
101
|
+
//
|
|
102
|
+
curbot.rawStart = closure rawStart(ptySpawned, local dokey, doresize, doattach) {
|
|
103
|
+
dokey = xnew(function(msg, arg) { ptySpawned.write(arg.key) })
|
|
104
|
+
js.t.ioctl_add_listener("raw-key", dokey)
|
|
105
|
+
doresize = xnew(function(msg, dim) { ptySpawned.resize(dim.cols, dim.rows) })
|
|
106
|
+
js.t.ioctl_add_listener("term-resize", doresize)
|
|
107
|
+
js.t.ioctl("raw", true)
|
|
108
|
+
doattach = xnew(function(msg, arg) { js.t.ioctl("raw", true) }) // restore raw mode when we are attached
|
|
109
|
+
js.t.ioctl_add_listener("term-attach", doattach)
|
|
110
|
+
|
|
111
|
+
curbot.rawStop = function rawStop() {
|
|
112
|
+
js.t.ioctl("raw")
|
|
113
|
+
js.t.ioctl_remove_listener("raw-key", dokey)
|
|
114
|
+
js.t.ioctl_remove_listener("term-resize", doresize)
|
|
115
|
+
js.t.ioctl_remove_listener("term-attach", doattach)
|
|
116
|
+
dokey = doresize = doattach = false
|
|
117
|
+
curbot.rawStop = undefined
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
// impReceive
|
|
122
|
+
//
|
|
123
|
+
// Received a payload.
|
|
124
|
+
//
|
|
125
|
+
curbot.impReceive = function impReceive(message, sourceID) {
|
|
126
|
+
// js.g.console.log("CurBot.impReceive(${sourceID}):\n", Dialect.print(new(message)))
|
|
127
|
+
if message.id == "destroy"
|
|
128
|
+
{ }
|
|
129
|
+
else if message.id == "subscribe"
|
|
130
|
+
subscribe(sourceID)
|
|
131
|
+
else if message.id == "unsubscribe"
|
|
132
|
+
unsubscribe(sourceID)
|
|
133
|
+
else {
|
|
134
|
+
subscribe(sourceID) // auto-subscribe
|
|
135
|
+
if message.id == "typed"
|
|
136
|
+
notifyAll(message, sourceID)
|
|
137
|
+
else if message.id == "keyline" && curbot.keyin
|
|
138
|
+
curbot.keyin(message.text) // terminal keyboard -> pty subprocess
|
|
139
|
+
else
|
|
140
|
+
curbot.host.DispatchMessage(message)
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
// impUnknown
|
|
145
|
+
//
|
|
146
|
+
// Received an unknown destination notice.
|
|
147
|
+
//
|
|
148
|
+
curbot.impUnknown = function impUnknown(unknownID, sourceID, gateway) {
|
|
149
|
+
if curbot.topsubs.indexOf(unknownID) >= 0 { // did not have courtesy to unsubscribe!
|
|
150
|
+
unsubscribe(unknownID)
|
|
151
|
+
return
|
|
152
|
+
}
|
|
153
|
+
if !gateway
|
|
154
|
+
debuglog("CurBot.impUnknownID:", unknownID, "sourceID:", sourceID)
|
|
54
155
|
}
|
|
55
|
-
current.host.OnReplyHook(replyHook.proc)
|
|
56
156
|
|
|
57
157
|
// ONtextOut
|
|
158
|
+
//
|
|
58
159
|
// Process console text output by Naan.
|
|
59
|
-
|
|
160
|
+
//
|
|
60
161
|
function ONtextOut(text) {
|
|
61
|
-
|
|
162
|
+
if curbot.naanin {
|
|
163
|
+
curbot.naanin(text) // naan output -> pty subprocess
|
|
164
|
+
return
|
|
165
|
+
}
|
|
166
|
+
notifyAll({
|
|
62
167
|
id: "textout",
|
|
63
168
|
text: text,
|
|
64
169
|
})
|
|
65
170
|
}
|
|
66
|
-
|
|
171
|
+
|
|
67
172
|
// ONdebugText
|
|
173
|
+
//
|
|
68
174
|
// Process console debug text output by Naan.
|
|
69
|
-
|
|
175
|
+
//
|
|
70
176
|
function ONdebugText(text, level) {
|
|
71
|
-
|
|
177
|
+
notifyAll({
|
|
72
178
|
id: "debugtext",
|
|
73
179
|
text: text,
|
|
74
180
|
level: level
|
|
75
181
|
})
|
|
76
182
|
}
|
|
77
|
-
|
|
183
|
+
|
|
78
184
|
// ONstatus
|
|
185
|
+
//
|
|
79
186
|
// Process status update output by Naan.
|
|
80
|
-
|
|
187
|
+
//
|
|
81
188
|
function ONstatus(status) {
|
|
82
|
-
|
|
189
|
+
notifyAll({
|
|
83
190
|
id: "status",
|
|
84
191
|
status: status
|
|
85
192
|
})
|
|
86
193
|
}
|
|
87
|
-
|
|
194
|
+
|
|
88
195
|
// ONdebugOut
|
|
196
|
+
//
|
|
89
197
|
// Process debugger output.
|
|
90
|
-
|
|
198
|
+
//
|
|
91
199
|
function ONdebugOut(data) {
|
|
92
|
-
|
|
200
|
+
notifyAll({
|
|
93
201
|
id: "debugout",
|
|
94
202
|
data: data
|
|
95
203
|
})
|
|
96
204
|
}
|
|
97
|
-
|
|
98
|
-
// ONmessageOut
|
|
99
|
-
// Process message output.
|
|
100
|
-
|
|
101
|
-
function ONmessageOut(data) {
|
|
102
|
-
if data._guid
|
|
103
|
-
return // already replied
|
|
104
|
-
current.execReceived(data)
|
|
105
|
-
sendAll({
|
|
106
|
-
id: "targetout",
|
|
107
|
-
data: data
|
|
108
|
-
})
|
|
109
|
-
}
|
|
110
205
|
|
|
111
|
-
//
|
|
112
|
-
// Remove a link.
|
|
113
|
-
|
|
114
|
-
function removeLink(link) {
|
|
115
|
-
current.links = current.links.filter(function(item) {
|
|
116
|
-
!(item.link eq link)
|
|
117
|
-
})
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
// exitNotify
|
|
121
|
-
// Notify all links that we have terminated.
|
|
122
|
-
|
|
123
|
-
function exitNotify(exitCode, local link) {
|
|
124
|
-
workco.uworkers[current.guid] = undefined
|
|
125
|
-
for link in current.links
|
|
126
|
-
link.exitWorker(exitCode)
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
// sendAll
|
|
130
|
-
// Send a message to all links.
|
|
131
|
-
|
|
132
|
-
function sendAll(msg, local link) {
|
|
133
|
-
for link in current.links
|
|
134
|
-
link.responder(msg)
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
//
|
|
138
|
-
// attach
|
|
206
|
+
// ONioctl
|
|
139
207
|
//
|
|
140
|
-
//
|
|
208
|
+
// Process ioctl.
|
|
141
209
|
//
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
responder: responder // link's responder
|
|
210
|
+
function ONioctl(op, arg) {
|
|
211
|
+
notifyAll({
|
|
212
|
+
id: "ioctl",
|
|
213
|
+
op: op,
|
|
214
|
+
arg: arg
|
|
148
215
|
})
|
|
149
|
-
if current.links.length == 1
|
|
150
|
-
current.host.Attach(current.termif) // attached while one link is active
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
//
|
|
154
|
-
// detach
|
|
155
|
-
//
|
|
156
|
-
// Detach a link.
|
|
157
|
-
//
|
|
158
|
-
|
|
159
|
-
current.detach = function detach(link) {
|
|
160
|
-
removeLink(link)
|
|
161
|
-
if current.links.length == 0
|
|
162
|
-
current.host.Detach(current.termif) // attached while one link is active
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
//
|
|
166
|
-
// target.PostMessage
|
|
167
|
-
//
|
|
168
|
-
// Post a message to the main thread.
|
|
169
|
-
//
|
|
170
|
-
current.PostMessage = function PostMessage(data) {
|
|
171
|
-
js.t.DispatchMessage(data)
|
|
172
|
-
list(false, { posted: true })
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
//
|
|
176
|
-
// msgin
|
|
177
|
-
//
|
|
178
|
-
// Send a message to the host interface.
|
|
179
|
-
|
|
180
|
-
current.msgin = function msgin(msg) {
|
|
181
|
-
current.host.DispatchMessage(msg)
|
|
182
216
|
}
|
|
183
217
|
|
|
184
|
-
|
|
185
|
-
// echo
|
|
186
|
-
//
|
|
187
|
-
// Echo a message to the *other* links.
|
|
188
|
-
|
|
189
|
-
current.echo = function echo(msg, thislink, local linkref) {
|
|
190
|
-
for linkref in current.links
|
|
191
|
-
if !(linkref.link eq thislink)
|
|
192
|
-
linkref.responder(msg)
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
//
|
|
196
|
-
// vitalUpdate
|
|
197
|
-
//
|
|
198
|
-
// Worker thread birth/death/enumeration.
|
|
218
|
+
curbot.host.Attach(curbot.termif)
|
|
199
219
|
|
|
200
|
-
|
|
201
|
-
sendAll(msg)
|
|
202
|
-
}
|
|
220
|
+
curbot.subprocess = MakeSubProcessor(curbot) // Enable PTY subprocesses on our terminal
|
|
203
221
|
|
|
204
222
|
// finis
|
|
205
|
-
|
|
223
|
+
|
|
224
|
+
curbot
|
|
206
225
|
};
|
|
207
226
|
|
|
208
227
|
|
|
209
228
|
/*
|
|
210
|
-
*
|
|
229
|
+
* NowBot
|
|
211
230
|
*
|
|
212
|
-
*
|
|
213
|
-
*
|
|
214
|
-
*/
|
|
215
|
-
|
|
216
|
-
function WorkerConnect(workerGUID) {
|
|
217
|
-
gWorkers[workerGUID]
|
|
218
|
-
}
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
/*
|
|
222
|
-
* workMainProxy
|
|
231
|
+
* Spawn a Naan worker in its own thread.
|
|
223
232
|
*
|
|
224
|
-
*
|
|
225
|
-
*
|
|
233
|
+
* Options:
|
|
234
|
+
* {
|
|
235
|
+
* name: <string> // target name, e.g. "Play"
|
|
236
|
+
* type: <string> // target category, e.g. "Local"
|
|
237
|
+
* startup: <dictionary> // startup options
|
|
238
|
+
* topOriginID: <string> // so top can route to us through IMP
|
|
239
|
+
* rootPath: <string> // root path of worker's folder, must have lib/node_worker_init.nlg
|
|
240
|
+
* node: {
|
|
241
|
+
* // see NodeJS docs
|
|
242
|
+
* workerData: { // passed to node_worker.js
|
|
243
|
+
* }
|
|
244
|
+
* }
|
|
245
|
+
* }
|
|
226
246
|
*
|
|
227
247
|
*/
|
|
228
248
|
|
|
229
|
-
closure
|
|
230
|
-
global(js)
|
|
231
|
-
|
|
232
|
-
|
|
249
|
+
closure NowBot(options, local nowbot, nodeops, subChannel, ptySpawned) {
|
|
250
|
+
global(App, js, threads, JSpath)
|
|
251
|
+
nowbot = new(object, this)
|
|
252
|
+
nowbot.topsubs = []
|
|
253
|
+
options = merge({
|
|
254
|
+
type: "node-worker"
|
|
255
|
+
}, options)
|
|
256
|
+
|
|
257
|
+
nodeops = merge({
|
|
258
|
+
// execArgv: ["--inspect-brk"] // unfortunately doesn't work; use VS Code instead
|
|
259
|
+
}, options.node)
|
|
260
|
+
if options.rootPath
|
|
261
|
+
nodeops.workerData = merge({
|
|
262
|
+
rootPath: options.rootPath
|
|
263
|
+
}, nodeops.workerData)
|
|
264
|
+
nowbot.thread = xnew(threads.Worker, JSpath.resolve(js.d, "lib/node_worker.js"), nodeops)
|
|
265
|
+
subChannel = xnew(threads.MessageChannel)
|
|
266
|
+
nowbot.thread.postMessage({ hereIsYourPort: subChannel.port1 }, [subChannel.port1])
|
|
267
|
+
nowbot.msgport = subChannel.port2
|
|
268
|
+
|
|
269
|
+
nowbot.instanceID = UUID()
|
|
270
|
+
nowbot.sender = App.imp.register(nowbot, {
|
|
271
|
+
name: options.name
|
|
272
|
+
type: options.type
|
|
273
|
+
instanceID: nowbot.instanceID
|
|
274
|
+
services: ["node-worker"]
|
|
275
|
+
})
|
|
233
276
|
|
|
277
|
+
// If this NowBot is created remotely then we need to send a message from our new instanceID
|
|
278
|
+
// to the InTop origin so that it can send messages to us. The intermediate gateways save the
|
|
279
|
+
// route to allow replies.
|
|
280
|
+
if options.topOriginID && options.topOriginID != App.imp.us.instanceID
|
|
281
|
+
nowbot.sender(options.topOriginID) // create route top->bottom
|
|
282
|
+
|
|
283
|
+
// subscribe
|
|
284
|
+
//
|
|
285
|
+
// Add an InTop to our subscribers if not already known.
|
|
286
|
+
//
|
|
287
|
+
function subscribe(destID) {
|
|
288
|
+
if !nowbot.topsubs.find(function(item) { item == destID }) {
|
|
289
|
+
nowbot.topsubs.push(destID)
|
|
290
|
+
if nowbot.workerDestID {
|
|
291
|
+
App.imp.inform(nowbot.workerDestID, destID) // provide path to workerID
|
|
292
|
+
nowbot.sender(destID, { // send to new subscriber
|
|
293
|
+
id: "workerDestID"
|
|
294
|
+
workerDestID: nowbot.workerDestID
|
|
295
|
+
})
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
// unsubscribe
|
|
234
301
|
//
|
|
235
|
-
//
|
|
236
|
-
//
|
|
237
|
-
// Post a message to the main thread.
|
|
302
|
+
// Remove an InTop from our subscribers if present.
|
|
238
303
|
//
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
list(false, { posted: true })
|
|
304
|
+
function unsubscribe(destID) {
|
|
305
|
+
nowbot.topsubs = nowbot.topsubs.filter(function(item) { item != destID })
|
|
242
306
|
}
|
|
243
307
|
|
|
308
|
+
// notifyAll
|
|
244
309
|
//
|
|
245
|
-
//
|
|
246
|
-
//
|
|
247
|
-
// Process a received message from the main thread, typically in response.
|
|
310
|
+
// Send the message to all our subscribers.
|
|
248
311
|
//
|
|
249
|
-
function
|
|
250
|
-
|
|
312
|
+
nowbot.notifyAll = function notifyAll(message, exceptID, local topDestID) {
|
|
313
|
+
for topDestID in nowbot.topsubs
|
|
314
|
+
if topDestID != exceptID
|
|
315
|
+
nowbot.sender(topDestID, message)
|
|
251
316
|
}
|
|
252
|
-
|
|
253
|
-
//
|
|
317
|
+
|
|
318
|
+
// textEntry
|
|
254
319
|
//
|
|
255
|
-
//
|
|
320
|
+
// Simulate text entry for subprocess support.
|
|
256
321
|
//
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
322
|
+
nowbot.textEntry = function textEntry(text) {
|
|
323
|
+
nowbot.msgport.postMessage({
|
|
324
|
+
id: "keyline"
|
|
325
|
+
text: text
|
|
326
|
+
})
|
|
260
327
|
}
|
|
261
328
|
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
//
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
* WorkerToMain
|
|
273
|
-
*
|
|
274
|
-
* Connect our worker to the main thread, returning a result tuple with an executor representing
|
|
275
|
-
* Main. Use this to create a context object for Main, allowing remote evaluation.
|
|
276
|
-
*
|
|
277
|
-
*/
|
|
278
|
-
|
|
279
|
-
closure WorkerToMain(local nideRunning, track) {
|
|
280
|
-
// mainProxy -- link tracker to main thread proxy
|
|
281
|
-
function mainProxy(track, name, options) {
|
|
282
|
-
workMainProxy(track, name, options)
|
|
329
|
+
// ioctl
|
|
330
|
+
//
|
|
331
|
+
// Send an ioctl to the terminal.
|
|
332
|
+
//
|
|
333
|
+
nowbot.ioctl = function ioctl(op, arg) {
|
|
334
|
+
notifyAll({
|
|
335
|
+
id: "ioctl"
|
|
336
|
+
op: op
|
|
337
|
+
arg: arg
|
|
338
|
+
})
|
|
283
339
|
}
|
|
284
340
|
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
341
|
+
// rawMode
|
|
342
|
+
//
|
|
343
|
+
// Configure ioctls for raw terminal operation using the spawned PTY process.
|
|
344
|
+
//
|
|
345
|
+
nowbot.rawStart = function rawStart(ptys) {
|
|
346
|
+
ptySpawned = ptys
|
|
347
|
+
ioctl("raw", true)
|
|
348
|
+
nowbot.rawStop = function rawStop() {
|
|
349
|
+
ioctl("raw", false)
|
|
350
|
+
nowbot.rawStop = undefined
|
|
351
|
+
ptySpawned = false
|
|
352
|
+
}
|
|
288
353
|
}
|
|
289
|
-
nideRunning = require("naanlib:frameworks/running/executors.nlg")
|
|
290
|
-
track = nideRunning.ExecutorTracker()
|
|
291
|
-
track.register(mainProxy, "proxy")
|
|
292
|
-
track.spawn("proxy") // returns result tuple
|
|
293
|
-
};
|
|
294
354
|
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
}
|
|
327
|
-
}
|
|
328
|
-
|
|
329
|
-
// exitNotify
|
|
330
|
-
// Notify all links that we have terminated.
|
|
331
|
-
|
|
332
|
-
function exitNotify(exitCode, local link) {
|
|
333
|
-
workco.uworkers[worker.guid] = undefined
|
|
334
|
-
for link in worker.links
|
|
335
|
-
link.exitWorker(exitCode)
|
|
336
|
-
worker.links = []
|
|
337
|
-
deathWatcher(workerID)
|
|
355
|
+
// impReceive
|
|
356
|
+
//
|
|
357
|
+
// Received a payload.
|
|
358
|
+
//
|
|
359
|
+
nowbot.impReceive = function impReceive(message, sourceID) {
|
|
360
|
+
if message.id == "destroy"
|
|
361
|
+
terminate()
|
|
362
|
+
else if message.id == "subscribe"
|
|
363
|
+
subscribe(sourceID)
|
|
364
|
+
else if message.id == "unsubscribe"
|
|
365
|
+
unsubscribe(sourceID)
|
|
366
|
+
else {
|
|
367
|
+
subscribe(sourceID) // auto-subscribe
|
|
368
|
+
if message.id == "typed" {
|
|
369
|
+
notifyAll(message, sourceID)
|
|
370
|
+
return
|
|
371
|
+
}
|
|
372
|
+
if ptySpawned { // raw mode: kludgey, but works
|
|
373
|
+
if message.id == "ioctl-event" {
|
|
374
|
+
if message.msg == "raw-key"
|
|
375
|
+
ptySpawned.write(message.arg.key)
|
|
376
|
+
else if message.msg == "term-resize"
|
|
377
|
+
ptySpawned.resize(message.arg.cols, message.arg.rows)
|
|
378
|
+
}
|
|
379
|
+
if (message.id == "attached")
|
|
380
|
+
ioctl("raw", true) // restore raw mode after terminal attach
|
|
381
|
+
}
|
|
382
|
+
if message.id == "keyline" && nowbot.keyin
|
|
383
|
+
nowbot.keyin(message.text) // terminal keyboard -> pty subprocess
|
|
384
|
+
else
|
|
385
|
+
nowbot.msgport.postMessage(message)
|
|
386
|
+
}
|
|
338
387
|
}
|
|
339
|
-
|
|
340
|
-
//
|
|
341
|
-
//
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
388
|
+
|
|
389
|
+
// impUnknown
|
|
390
|
+
//
|
|
391
|
+
// Received an unknown destination notice.
|
|
392
|
+
//
|
|
393
|
+
nowbot.impUnknown = function impUnknown(unknownID, sourceID, gateway) {
|
|
394
|
+
if nowbot.topsubs.indexOf(unknownID) >= 0 { // did not have courtesy to unsubscribe!
|
|
395
|
+
unsubscribe(unknownID)
|
|
396
|
+
return
|
|
397
|
+
}
|
|
398
|
+
if !gateway
|
|
399
|
+
debuglog("NowBot.impUnknownID:", unknownID, "sourceID:", sourceID)
|
|
346
400
|
}
|
|
347
401
|
|
|
402
|
+
// nowbot
|
|
348
403
|
//
|
|
349
|
-
//
|
|
350
|
-
//
|
|
351
|
-
// An exception occurred on the worker thread. Since Naan catches all exceptions this should
|
|
404
|
+
// An exception occurred on the worker thread. Since Naan catches all exceptions this should
|
|
352
405
|
// not occur normally.
|
|
353
|
-
|
|
354
|
-
worker.thread.on("error", function onerror(error) {
|
|
355
|
-
debuglog("worker terminated with error", workerID, error)
|
|
356
|
-
exitNotify(-1)
|
|
357
|
-
})
|
|
358
|
-
|
|
359
406
|
//
|
|
407
|
+
nowbot.thread.on("error", function onerror(error) {
|
|
408
|
+
debuglog("worker terminated with error", options.type, options.name, error)
|
|
409
|
+
notifyAll({
|
|
410
|
+
id: "terminated"
|
|
411
|
+
error: error
|
|
412
|
+
})
|
|
413
|
+
nowbot.dispatchEvent("terminated", nowbot.instanceID, { error: error })
|
|
414
|
+
nowbot.thread = false
|
|
415
|
+
destroy()
|
|
416
|
+
})
|
|
417
|
+
|
|
360
418
|
// onexit
|
|
361
419
|
//
|
|
362
|
-
//
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
420
|
+
// Note that the worker thread has terminated.
|
|
421
|
+
//
|
|
422
|
+
nowbot.thread.on("exit", function onexit(exitCode) {
|
|
423
|
+
notifyAll({
|
|
424
|
+
id: "terminated"
|
|
425
|
+
exitCode: exitCode
|
|
426
|
+
})
|
|
427
|
+
nowbot.dispatchEvent("terminated", nowbot.instanceID, { exitCode: exitCode })
|
|
428
|
+
nowbot.thread = false
|
|
429
|
+
destroy()
|
|
366
430
|
})
|
|
367
431
|
|
|
432
|
+
// destroy
|
|
368
433
|
//
|
|
369
|
-
//
|
|
434
|
+
// Ensure the worker is destroyed.
|
|
370
435
|
//
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
436
|
+
nowbot.destroy = function destroy() {
|
|
437
|
+
terminate()
|
|
438
|
+
nowbot.thread = false
|
|
439
|
+
nowbot.impconn.destroy()
|
|
440
|
+
nowbot.impconn = false
|
|
441
|
+
App.imp.unregister(nowbot.instanceID)
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
// NaaN message
|
|
445
|
+
//
|
|
446
|
+
// A message has been received from NaaN running on the worker thread.
|
|
447
|
+
//
|
|
448
|
+
nowbot.msgport.on("message", function (msg, local startmsg) {
|
|
449
|
+
if msg.id == "naan-imp-node" {
|
|
450
|
+
nowbot.impconn.dispatch(new(msg.data))
|
|
451
|
+
return
|
|
452
|
+
} else if msg.id == "loaded" {
|
|
375
453
|
startmsg = {
|
|
376
454
|
id: "start"
|
|
377
455
|
state: false // resume state, if we have any
|
|
378
|
-
altcmd:
|
|
456
|
+
altcmd: options.startup.initcmds
|
|
379
457
|
dirpath: js.d
|
|
380
458
|
workerID: workerID
|
|
381
|
-
|
|
459
|
+
metadata: {
|
|
460
|
+
mainInstanceID: App.imp.us.instanceID
|
|
461
|
+
name: options.name
|
|
462
|
+
maintext: options.startup.maintext.concat("\n")
|
|
463
|
+
}
|
|
382
464
|
}
|
|
383
|
-
if startup.
|
|
384
|
-
startmsg.
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
id: "targetin"
|
|
395
|
-
data: msg.data
|
|
396
|
-
}) }
|
|
397
|
-
else {
|
|
398
|
-
if msg.id == "status"
|
|
399
|
-
worker.lastStatus = milliseconds()
|
|
400
|
-
else if msg.id == "targetout"
|
|
401
|
-
worker.execReceived(msg.data)
|
|
402
|
-
sendAll(msg) } // default is just return message to the client
|
|
465
|
+
if options.startup.dirpath
|
|
466
|
+
startmsg.dirpath = options.startup.dirpath
|
|
467
|
+
nowbot.msgport.postMessage(startmsg)
|
|
468
|
+
notifyAll({
|
|
469
|
+
id: "started"
|
|
470
|
+
})
|
|
471
|
+
nowbot.dispatchEvent("started", nowbot.instanceID)
|
|
472
|
+
} else if msg.id == "textout" && nowbot.naanin
|
|
473
|
+
nowbot.naanin(msg.text) // naan output -> pty subprocess
|
|
474
|
+
else
|
|
475
|
+
notifyAll(msg)
|
|
403
476
|
})
|
|
404
|
-
|
|
405
|
-
//
|
|
406
|
-
// terminate
|
|
407
|
-
//
|
|
408
|
-
// Terminate this worker asap.
|
|
409
|
-
|
|
410
|
-
worker.terminate = function terminate(local error, exitCode) {
|
|
411
|
-
`(error, exitCode) = await(worker.thread.terminate())
|
|
412
|
-
exitNotify(exitCode)
|
|
413
|
-
}
|
|
414
477
|
|
|
478
|
+
// terminate
|
|
415
479
|
//
|
|
416
|
-
//
|
|
417
|
-
//
|
|
418
|
-
// Attach a connection to our worker.
|
|
419
|
-
//
|
|
420
|
-
|
|
421
|
-
worker.attach = function attach(link, responder) {
|
|
422
|
-
removeLink(link)
|
|
423
|
-
worker.links.push({
|
|
424
|
-
link: link // a link to us
|
|
425
|
-
responder: responder // link's responder
|
|
426
|
-
})
|
|
427
|
-
}
|
|
428
|
-
|
|
429
|
-
//
|
|
430
|
-
// detach
|
|
431
|
-
//
|
|
432
|
-
// Detach a link from our worker.
|
|
480
|
+
// Terminate this worker asap.
|
|
433
481
|
//
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
482
|
+
nowbot.terminate = function terminate(local error, exitCode) {
|
|
483
|
+
if nowbot.thread
|
|
484
|
+
`(error, exitCode) = await(nowbot.thread.terminate()) // notified by on-error and on-exit
|
|
485
|
+
else
|
|
486
|
+
list(false, { terminated: true }) // already terminated
|
|
437
487
|
}
|
|
438
488
|
|
|
439
|
-
//
|
|
440
489
|
// PostMessage
|
|
441
490
|
//
|
|
442
|
-
//
|
|
491
|
+
// Post a message to the worker thread.
|
|
443
492
|
//
|
|
444
|
-
|
|
445
|
-
|
|
493
|
+
nowbot.PostMessage = function PostMessage(data) {
|
|
494
|
+
nowbot.msgport.postMessage({ // send data to worker
|
|
446
495
|
id: "targetin",
|
|
447
496
|
data: data
|
|
448
497
|
})
|
|
449
498
|
list(false, { posted: true })
|
|
450
499
|
}
|
|
451
500
|
|
|
452
|
-
//
|
|
453
|
-
|
|
454
|
-
//
|
|
455
|
-
// Send a message to the worker thread.
|
|
456
|
-
|
|
457
|
-
worker.msgin = function msgin(msg) {
|
|
458
|
-
worker.msgport.postMessage(msg)
|
|
459
|
-
}
|
|
460
|
-
|
|
461
|
-
//
|
|
462
|
-
// echo
|
|
463
|
-
//
|
|
464
|
-
// Echo a message to the *other* links.
|
|
465
|
-
|
|
466
|
-
worker.echo = function echo(msg, thislink, local linkref) {
|
|
467
|
-
for linkref in worker.links
|
|
468
|
-
if !(linkref.link eq thislink)
|
|
469
|
-
linkref.responder(msg)
|
|
470
|
-
}
|
|
471
|
-
|
|
472
|
-
//
|
|
473
|
-
// vitalWatch
|
|
474
|
-
//
|
|
475
|
-
// Report our termination to the specified watcher.
|
|
476
|
-
|
|
477
|
-
worker.vitalWatch = function vitalWatch(watcher) {
|
|
478
|
-
deathWatcher = watcher
|
|
479
|
-
}
|
|
501
|
+
nowbot.subprocess = MakeSubProcessor(nowbot) // Enable PTY subprocesses on our terminal
|
|
502
|
+
Events(nowbot)
|
|
480
503
|
|
|
481
504
|
// finis
|
|
482
|
-
|
|
505
|
+
|
|
506
|
+
nowbot
|
|
483
507
|
};
|
|
484
508
|
|
|
485
509
|
|
|
486
510
|
/*
|
|
487
|
-
*
|
|
511
|
+
* NobBot
|
|
488
512
|
*
|
|
489
|
-
*
|
|
490
|
-
*
|
|
491
|
-
* clients to create a new connection to talk with an existing worker.
|
|
513
|
+
* Create a remote interface like NowBot, but also provide messaging support for NodeWorkerNub inside
|
|
514
|
+
* the worker.
|
|
492
515
|
*
|
|
493
516
|
*/
|
|
494
517
|
|
|
495
|
-
closure
|
|
496
|
-
|
|
497
|
-
|
|
518
|
+
closure NobBot(options, local nobbot)
|
|
519
|
+
{
|
|
520
|
+
global(App)
|
|
521
|
+
nobbot = NowBot(options)
|
|
498
522
|
|
|
523
|
+
// informAll
|
|
499
524
|
//
|
|
500
|
-
//
|
|
501
|
-
//
|
|
502
|
-
// Note that the connection has closed.
|
|
503
|
-
//
|
|
504
|
-
|
|
505
|
-
link.closeConn = function closeConn() {
|
|
506
|
-
worker.detach(link) // stop receiving updates from worker
|
|
507
|
-
}
|
|
508
|
-
|
|
509
|
-
//
|
|
510
|
-
// exitWorker
|
|
511
|
-
//
|
|
512
|
-
// Note that the worker has exited.
|
|
525
|
+
// Inform sourceID path to all our subscribers.
|
|
513
526
|
//
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
workerID: worker.workerID // notify client they've lost a worker
|
|
518
|
-
exitCode: exitCode
|
|
519
|
-
}])
|
|
520
|
-
workco.closeLink(link, conn, worker.workerID)
|
|
521
|
-
worker.detach(link)
|
|
527
|
+
function informAll(sourceID, local topDestID) {
|
|
528
|
+
for topDestID in nobbot.topsubs
|
|
529
|
+
App.imp.inform(sourceID, topDestID)
|
|
522
530
|
}
|
|
523
531
|
|
|
524
|
-
|
|
532
|
+
App.imp.addEventListener("active", function(event, info) {
|
|
533
|
+
if info.ourID == nobbot.instanceID {
|
|
534
|
+
nobbot.workerDestID = info.destID // handshake completed
|
|
535
|
+
informAll(nobbot.workerDestID) // provide path to workerID
|
|
536
|
+
nobbot.notifyAll({ // send to subscribers
|
|
537
|
+
id: "workerDestID"
|
|
538
|
+
workerDestID: nobbot.workerDestID
|
|
539
|
+
})
|
|
540
|
+
}
|
|
541
|
+
})
|
|
525
542
|
|
|
526
|
-
|
|
527
|
-
|
|
543
|
+
nobbot.impconn = App.imp.responder(function(data) {
|
|
544
|
+
nobbot.msgport.postMessage({ // send to worker
|
|
545
|
+
id: "naan-imp-node" // scoped for NodeWorkerNub
|
|
546
|
+
data: data
|
|
547
|
+
})
|
|
548
|
+
list(false, { sent: true })
|
|
549
|
+
}, {
|
|
550
|
+
ourID: nobbot.instanceID
|
|
528
551
|
})
|
|
529
|
-
sender("linked", [false, {
|
|
530
|
-
workerID: worker.workerID // notify client they've gained a worker
|
|
531
|
-
}])
|
|
532
552
|
|
|
533
553
|
// finis
|
|
534
554
|
|
|
535
|
-
|
|
555
|
+
nobbot
|
|
536
556
|
};
|
|
537
557
|
|
|
538
558
|
|
|
539
559
|
/*
|
|
540
|
-
*
|
|
560
|
+
* MakeSubProcessor
|
|
541
561
|
*
|
|
542
|
-
*
|
|
543
|
-
*
|
|
544
|
-
*
|
|
562
|
+
* Method PTY subprocess capability to CurBot and NowBot. They also need these:
|
|
563
|
+
*
|
|
564
|
+
* function impReceive(message, sourceID) { ...
|
|
565
|
+
* ...
|
|
566
|
+
* if message.id == "keyline" && nowbot.keyin
|
|
567
|
+
* execbot.keyin(message.text) // terminal keyboard -> pty subprocess
|
|
568
|
+
*
|
|
569
|
+
* function naanmsg(msg, local startmsg) { ...
|
|
570
|
+
* ...
|
|
571
|
+
* else if msg.id == "textout" && nowbot.naanin
|
|
572
|
+
* execbot.naanin(msg.text) // naan output -> pty subprocess
|
|
573
|
+
*
|
|
574
|
+
* subprocess
|
|
575
|
+
*
|
|
576
|
+
* Create a PTY subprocess and connect with the worker and terminal. You specify the path of
|
|
577
|
+
* the executable and the arguments. If no executable is specified then a shell is created. The
|
|
578
|
+
* return value is a result tuple with an object that can be used to kill or monitor the
|
|
579
|
+
* subprocess.
|
|
580
|
+
*
|
|
581
|
+
* exec.subprocess(executable, args, options)
|
|
582
|
+
*
|
|
583
|
+
* The subprocess can be connected to the terminal raw, or in a variety of ways:
|
|
584
|
+
*
|
|
585
|
+
* term-keyboard | term-display | worker-in | worker-out
|
|
586
|
+
* -------------------------------------|---------------|------------|-----------
|
|
587
|
+
* subprocess input keyboard | | | pipe
|
|
588
|
+
* subprocess output | display | tee | pipe | tee |
|
|
589
|
+
*
|
|
590
|
+
* Options:
|
|
591
|
+
* {
|
|
592
|
+
* input: false | "keyboard" | "pipe"
|
|
593
|
+
* output: false | "display" | "pipe" | "tee"
|
|
594
|
+
* raw: <boolean>
|
|
595
|
+
* spawn: <PtyManager.spawn options>
|
|
596
|
+
* }
|
|
545
597
|
*
|
|
546
598
|
*/
|
|
547
599
|
|
|
548
|
-
closure
|
|
549
|
-
global(
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
if !iddict
|
|
563
|
-
workco.links[conn] = iddict = { }
|
|
564
|
-
iddict[workerID] = link
|
|
565
|
-
}
|
|
566
|
-
|
|
567
|
-
// deleteLinkForConnection
|
|
568
|
-
// Remove a link for a connection under its workerID, or false.
|
|
569
|
-
|
|
570
|
-
function deleteLinkForConnection(conn, workerID) {
|
|
571
|
-
if workco.links[conn][workerID]
|
|
572
|
-
workco.links[conn][workerID] = undefined
|
|
573
|
-
}
|
|
574
|
-
|
|
575
|
-
// makeSender
|
|
576
|
-
// Sender factory for specified connection and message.
|
|
577
|
-
|
|
578
|
-
closure makeSender(conn, message) {
|
|
579
|
-
function sender(respOp, payload) {
|
|
580
|
-
conn.send({
|
|
581
|
-
clientID: message.clientID
|
|
582
|
-
serverID: message.serverID
|
|
583
|
-
workerID: message.workerID
|
|
584
|
-
respOp: respOp
|
|
585
|
-
payload: payload
|
|
586
|
-
})
|
|
600
|
+
closure MakeSubProcessor(execbot) {
|
|
601
|
+
global()
|
|
602
|
+
closure subprocess(
|
|
603
|
+
executable, args, options, local error, pty) {
|
|
604
|
+
|
|
605
|
+
// ptyData - text has been returned from the subprocess
|
|
606
|
+
function ptyData(text) {
|
|
607
|
+
if options.output == "display" || options.output == "tee"
|
|
608
|
+
execbot.notifyAll({ // send to display
|
|
609
|
+
id: "textout",
|
|
610
|
+
text: text
|
|
611
|
+
})
|
|
612
|
+
if options.output == "pipe" || options.output == "tee"
|
|
613
|
+
execbot.textEntry(text) // send to NaaN worker
|
|
587
614
|
}
|
|
588
|
-
}
|
|
589
|
-
|
|
590
|
-
// makeLink
|
|
591
|
-
// Link the specified message, connection and worker.
|
|
592
|
-
|
|
593
|
-
function makeLink(message, conn, local worker, link) {
|
|
594
|
-
worker = workco.workers[message.workerID]
|
|
595
|
-
link = workLink(workco, conn, worker, makeSender(conn, message))
|
|
596
|
-
addLinkForConnection(conn, message.workerID, link)
|
|
597
|
-
}
|
|
598
|
-
|
|
599
|
-
// termination
|
|
600
|
-
// Note that a worker has terminated.
|
|
601
|
-
|
|
602
|
-
function termination(workerID) {
|
|
603
|
-
workco.current.vitalUpdate({
|
|
604
|
-
id: "termination", // note a thread has gone away
|
|
605
|
-
workerID: workerID
|
|
606
|
-
})
|
|
607
|
-
workco.workers[workerID] = undefined // it's like this worker has never been
|
|
608
|
-
}
|
|
609
615
|
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
else
|
|
622
|
-
worker = workThread(workco, workerID, config, guid)
|
|
623
|
-
workco.uworkers[worker.guid] = worker
|
|
624
|
-
workco.workers[workerID] = worker
|
|
625
|
-
gWorkers[worker.guid] = worker }
|
|
626
|
-
if workerID == "NideServer"
|
|
627
|
-
workco.current.vitalUpdate({
|
|
628
|
-
id: "workerlist", // send the initial list of workers
|
|
629
|
-
workers: let(workers, workerID, worker) {
|
|
630
|
-
workers = { }
|
|
631
|
-
for `(workerID, worker) in workco.workers
|
|
632
|
-
workers[workerID] = {
|
|
633
|
-
name: worker.name
|
|
634
|
-
}
|
|
635
|
-
workers
|
|
636
|
-
}()
|
|
637
|
-
})
|
|
638
|
-
else {
|
|
639
|
-
worker.vitalWatch(termination)
|
|
640
|
-
workco.current.vitalUpdate({
|
|
641
|
-
id: "spawned", // note a new worker thread
|
|
642
|
-
name: config.name
|
|
643
|
-
workerID: workerID
|
|
644
|
-
}) }
|
|
645
|
-
list(false, worker)
|
|
646
|
-
}
|
|
616
|
+
// ptyKilled - the subprocess has terminated
|
|
617
|
+
function ptyKilled(event) {
|
|
618
|
+
if execbot.keyin === keyin
|
|
619
|
+
execbot.keyin = false
|
|
620
|
+
if execbot.naanin === naanin
|
|
621
|
+
execbot.naanin = false
|
|
622
|
+
if options.raw {
|
|
623
|
+
execbot.rawStop()
|
|
624
|
+
execbot.textEntry("\x15mu();;\n") // send to NaaN worker
|
|
625
|
+
}
|
|
626
|
+
}
|
|
647
627
|
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
//
|
|
652
|
-
workco.wsReceive = function wsReceive(message, conn, local worker, link, error) {
|
|
653
|
-
if !message.workerID
|
|
654
|
-
error = Error("workerID required", message.workerOp)
|
|
655
|
-
else
|
|
656
|
-
{
|
|
657
|
-
worker = workco.workers[message.workerID]
|
|
658
|
-
link = workco.links[conn][message.workerID]
|
|
659
|
-
if message.workerOp == "msgin" {
|
|
660
|
-
if worker && message.payload {
|
|
661
|
-
if !link
|
|
662
|
-
makeLink(message, conn) // make sure we have a link for responses
|
|
663
|
-
worker.msgin(message.payload) } // send message to worker
|
|
664
|
-
return }
|
|
665
|
-
else if message.workerOp == "echo" {
|
|
666
|
-
if worker && message.payload {
|
|
667
|
-
if !link
|
|
668
|
-
makeLink(message, conn) // make sure we have a link for responses
|
|
669
|
-
worker.echo(message.payload, link) } // echo message to other links
|
|
670
|
-
return }
|
|
671
|
-
else if message.workerOp == "spawn" {
|
|
672
|
-
spawn(message.workerID, message.payload, message.workerGUID)
|
|
673
|
-
if !link
|
|
674
|
-
makeLink(message, conn) // make sure we have a link for responses
|
|
675
|
-
return }
|
|
676
|
-
else if message.workerOp == "terminate" {
|
|
677
|
-
if worker {
|
|
678
|
-
if !link
|
|
679
|
-
makeLink(message, conn) // make sure we have a link for responses
|
|
680
|
-
worker.terminate() } // echo message to other links
|
|
681
|
-
return }
|
|
682
|
-
error = Error("invalid parameters", message.workerOp, message.workerID)
|
|
628
|
+
// keyin - the terminal has generated text for the subprocess
|
|
629
|
+
function keyin(text) {
|
|
630
|
+
pty.write(text)
|
|
683
631
|
}
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
// wsClose
|
|
689
|
-
//
|
|
690
|
-
// Note that the connection with the client was closed.
|
|
691
|
-
//
|
|
692
|
-
|
|
693
|
-
workco.wsClose = function wsClose(conn, local workerID, link) {
|
|
694
|
-
for workerID in workco.workers {
|
|
695
|
-
link = workco.links[conn][workerID]
|
|
696
|
-
if link
|
|
697
|
-
link.closeConn()
|
|
698
|
-
deleteLinkForConnection(conn, workerID)
|
|
632
|
+
|
|
633
|
+
// naanin - NaaN worker has generated text for the subprocess
|
|
634
|
+
function naanin(text) {
|
|
635
|
+
pty.write(text)
|
|
699
636
|
}
|
|
700
|
-
}
|
|
701
|
-
|
|
702
|
-
//
|
|
703
|
-
// closeLink
|
|
704
|
-
//
|
|
705
|
-
// Note that a link with the worker has closed.
|
|
706
|
-
//
|
|
707
637
|
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
638
|
+
require("./pty.nlg") // load on demand
|
|
639
|
+
`(error, pty) = PtyManager().spawn(executable, args, {
|
|
640
|
+
ptyData: ptyData
|
|
641
|
+
ptyKilled: ptyKilled
|
|
642
|
+
}, options.spawn)
|
|
643
|
+
if error
|
|
644
|
+
return (list(error))
|
|
645
|
+
if options.input == "keyboard"
|
|
646
|
+
execbot.keyin = keyin // replace existing
|
|
647
|
+
else if options.input == "pipe"
|
|
648
|
+
execbot.naanin = naanin // replace existing
|
|
649
|
+
if options.raw
|
|
650
|
+
execbot.rawStart(pty)
|
|
651
|
+
|
|
652
|
+
// our worker has terminated
|
|
653
|
+
execbot.addEventListener("terminated", function() {
|
|
654
|
+
pty.kill()
|
|
655
|
+
})
|
|
711
656
|
|
|
712
|
-
|
|
713
|
-
|
|
657
|
+
list(false, pty)
|
|
658
|
+
}
|
|
714
659
|
};
|
|
715
660
|
|
|
716
661
|
|
|
@@ -722,13 +667,12 @@ closure workController(api, local workco) {
|
|
|
722
667
|
*/
|
|
723
668
|
|
|
724
669
|
function workInit(local manifest) {
|
|
725
|
-
manifest = `(
|
|
726
|
-
workController, workInit)
|
|
670
|
+
manifest = `(CurBot, NowBot, NobBot, MakeSubProcessor, workInit)
|
|
727
671
|
Naan.module.build(module.id, "worker", function(modobj, compobj) {
|
|
728
672
|
require("./node.nlg")
|
|
729
673
|
compobj.manifest = manifest
|
|
730
|
-
modobj.exports.
|
|
731
|
-
modobj.exports.
|
|
732
|
-
modobj.exports.
|
|
674
|
+
modobj.exports.CurBot = CurBot
|
|
675
|
+
modobj.exports.NowBot = NowBot
|
|
676
|
+
modobj.exports.NobBot = NobBot
|
|
733
677
|
})
|
|
734
678
|
}();
|