@naanlang/naan 1.4.4 → 1.6.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 +4 -4
- package/bin/index.js +25 -3
- package/dist/env_web.js +164 -22
- package/dist/naan.min.js +5 -5
- package/frameworks/browser/browser.nlg +2 -2
- package/frameworks/browser/https_request.nlg +2 -2
- package/frameworks/browser/sworker.js +28 -26
- package/frameworks/browser/terminals.nlg +342 -700
- package/frameworks/browser/worker.nlg +255 -0
- package/frameworks/browser/workers.nlg +5 -5
- package/frameworks/browser/ws_client.nlg +15 -10
- package/frameworks/client/apiclient.nlg +204 -19
- package/frameworks/client/client.nlg +22 -2
- package/frameworks/client/psm_client.nlg +12 -3
- package/frameworks/client/relaycon.nlg +87 -161
- package/frameworks/common/events.nlg +101 -0
- package/frameworks/common/repltools.nlg +80 -1
- package/frameworks/node/apiserver.nlg +39 -246
- package/frameworks/node/filesystem.nlg +39 -12
- package/frameworks/node/gitter.nlg +9 -7
- package/frameworks/node/http_request.nlg +34 -13
- package/frameworks/node/https_request.nlg +8 -3
- package/frameworks/node/node.nlg +2 -0
- package/frameworks/node/pty.nlg +346 -0
- package/frameworks/node/shell.nlg +4 -4
- package/frameworks/node/worker.nlg +409 -539
- package/frameworks/node/ws_client.nlg +2 -2
- package/frameworks/project/build.nlg +1 -1
- package/frameworks/project/projects.nlg +2 -1
- package/frameworks/running/debugnub.nlg +17 -4
- package/frameworks/running/executors.nlg +27 -274
- package/frameworks/running/instances.nlg +393 -0
- package/frameworks/running/remote_req.nlg +143 -0
- package/frameworks/running/remote_res.nlg +89 -0
- package/frameworks/running/taskexec.nlg +2 -2
- package/frameworks/service/imp.nlg +736 -0
- package/frameworks/service/model.nlg +71 -0
- package/frameworks/service/nubnode.nlg +105 -0
- package/frameworks/service/nubweb.nlg +106 -0
- package/frameworks/service/service.nlg +28 -0
- package/frameworks/storage/dbt_pouch.nlg +26 -13
- package/frameworks/storage/psm.nlg +39 -5
- package/frameworks/storage/psm_dbtables.nlg +10 -2
- package/lib/browser/env_web.js +171 -29
- package/lib/browser/env_webworker.js +91 -5
- package/lib/core/naanlib.js +5 -5
- package/lib/env_node.js +184 -8
- package/lib/env_nodeworker.js +74 -1
- package/package.json +1 -1
- package/plugins/serviceAws/aws_cloudwatchlogs.nlg +2 -1
- package/plugins/serviceAws/aws_dynamo.nlg +1 -0
- package/plugins/serviceAws/aws_s3.nlg +3 -3
- package/plugins/serviceAws/aws_sqs.nlg +3 -1
- package/plugins/serviceAws/aws_utils.nlg +3 -1
- package/plugins/serviceAws/dbt_aws.nlg +22 -20
- package/plugins/serviceAws/psm_aws.nlg +2 -1
- package/plugins/serviceNexara/speechrec.nlg +10 -6
- package/test/test_02_context.nlg +24 -1
- package/test/test_03_jsinterop.nlg +32 -3
- package/plugins/serviceGC/russian_trusted_root_ca_pem.crt +0 -33
|
@@ -6,7 +6,7 @@
|
|
|
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
|
|
|
@@ -18,6 +18,69 @@
|
|
|
18
18
|
gWorkers;
|
|
19
19
|
|
|
20
20
|
|
|
21
|
+
/*
|
|
22
|
+
* ioctl terminal control and events
|
|
23
|
+
*
|
|
24
|
+
* Example "raw" mode:
|
|
25
|
+
*
|
|
26
|
+
// rawTest
|
|
27
|
+
// echo typed keystrokes in BOLD until Control-C stops it.
|
|
28
|
+
//
|
|
29
|
+
closure rawTest(local dokey) {
|
|
30
|
+
dokey = xnew(function(msg, arg) {
|
|
31
|
+
if arg.key == "\x03" {
|
|
32
|
+
js.t.ioctl("raw", false)
|
|
33
|
+
js.t.ioctl_remove_listener("raw-key", dokey)
|
|
34
|
+
}
|
|
35
|
+
else
|
|
36
|
+
print("\x1b[1m${arg.key}\x1b[22m")
|
|
37
|
+
})
|
|
38
|
+
js.t.ioctl_add_listener("raw-key", dokey)
|
|
39
|
+
js.t.ioctl("raw", true)
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
rawTest();
|
|
43
|
+
*
|
|
44
|
+
*
|
|
45
|
+
* Example echo control:
|
|
46
|
+
*
|
|
47
|
+
js.t.ioctl("echo", 0) // no echo at all
|
|
48
|
+
js.t.ioctl("echo", 1) // echo newlines (best for hiding REPL commands)
|
|
49
|
+
js.t.ioctl("echo", 2) // normal echo
|
|
50
|
+
|
|
51
|
+
js.t.ioctl("sane") // restore echo and raw
|
|
52
|
+
*
|
|
53
|
+
*
|
|
54
|
+
* Example simulated keystrokes:
|
|
55
|
+
*
|
|
56
|
+
future(function(){ js.t.ioctl("keystroke", "joe") }, 10); // "joe" in keyboard buffer
|
|
57
|
+
*
|
|
58
|
+
*
|
|
59
|
+
* Example terminal resize notification:
|
|
60
|
+
*
|
|
61
|
+
doresize = xnew(function(msg, dim) { printline("(${dim.cols}, ${dim.rows})")})
|
|
62
|
+
js.t.ioctl_add_listener("term-resize", doresize);
|
|
63
|
+
*
|
|
64
|
+
*
|
|
65
|
+
* Example terminal connection notification:
|
|
66
|
+
*
|
|
67
|
+
// add removable listener:
|
|
68
|
+
listener = xnew(function(msg,arg) { debuglog("listener:", msg, arg) });
|
|
69
|
+
js.t.ioctl_add_listener("term-attach", listener);
|
|
70
|
+
js.t.ioctl_add_listener("term-detach", listener);
|
|
71
|
+
|
|
72
|
+
// remove the listeners:
|
|
73
|
+
js.t.ioctl_remove_listener("term-attach", listener);
|
|
74
|
+
js.t.ioctl_remove_listener("term-detach", listener);
|
|
75
|
+
*
|
|
76
|
+
* Note that js.t.ioctl(...) controls the *terminal* even if attached to a different instance. But
|
|
77
|
+
* ioctl event listeners are attached to an *instance* regardless of what terminal is connected.
|
|
78
|
+
* But in general it does the "right thing" for multiple terminals on a single instance, and when
|
|
79
|
+
* switching among instances.
|
|
80
|
+
*
|
|
81
|
+
*/
|
|
82
|
+
|
|
83
|
+
|
|
21
84
|
/*
|
|
22
85
|
* TermHost
|
|
23
86
|
*
|
|
@@ -27,387 +90,95 @@ gWorkers;
|
|
|
27
90
|
* {
|
|
28
91
|
* type: <string> // target category, e.g. "Host", "api.yyy.com"
|
|
29
92
|
* workerID: <string> // kind of worker in server subsystem
|
|
30
|
-
* dispatcher: <tuple> // dispatcher function for incoming messages
|
|
31
93
|
* startup: <dictionary> // startup options
|
|
32
|
-
* clientID: <string> // (rare) our identification on client
|
|
33
|
-
* serverID: <string> // (rare) server subsystem for us
|
|
34
94
|
* }
|
|
35
95
|
*
|
|
36
96
|
*/
|
|
37
97
|
|
|
38
|
-
closure TermHost(track,
|
|
98
|
+
closure TermHost(track, name, options,
|
|
99
|
+
local relay, error, destID, target, xc)
|
|
39
100
|
{
|
|
40
|
-
global(
|
|
41
|
-
options = merge({
|
|
42
|
-
type: "Host"
|
|
43
|
-
workerID: "myDebugWorker"
|
|
44
|
-
clientID: "DebugWorkers"
|
|
45
|
-
serverID: "Workers"
|
|
46
|
-
}, options)
|
|
47
|
-
target = require("../running/executors.nlg").ExecutorBase(track, options.type, name)
|
|
48
|
-
nlregex = RegExp("\\n", "g")
|
|
49
|
-
target.workerID = options.workerID
|
|
50
|
-
target.msgQueue = []
|
|
51
|
-
target.dispatcher = call(options.dispatcher)
|
|
101
|
+
global(App)
|
|
52
102
|
|
|
53
|
-
//
|
|
103
|
+
// findHostInstance
|
|
54
104
|
//
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
// Connect with the host if not already connected.
|
|
65
|
-
closure connect(local url, pending) {
|
|
66
|
-
if target.ws
|
|
67
|
-
return(list(false, { connected: true }))
|
|
68
|
-
try {
|
|
69
|
-
url = xnew(window.URL, api.url)
|
|
70
|
-
} catch {
|
|
71
|
-
return(list(Error("invalid URL ${api.url}", exception)))
|
|
105
|
+
// Find the host instance name/type, or create new remote worker. The default for no name/type is
|
|
106
|
+
// the server itself.
|
|
107
|
+
//
|
|
108
|
+
function findHostInstance(relay, name, type, local error, found, dest, worker) {
|
|
109
|
+
`(error, found) = relay.clients()
|
|
110
|
+
if !error {
|
|
111
|
+
dest = found.find(function(item) { item.name == "NaanIDE Server" && item.type == "Server IMP" })
|
|
112
|
+
if !dest
|
|
113
|
+
error = Error("cannot locate host")
|
|
72
114
|
}
|
|
73
|
-
if
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
// onopen
|
|
81
|
-
// The WebSocket connection is now open.
|
|
82
|
-
target.ws.onopen = function onopen(e, local info, spawner) {
|
|
83
|
-
info = {
|
|
84
|
-
name: name
|
|
85
|
-
workerID: target.workerID
|
|
115
|
+
if !error
|
|
116
|
+
`(error, found) = relay.clients(dest.destID)
|
|
117
|
+
if !error {
|
|
118
|
+
if name && type {
|
|
119
|
+
dest = found.find(function(item) { item.name == name && item.type == type })
|
|
120
|
+
if dest
|
|
121
|
+
return (list(false, dest.destID)) // found worker
|
|
86
122
|
}
|
|
87
|
-
if
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
spawner = new(options.startup) || { }
|
|
94
|
-
spawner.name = name
|
|
95
|
-
sendControl("spawn", spawner)
|
|
96
|
-
pending.signal(list(false, { ok: true }))
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
// onmessage
|
|
100
|
-
// A message was received from the worker via WebSockets.
|
|
101
|
-
target.ws.onmessage = function onmessage(e, message, local msg) {
|
|
102
|
-
try {
|
|
103
|
-
message = new(window.JSON.parse(e.data))
|
|
104
|
-
} catch {
|
|
105
|
-
if true {
|
|
106
|
-
debuglog("can't decode incoming ws message:", exception)
|
|
107
|
-
return }
|
|
123
|
+
if !name || !type { // find main instance
|
|
124
|
+
dest = found.find(function(item) { item.name == "NaanIDE Server" && item.type == "NaaN Server" })
|
|
125
|
+
if !dest
|
|
126
|
+
return (list(Error("cannot locate NaanIDE Server")))
|
|
127
|
+
else
|
|
128
|
+
return (list(false, dest.destID))
|
|
108
129
|
}
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
dispatcher(message) // request from Host
|
|
132
|
-
else if message.respOp || message.id
|
|
133
|
-
debuglog("unknown host response message:", message.respOp || message.id)
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
// dispatcher
|
|
137
|
-
// Respond to a host request while preserving context to permit reply routing
|
|
138
|
-
closure dispatcher(message) {
|
|
139
|
-
target.dispatcher(message.payload.data, function(reply) {
|
|
140
|
-
target.ws.send(window.JSON.stringify({
|
|
141
|
-
guid: api.guid
|
|
142
|
-
clientID: message.clientID
|
|
143
|
-
serverID: message.serverID
|
|
144
|
-
workerID: message.workerID
|
|
145
|
-
respOp: "msgout"
|
|
146
|
-
payload: {
|
|
147
|
-
id: "targetout",
|
|
148
|
-
data: reply
|
|
149
|
-
}
|
|
150
|
-
}))
|
|
151
|
-
})
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
// onerror
|
|
155
|
-
// An error occurred on the WebSocket connection.
|
|
156
|
-
// This can happen in normal operation when the connection times out.
|
|
157
|
-
target.ws.onerror = function onerror(e) {
|
|
158
|
-
pending.signal(list(Error("websocket failed", e)))
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
// onclose
|
|
162
|
-
// The WebSocket connection was closed.
|
|
163
|
-
target.ws.onclose = function onclose(e) {
|
|
164
|
-
if e.code != 1000 && e.code != 1001 && e.code != 1005 && e.code != 1006
|
|
165
|
-
debuglog("ws close:", e.code, e.reason)
|
|
166
|
-
target.execClosed(Error("socket closed", e.code, e.reason))
|
|
167
|
-
target.ws = false
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
pending.wait()
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
//
|
|
174
|
-
// hostWorkerUpdate
|
|
175
|
-
//
|
|
176
|
-
// New workers created/discovered on this host.
|
|
177
|
-
//
|
|
178
|
-
function hostWorkerUpdate(msg, local localID, worker) {
|
|
179
|
-
if msg.id == "spawned" {
|
|
180
|
-
if !findWorker(msg.workerID)
|
|
181
|
-
TermHost(track, api, msg.name, { type: options.type, workerID: msg.workerID })
|
|
182
|
-
}
|
|
183
|
-
else if msg.id == "termination"
|
|
184
|
-
track.delete(findWorker(msg.workerID))
|
|
185
|
-
else if msg.id == "workerlist" {
|
|
186
|
-
for `(localID, worker) in msg.workers
|
|
187
|
-
if !findWorker(localID)
|
|
188
|
-
TermHost(track, api, worker.name, { type: options.type, workerID: localID })
|
|
189
|
-
}
|
|
190
|
-
}
|
|
191
|
-
|
|
192
|
-
//
|
|
193
|
-
// hostWorkerMatch
|
|
194
|
-
//
|
|
195
|
-
// True iff the specified information matches us.
|
|
196
|
-
//
|
|
197
|
-
target.hostWorkerMatch = function hostWorkerMatch(testApi, testID) {
|
|
198
|
-
testApi === api && testID == target.workerID
|
|
199
|
-
}
|
|
200
|
-
|
|
201
|
-
//
|
|
202
|
-
// doMessage
|
|
203
|
-
//
|
|
204
|
-
// Process the specified undecoded message.
|
|
205
|
-
target.doMessage = function doMessage(msg) {
|
|
206
|
-
if msg.id == "textout" {
|
|
207
|
-
target.written = true
|
|
208
|
-
target.term.Write(msg.text.replace(nlregex, "\r\n")) }
|
|
209
|
-
else if msg.id == "debugtext" {
|
|
210
|
-
target.written = true
|
|
211
|
-
target.debugWrite(msg.text, msg.level) }
|
|
212
|
-
else if msg.id == "targetout"
|
|
213
|
-
target.execReceived(msg.data)
|
|
214
|
-
else if msg.id == "started"
|
|
215
|
-
{ }
|
|
216
|
-
else if msg.id == "typed"
|
|
217
|
-
target.term.Write(msg.text.replace(nlregex, "\r\n"))
|
|
218
|
-
else if msg.id == "status"
|
|
219
|
-
target.statusCB(target, msg.status)
|
|
220
|
-
else if msg.id == "debugout"
|
|
221
|
-
target.debugger.debugData(target, msg.data)
|
|
222
|
-
else
|
|
223
|
-
debuglog("unknown host worker message:", msg.id)
|
|
224
|
-
}
|
|
225
|
-
|
|
226
|
-
//
|
|
227
|
-
// sendControl
|
|
228
|
-
//
|
|
229
|
-
// Send a message to the worker controller.
|
|
230
|
-
|
|
231
|
-
target.sendControl = function sendControl(workerOp, payload) {
|
|
232
|
-
target.ws.send(window.JSON.stringify({
|
|
233
|
-
guid: api.guid
|
|
234
|
-
clientID: options.clientID
|
|
235
|
-
serverID: options.serverID
|
|
236
|
-
workerID: target.workerID
|
|
237
|
-
workerOp: workerOp
|
|
238
|
-
payload: payload
|
|
239
|
-
}))
|
|
240
|
-
}
|
|
241
|
-
|
|
242
|
-
//
|
|
243
|
-
// send
|
|
244
|
-
//
|
|
245
|
-
// Send a message to the worker.
|
|
246
|
-
|
|
247
|
-
target.send = function send(msg) {
|
|
248
|
-
sendControl("msgin", msg)
|
|
249
|
-
}
|
|
250
|
-
|
|
251
|
-
//
|
|
252
|
-
// oninterrupt
|
|
253
|
-
//
|
|
254
|
-
|
|
255
|
-
function oninterrupt() {
|
|
256
|
-
send({ // send interrupt to worker
|
|
257
|
-
id: "interrupt"
|
|
258
|
-
})
|
|
259
|
-
}
|
|
260
|
-
|
|
261
|
-
//
|
|
262
|
-
// onreturn
|
|
263
|
-
//
|
|
264
|
-
|
|
265
|
-
function onreturn(local text) {
|
|
266
|
-
text = target.term.TakeText()
|
|
267
|
-
echotext(text)
|
|
268
|
-
send({ // send user-entered text to worker
|
|
269
|
-
id: "keyline",
|
|
270
|
-
text: text
|
|
271
|
-
})
|
|
272
|
-
}
|
|
273
|
-
|
|
274
|
-
// echotext
|
|
275
|
-
//
|
|
276
|
-
// Echo text to other terminals.
|
|
277
|
-
|
|
278
|
-
function echotext(text) {
|
|
279
|
-
sendControl("echo", { // send user-entered text to worker
|
|
280
|
-
id: "typed",
|
|
281
|
-
text: "\x1b[90m\x1b[3m".concat(text, "\x1b[0m\n") // dark-grey, italic
|
|
282
|
-
})
|
|
283
|
-
}
|
|
284
|
-
|
|
285
|
-
// target.KeyText
|
|
286
|
-
//
|
|
287
|
-
// Send text to the worker, with optional echo to terminal.
|
|
288
|
-
|
|
289
|
-
target.KeyText = function KeyText(text, echo) {
|
|
290
|
-
if echo {
|
|
291
|
-
target.term.WriteLn(text.trim())
|
|
292
|
-
echotext(text.trim())
|
|
130
|
+
dest = found.find(function(item) { item.name == "NaanIDE Server" && item.type == "Node Remote" })
|
|
131
|
+
if !dest
|
|
132
|
+
return (list(Error("cannot locate NaanIDE Server Remote")))
|
|
133
|
+
`(error, xc) = relay.context(dest.destID)
|
|
134
|
+
if !error {
|
|
135
|
+
`(error) = xc.evalq(chns("node"))
|
|
136
|
+
if error
|
|
137
|
+
return (list(Error("cannot switch namespace", error)))
|
|
138
|
+
}
|
|
139
|
+
if !error
|
|
140
|
+
closure (options) {
|
|
141
|
+
`(error, worker) = xc.evalq(NobBot(options), `(options))
|
|
142
|
+
}({
|
|
143
|
+
name: name
|
|
144
|
+
type: options.type
|
|
145
|
+
startup: options.startup
|
|
146
|
+
topOriginID: App.imp.us.instanceID
|
|
147
|
+
})
|
|
148
|
+
if error
|
|
149
|
+
error = Error("cannot spawn remote instance", error)
|
|
150
|
+
else
|
|
151
|
+
return (list(false, worker.instanceID))
|
|
293
152
|
}
|
|
294
|
-
|
|
295
|
-
id: "keyline",
|
|
296
|
-
text: text
|
|
297
|
-
})
|
|
153
|
+
list(error)
|
|
298
154
|
}
|
|
299
155
|
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
// Post a message to the target.
|
|
304
|
-
//
|
|
305
|
-
|
|
306
|
-
target.PostMessage = function PostMessage(data, local result) {
|
|
307
|
-
result = connect()
|
|
308
|
-
if result.0
|
|
309
|
-
return (result)
|
|
310
|
-
send({ // send data to worker
|
|
311
|
-
id: "targetin",
|
|
312
|
-
data: data
|
|
313
|
-
})
|
|
314
|
-
list(false, { posted: true })
|
|
315
|
-
}
|
|
316
|
-
|
|
317
|
-
//
|
|
318
|
-
// target.DebugCmd
|
|
319
|
-
//
|
|
320
|
-
// Post a debug command to the target.
|
|
321
|
-
//
|
|
322
|
-
|
|
323
|
-
target.DebugCmd = function DebugCmd(data) {
|
|
324
|
-
connect()
|
|
325
|
-
send({ // send debug command to worker
|
|
326
|
-
id: "debugin",
|
|
327
|
-
data: data
|
|
328
|
-
})
|
|
329
|
-
}
|
|
156
|
+
options = merge({
|
|
157
|
+
type: "Host"
|
|
158
|
+
}, options)
|
|
330
159
|
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
else if (level >= 3)
|
|
344
|
-
target.term.WriteLn(text, target.term.Red) // light red for warnings
|
|
345
|
-
else if (level >= 2)
|
|
346
|
-
target.term.WriteLn(text, target.term.Green) // green for Naan.debug.debuglog logging
|
|
347
|
-
else
|
|
348
|
-
target.term.WriteLn(text, target.term.Red+target.term.Bold) // heavy red for errors
|
|
349
|
-
}
|
|
160
|
+
target = findIDEtarget(track, name, options.workerID)
|
|
161
|
+
if target
|
|
162
|
+
return (list(false, target)) // already exists
|
|
163
|
+
|
|
164
|
+
relay = require("naanlib:frameworks/client/relaycon.nlg").RelayCon(App.imp)
|
|
165
|
+
if options.workerID == "NideServer" // server main thread
|
|
166
|
+
`(error, destID) = findHostInstance(relay)
|
|
167
|
+
else
|
|
168
|
+
`(error, destID) = findHostInstance(relay, name, options.type)
|
|
169
|
+
relay.close()
|
|
170
|
+
if error
|
|
171
|
+
return (list(error))
|
|
350
172
|
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
target.termAttach = function termAttach(repl, db, statusCB, local msg) {
|
|
357
|
-
target.term = repl
|
|
358
|
-
target.debugger = db
|
|
359
|
-
target.statusCB = statusCB
|
|
360
|
-
if target.termSaved {
|
|
361
|
-
target.term.StateLoad(target.termSaved)
|
|
362
|
-
target.termSaved = false }
|
|
363
|
-
else
|
|
364
|
-
target.term.Reset()
|
|
365
|
-
target.debugger.attach(target)
|
|
366
|
-
while target.msgQueue.length > 0 {
|
|
367
|
-
for msg in target.msgQueue.splice(0) // all current messages
|
|
368
|
-
target.doMessage(msg)
|
|
369
|
-
}
|
|
370
|
-
target.msgQueue = false
|
|
371
|
-
target.term.On("interrupt", oninterrupt.proc)
|
|
372
|
-
target.term.On("return", onreturn.proc)
|
|
373
|
-
target.term.Focus()
|
|
374
|
-
connect() // ensure we are connected
|
|
375
|
-
target
|
|
376
|
-
}
|
|
377
|
-
|
|
378
|
-
//
|
|
379
|
-
// termDetach
|
|
380
|
-
//
|
|
381
|
-
// The terminal is being deattached from our instance.
|
|
382
|
-
|
|
383
|
-
target.termDetach = function termDetach(repl, db) {
|
|
384
|
-
target.term.On("interrupt")
|
|
385
|
-
target.term.On("return")
|
|
386
|
-
target.msgQueue = []
|
|
387
|
-
target.debugger.detach(target)
|
|
388
|
-
target.termSaved = target.term.StateSave()
|
|
389
|
-
target.term.Reset()
|
|
390
|
-
target.statusCB = false
|
|
391
|
-
target.debugger = false
|
|
392
|
-
target.term = false
|
|
393
|
-
}
|
|
394
|
-
|
|
395
|
-
// destroy
|
|
396
|
-
//
|
|
397
|
-
// Destroy the execution instance.
|
|
398
|
-
|
|
399
|
-
target.destroy = function destroy() {
|
|
400
|
-
track.delete(target)
|
|
401
|
-
termDetach()
|
|
402
|
-
sendControl("terminate", { })
|
|
403
|
-
target.ws.close(1000) // 1000: normal close
|
|
404
|
-
}
|
|
173
|
+
target = require("../running/instances.nlg").InTop(track, {
|
|
174
|
+
name: name
|
|
175
|
+
type: options.type
|
|
176
|
+
})
|
|
177
|
+
target.workerID = options.workerID
|
|
405
178
|
|
|
406
|
-
|
|
407
|
-
if
|
|
408
|
-
return (list(
|
|
409
|
-
track.add(target)
|
|
410
|
-
connect() // connect right away to start receiving messages
|
|
179
|
+
`(error) = target.open(destID)
|
|
180
|
+
if error
|
|
181
|
+
return (list(Error("cannot create InTop", error)))
|
|
411
182
|
|
|
412
183
|
// finis
|
|
413
184
|
|
|
@@ -424,14 +195,13 @@ closure TermHost(track, api, name, options, local target, nlregex, xtarg)
|
|
|
424
195
|
* {
|
|
425
196
|
* workerID: <string> // kind of worker in server subsystem
|
|
426
197
|
* // "NaanIDE" for local IDE
|
|
427
|
-
* // "NaanIDE-Debug" for browser debug target
|
|
428
198
|
* startup: <dictionary> // startup options
|
|
429
199
|
* type: <string> // (rare) target category, e.g. "Local"
|
|
430
200
|
* }
|
|
431
201
|
*
|
|
432
202
|
*/
|
|
433
203
|
|
|
434
|
-
closure TermLocal(track, name, options, local target,
|
|
204
|
+
closure TermLocal(track, name, options, local target, worker, inbot, error)
|
|
435
205
|
{
|
|
436
206
|
global(js, window, gWorkers)
|
|
437
207
|
if !dictionary(gWorkers)
|
|
@@ -442,293 +212,28 @@ closure TermLocal(track, name, options, local target, nlregex, listener)
|
|
|
442
212
|
if options.workerID == "NaanIDE" {
|
|
443
213
|
if !js.t
|
|
444
214
|
return (list(Error("Cannot access Local IDE executor")))
|
|
445
|
-
termInstallVirtualWatcher(track,
|
|
215
|
+
termInstallVirtualWatcher(track, window)
|
|
446
216
|
return (termIDE(track, name, options.workerID, js.t)) // connect to IDE execution instance itself
|
|
447
217
|
}
|
|
448
|
-
target = require("../running/executors.nlg").ExecutorBase(track, options.type, name)
|
|
449
|
-
nlregex = RegExp("\\n", "g")
|
|
450
|
-
target.workerID = options.workerID
|
|
451
|
-
target.msgQueue = []
|
|
452
|
-
if options.workerID == "NaanIDE-Debug" {
|
|
453
|
-
target.worker = window.open(window.location.href, "_blank")
|
|
454
|
-
target.worker.addEventListener("beforeunload", function(e) { // our target is closing
|
|
455
|
-
destroy()
|
|
456
|
-
})
|
|
457
|
-
window.addEventListener("beforeunload", function(e) { // we are closing
|
|
458
|
-
// ### tell target we are closing (if needed)
|
|
459
|
-
})
|
|
460
|
-
listener = window
|
|
461
|
-
target.guid = 1
|
|
462
|
-
} else {
|
|
463
|
-
if not window.Worker
|
|
464
|
-
return (list(Error("Local environment does not support workers")))
|
|
465
|
-
target.worker = xnew(window.Worker, "env_webworker.js")
|
|
466
|
-
listener = target.worker
|
|
467
|
-
target.guid = UUID()
|
|
468
|
-
}
|
|
469
|
-
gWorkers[target.guid] = target
|
|
470
218
|
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
listener.addEventListener("message", function(e, msg) {
|
|
475
|
-
msg = new(e.data)
|
|
476
|
-
if msg.id == "termination" {
|
|
477
|
-
destroy()
|
|
478
|
-
return }
|
|
479
|
-
else if msg.id != "targetout" && msg.id != "loaded" {
|
|
480
|
-
if msg.id == "status" {
|
|
481
|
-
target.lastStatus = milliseconds()
|
|
482
|
-
target.execSetStatus(msg.status)
|
|
483
|
-
}
|
|
484
|
-
if target.msgQueue {
|
|
485
|
-
if msg.id != "status"
|
|
486
|
-
target.msgQueue.push(msg)
|
|
487
|
-
return } }
|
|
488
|
-
target.doMessage(msg)
|
|
489
|
-
})
|
|
219
|
+
target = findIDEtarget(track, name, options.workerID)
|
|
220
|
+
if target
|
|
221
|
+
return (list(false, target)) // already exists
|
|
490
222
|
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
target.execClosed(Error("instance error", e.message))
|
|
223
|
+
worker = xnew(window.Worker, "env_webworker.js")
|
|
224
|
+
inbot = NubBot(worker, {
|
|
225
|
+
name: name
|
|
226
|
+
type: options.workerID
|
|
227
|
+
startup: options.startup
|
|
497
228
|
})
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
})
|
|
507
|
-
}
|
|
508
|
-
|
|
509
|
-
//
|
|
510
|
-
// onreturn
|
|
511
|
-
//
|
|
512
|
-
|
|
513
|
-
function onreturn() {
|
|
514
|
-
target.worker.postMessage({ // send user-entered text to worker
|
|
515
|
-
id: "keyline",
|
|
516
|
-
text: target.term.TakeText()
|
|
517
|
-
})
|
|
518
|
-
}
|
|
519
|
-
|
|
520
|
-
// target.KeyText
|
|
521
|
-
//
|
|
522
|
-
// Send text to the worker, with optional echo to terminal.
|
|
523
|
-
|
|
524
|
-
target.KeyText = function KeyText(text, echo) {
|
|
525
|
-
if echo
|
|
526
|
-
target.term.WriteLn(text.trim())
|
|
527
|
-
target.worker.postMessage({ // send text to worker
|
|
528
|
-
id: "keyline",
|
|
529
|
-
text: text
|
|
530
|
-
})
|
|
531
|
-
}
|
|
532
|
-
|
|
533
|
-
//
|
|
534
|
-
// doMessage
|
|
535
|
-
//
|
|
536
|
-
// Process the specified undecoded message.
|
|
537
|
-
|
|
538
|
-
target.doMessage = function doMessage(msg) {
|
|
539
|
-
if msg.id == "textout"
|
|
540
|
-
target.term.Write(msg.text.replace(nlregex, "\r\n"))
|
|
541
|
-
else if msg.id == "debugtext"
|
|
542
|
-
target.debugWrite(msg.text, msg.level)
|
|
543
|
-
else if msg.id == "targetout"
|
|
544
|
-
target.execReceived(msg.data)
|
|
545
|
-
else if msg.id == "status"
|
|
546
|
-
target.statusCB(target, msg.status)
|
|
547
|
-
else if msg.id == "debugout"
|
|
548
|
-
target.debugger.debugData(target, msg.data)
|
|
549
|
-
else if msg.id == "download"
|
|
550
|
-
FileDownload(xnew(window.File, msg.bits, msg.name, msg.options))
|
|
551
|
-
else if msg.id == "loaded" {
|
|
552
|
-
if !target.started
|
|
553
|
-
target.worker.postMessage({
|
|
554
|
-
id: "start",
|
|
555
|
-
state: false // resume state, if we have any
|
|
556
|
-
altcmd: options.startup.initcmds
|
|
557
|
-
workerID: target.workerID
|
|
558
|
-
workerGUID: target.guid
|
|
559
|
-
})
|
|
560
|
-
target.started = true
|
|
561
|
-
} else if msg.id == "targetsend" {
|
|
562
|
-
msg.data._guid = target.guid
|
|
563
|
-
js.t.DispatchMessage(msg.data)
|
|
564
|
-
}
|
|
565
|
-
}
|
|
566
|
-
|
|
567
|
-
//
|
|
568
|
-
// target.DebugCmd
|
|
569
|
-
//
|
|
570
|
-
// Post a debug command to the target.
|
|
571
|
-
//
|
|
572
|
-
|
|
573
|
-
target.DebugCmd = function DebugCmd(data) {
|
|
574
|
-
target.worker.postMessage({ // send data to worker
|
|
575
|
-
id: "debugin"
|
|
576
|
-
data: data
|
|
577
|
-
})
|
|
578
|
-
}
|
|
579
|
-
|
|
580
|
-
//
|
|
581
|
-
// target.PostMessage
|
|
582
|
-
//
|
|
583
|
-
// Post a message to the target, if it has registered a listener.
|
|
584
|
-
//
|
|
585
|
-
|
|
586
|
-
target.PostMessage = function PostMessage(data) {
|
|
587
|
-
target.worker.postMessage({ // send data to worker
|
|
588
|
-
id: "targetin",
|
|
589
|
-
data: data
|
|
590
|
-
})
|
|
591
|
-
list(false, { posted: true })
|
|
592
|
-
}
|
|
593
|
-
|
|
594
|
-
//
|
|
595
|
-
// target.debugWrite
|
|
596
|
-
//
|
|
597
|
-
// Write a debug message to the repl.
|
|
598
|
-
//
|
|
599
|
-
|
|
600
|
-
target.debugWrite = function(text, level) {
|
|
601
|
-
text = text.replaceAll("\n", "\r\n")
|
|
602
|
-
if (level >= 5)
|
|
603
|
-
target.term.WriteLn(text, target.term.Cyan) // cyan for builtin logging
|
|
604
|
-
else if (level >= 4)
|
|
605
|
-
target.term.WriteLn(text, target.term.Blue) // blue for Naan function logging
|
|
606
|
-
else if (level >= 3)
|
|
607
|
-
target.term.WriteLn(text, target.term.Red) // light red for warnings
|
|
608
|
-
else if (level >= 2)
|
|
609
|
-
target.term.WriteLn(text, target.term.Green) // green for Naan.debug.debuglog logging
|
|
610
|
-
else
|
|
611
|
-
target.term.WriteLn(text, target.term.Red+target.term.Bold) // heavy red for errors
|
|
612
|
-
}
|
|
613
|
-
|
|
614
|
-
//
|
|
615
|
-
// termAttach
|
|
616
|
-
//
|
|
617
|
-
// A terminal was attached to our instance.
|
|
618
|
-
|
|
619
|
-
target.termAttach = function termAttach(repl, db, statusCB, local msg) {
|
|
620
|
-
target.term = repl
|
|
621
|
-
target.debugger = db
|
|
622
|
-
target.statusCB = statusCB
|
|
623
|
-
if target.termSaved {
|
|
624
|
-
target.term.StateLoad(target.termSaved)
|
|
625
|
-
target.termSaved = false }
|
|
626
|
-
else
|
|
627
|
-
target.term.Reset()
|
|
628
|
-
target.debugger.attach(target)
|
|
629
|
-
while target.msgQueue.length > 0 {
|
|
630
|
-
for msg in target.msgQueue.splice(0) // all current messages
|
|
631
|
-
target.doMessage(msg)
|
|
632
|
-
}
|
|
633
|
-
target.msgQueue = false
|
|
634
|
-
target.term.On("interrupt", oninterrupt.proc)
|
|
635
|
-
target.term.On("return", onreturn.proc)
|
|
636
|
-
target.term.Focus()
|
|
637
|
-
target
|
|
638
|
-
}
|
|
639
|
-
|
|
640
|
-
//
|
|
641
|
-
// termDetach
|
|
642
|
-
//
|
|
643
|
-
// The terminal is being deattached from our instance.
|
|
644
|
-
|
|
645
|
-
target.termDetach = function termDetach() {
|
|
646
|
-
target.term.On("interrupt")
|
|
647
|
-
target.term.On("return")
|
|
648
|
-
target.msgQueue = []
|
|
649
|
-
target.debugger.detach(target)
|
|
650
|
-
target.termSaved = target.term.StateSave()
|
|
651
|
-
target.statusCB = false
|
|
652
|
-
target.debugger = false
|
|
653
|
-
target.term = false
|
|
654
|
-
}
|
|
655
|
-
|
|
656
|
-
// destroy
|
|
657
|
-
//
|
|
658
|
-
// Destroy the execution instance.
|
|
659
|
-
|
|
660
|
-
target.destroy = function destroy() {
|
|
661
|
-
gWorkers[target.guid] = undefined
|
|
662
|
-
target.execClosed(Error("instance destroyed"))
|
|
663
|
-
track.delete(target)
|
|
664
|
-
termDetach()
|
|
665
|
-
target.worker.terminate() // kill without saving
|
|
666
|
-
target.worker = false
|
|
667
|
-
}
|
|
668
|
-
|
|
669
|
-
track.add(target)
|
|
670
|
-
|
|
671
|
-
// finis
|
|
672
|
-
|
|
673
|
-
list(false, target)
|
|
674
|
-
};
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
/*
|
|
678
|
-
* WorkerConnect
|
|
679
|
-
*
|
|
680
|
-
* Return the existing web worker for a workerGUID, or false if it does not exist.
|
|
681
|
-
*
|
|
682
|
-
*/
|
|
683
|
-
|
|
684
|
-
function WorkerConnect(workerGUID) {
|
|
685
|
-
gWorkers[workerGUID]
|
|
686
|
-
};
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
/*
|
|
690
|
-
* termMainProxy
|
|
691
|
-
*
|
|
692
|
-
* Make a browser proxy representing the main thread. This runs inside the worker and allows it
|
|
693
|
-
* to do remote execution with Main.
|
|
694
|
-
*
|
|
695
|
-
*/
|
|
696
|
-
|
|
697
|
-
closure termMainProxy(track, name, options, local target) {
|
|
698
|
-
global(js)
|
|
699
|
-
target = require("../running/executors.nlg").ExecutorBase(track, "mainProxy", name)
|
|
700
|
-
target.name = name
|
|
701
|
-
|
|
702
|
-
//
|
|
703
|
-
// target.PostMessage
|
|
704
|
-
//
|
|
705
|
-
// Post a message to the main thread.
|
|
706
|
-
//
|
|
707
|
-
target.PostMessage = function PostMessage(data) {
|
|
708
|
-
js.t.DispatchMessage(data)
|
|
709
|
-
list(false, { posted: true })
|
|
710
|
-
}
|
|
711
|
-
|
|
712
|
-
//
|
|
713
|
-
// onreceive
|
|
714
|
-
//
|
|
715
|
-
// Process a received message from the main thread, typically in response.
|
|
716
|
-
//
|
|
717
|
-
function onreceive(data) {
|
|
718
|
-
target.execReceived(data)
|
|
719
|
-
}
|
|
720
|
-
|
|
721
|
-
// destroy
|
|
722
|
-
//
|
|
723
|
-
// Destroy the execution instance.
|
|
724
|
-
//
|
|
725
|
-
target.destroy = function destroy() {
|
|
726
|
-
target.execClosed(Error("instance destroyed"))
|
|
727
|
-
track.delete(target)
|
|
728
|
-
}
|
|
729
|
-
|
|
730
|
-
js.t.OnReceive(onreceive.proc)
|
|
731
|
-
track.add(target)
|
|
229
|
+
target = require("../running/instances.nlg").InTop(track, {
|
|
230
|
+
name: name
|
|
231
|
+
type: options.type
|
|
232
|
+
workerID: options.workerID
|
|
233
|
+
})
|
|
234
|
+
`(error) = target.open(inbot.instanceID)
|
|
235
|
+
if error
|
|
236
|
+
return (list(Error("cannot create InTop", error)))
|
|
732
237
|
|
|
733
238
|
// finis
|
|
734
239
|
|
|
@@ -736,42 +241,21 @@ closure termMainProxy(track, name, options, local target) {
|
|
|
736
241
|
};
|
|
737
242
|
|
|
738
243
|
|
|
739
|
-
/*
|
|
740
|
-
* WorkerToMain
|
|
741
|
-
*
|
|
742
|
-
* Connect our worker to the main thread, returning a result tuple with an executor representing
|
|
743
|
-
* Main. Use this to create a context object for Main, allowing remote evaluation.
|
|
744
|
-
*
|
|
745
|
-
*/
|
|
746
|
-
|
|
747
|
-
closure WorkerToMain(local nideRunning, track) {
|
|
748
|
-
// mainProxy -- link tracker to main thread proxy
|
|
749
|
-
function mainProxy(track, name, options) {
|
|
750
|
-
termMainProxy(track, name, options)
|
|
751
|
-
}
|
|
752
|
-
|
|
753
|
-
if !js.s {
|
|
754
|
-
error = Error("WorkerToMain only available in browser workers")
|
|
755
|
-
return (list(error))
|
|
756
|
-
}
|
|
757
|
-
nideRunning = require("naanlib:frameworks/running/executors.nlg")
|
|
758
|
-
track = nideRunning.ExecutorTracker()
|
|
759
|
-
track.register(mainProxy, "proxy")
|
|
760
|
-
track.spawn("proxy") // returns result tuple
|
|
761
|
-
};
|
|
762
|
-
|
|
763
|
-
|
|
764
244
|
/*
|
|
765
245
|
* findIDEtarget
|
|
766
246
|
*
|
|
767
|
-
* Find a target for our IDE that matches the specified name, workerID, and naancont.
|
|
247
|
+
* Find a target for our IDE that matches the specified name, workerID, and naancont. Either the
|
|
248
|
+
* title or the naancont must match. The title will match but not the naancont if the window was
|
|
249
|
+
* closed/reloaded but we didn't get notified because browsers are annoying that way. Alternatively
|
|
250
|
+
* the naancont will match but not the title if we have updated the version.
|
|
768
251
|
*
|
|
769
252
|
*/
|
|
770
253
|
|
|
771
|
-
closure findIDEtarget(track, name, workerID, naancont, local target) {
|
|
254
|
+
closure findIDEtarget(track, name, workerID, title, naancont, local target) {
|
|
772
255
|
global()
|
|
773
256
|
for target in track.enumlist()
|
|
774
|
-
if target.name == name && target.workerID == workerID
|
|
257
|
+
if target.name == name && target.workerID == workerID
|
|
258
|
+
&& (target.title == title || !target.naancont || target.naancont === naancont)
|
|
775
259
|
return (target)
|
|
776
260
|
false
|
|
777
261
|
};
|
|
@@ -788,8 +272,10 @@ closure findIDEtarget(track, name, workerID, naancont, local target) {
|
|
|
788
272
|
|
|
789
273
|
closure termIDE(track, name, workerID, naancont, title, local target, connected) {
|
|
790
274
|
global(js, gWorkers)
|
|
791
|
-
target = findIDEtarget(track, name, workerID, naancont)
|
|
275
|
+
target = findIDEtarget(track, name, workerID, title, naancont)
|
|
792
276
|
if target { // new naancont on existing target
|
|
277
|
+
if target.naancont && naancont !== target.naancont
|
|
278
|
+
target.targetClose()
|
|
793
279
|
target.updateController(naancont)
|
|
794
280
|
target.title = title
|
|
795
281
|
track.update(target)
|
|
@@ -800,6 +286,7 @@ closure termIDE(track, name, workerID, naancont, title, local target, connected)
|
|
|
800
286
|
target.title = title
|
|
801
287
|
target.workerID = workerID
|
|
802
288
|
target.naancont = naancont
|
|
289
|
+
naancont.ioctl_open(ioctl_callback.proc)
|
|
803
290
|
connected = []
|
|
804
291
|
|
|
805
292
|
// replyHook
|
|
@@ -814,6 +301,20 @@ closure termIDE(track, name, workerID, naancont, title, local target, connected)
|
|
|
814
301
|
})
|
|
815
302
|
}
|
|
816
303
|
|
|
304
|
+
// ioctl_callback
|
|
305
|
+
//
|
|
306
|
+
// Ioctl from our instance.
|
|
307
|
+
//
|
|
308
|
+
function ioctl_callback(op, arg) { // where ioctls go when they have nowhere to go
|
|
309
|
+
debuglog("no-terminal ioctl:", op, arg)
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
// ioctl_event
|
|
313
|
+
//
|
|
314
|
+
target.ioctl_event = function ioctl_event(msg, arg) {
|
|
315
|
+
naancont.ioctl_event(msg, arg)
|
|
316
|
+
}
|
|
317
|
+
|
|
817
318
|
// target.DebugCmd
|
|
818
319
|
//
|
|
819
320
|
// Post a debug command to the target, ourselves.
|
|
@@ -835,15 +336,16 @@ closure termIDE(track, name, workerID, naancont, title, local target, connected)
|
|
|
835
336
|
//
|
|
836
337
|
// Create a closure for an attaching terminal.
|
|
837
338
|
//
|
|
838
|
-
target.termAttach = closure termAttach(term, db,
|
|
339
|
+
target.termAttach = closure termAttach(term, db, notify, local connection, jsterm, inbound) {
|
|
839
340
|
connection = new(object, this)
|
|
341
|
+
jsterm = term.jsAcquire() // termIDE must be direct
|
|
840
342
|
|
|
841
343
|
function oninterrupt() {
|
|
842
344
|
naancont.Interrupt(inbound)
|
|
843
345
|
}
|
|
844
346
|
|
|
845
347
|
function onreturn() {
|
|
846
|
-
naancont.Return(
|
|
348
|
+
naancont.Return(jsterm.TakeText(), inbound)
|
|
847
349
|
}
|
|
848
350
|
|
|
849
351
|
function onstatus(status) {
|
|
@@ -861,7 +363,7 @@ closure termIDE(track, name, workerID, naancont, title, local target, connected)
|
|
|
861
363
|
|
|
862
364
|
connection.KeyText = function KeyText(text, echo) { // send text to instance
|
|
863
365
|
if echo
|
|
864
|
-
|
|
366
|
+
jsterm.WriteLn(text.trim()) // echo to terminal
|
|
865
367
|
naancont.Return(text, inbound)
|
|
866
368
|
}
|
|
867
369
|
|
|
@@ -871,16 +373,15 @@ closure termIDE(track, name, workerID, naancont, title, local target, connected)
|
|
|
871
373
|
}
|
|
872
374
|
|
|
873
375
|
connection.WriteLn = function WriteLn(text) {
|
|
874
|
-
|
|
376
|
+
jsterm.WriteLn(text)
|
|
875
377
|
}
|
|
876
378
|
|
|
877
379
|
connection.termDetach = function termDetach() { // disconnect the terminal
|
|
878
380
|
db.detach(target)
|
|
879
|
-
term.On("interrupt")
|
|
880
|
-
term.On("return")
|
|
881
381
|
if inbound
|
|
882
382
|
naancont.Detach(inbound)
|
|
883
383
|
connected = connected.filter(function(conn) { conn !== connection })
|
|
384
|
+
term.jsRelease()
|
|
884
385
|
}
|
|
885
386
|
|
|
886
387
|
connection.popup = true // we can handle multiple terminals
|
|
@@ -888,15 +389,15 @@ closure termIDE(track, name, workerID, naancont, title, local target, connected)
|
|
|
888
389
|
let (replstate) {
|
|
889
390
|
replstate = naancont.StateGet()
|
|
890
391
|
if (replstate)
|
|
891
|
-
|
|
392
|
+
jsterm.StateLoad(replstate)
|
|
892
393
|
else
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
394
|
+
jsterm.Reset()
|
|
395
|
+
jsterm.On("interrupt", oninterrupt.proc)
|
|
396
|
+
jsterm.On("return", onreturn.proc)
|
|
397
|
+
jsterm.Focus()
|
|
897
398
|
inbound = xnew({
|
|
898
|
-
OnMessage:
|
|
899
|
-
StateSave:
|
|
399
|
+
OnMessage: jsterm.OnMessage
|
|
400
|
+
StateSave: jsterm.StateSave
|
|
900
401
|
OnStatus: onstatus.proc
|
|
901
402
|
OnMessageOut: onmessageout.proc
|
|
902
403
|
OnDebugOut: ondebugout.proc
|
|
@@ -907,7 +408,33 @@ closure termIDE(track, name, workerID, naancont, title, local target, connected)
|
|
|
907
408
|
connected.push(connection)
|
|
908
409
|
db.attach(target)
|
|
909
410
|
} ()
|
|
910
|
-
|
|
411
|
+
|
|
412
|
+
naancont.ioctl_open(function (op, arg) {
|
|
413
|
+
if op == "sane"
|
|
414
|
+
jsterm.Sane()
|
|
415
|
+
else if op == "raw" {
|
|
416
|
+
if arg // enable raw mode
|
|
417
|
+
jsterm.OnRaw(function(str, origin) {
|
|
418
|
+
ioctl_event("raw-key", {
|
|
419
|
+
key: str
|
|
420
|
+
origin: origin
|
|
421
|
+
})
|
|
422
|
+
})
|
|
423
|
+
else // else disable raw
|
|
424
|
+
jsterm.OnRaw()
|
|
425
|
+
} else if op == "keystroke"
|
|
426
|
+
jsterm.PutKey(arg) // simulate a keystroke
|
|
427
|
+
else if op == "echo"
|
|
428
|
+
jsterm.EchoSet(arg) // echo: 0, 1, 2
|
|
429
|
+
})
|
|
430
|
+
|
|
431
|
+
jsterm.OnResize(function(columns, rows) {
|
|
432
|
+
ioctl_event("term-resize", {
|
|
433
|
+
cols: columns
|
|
434
|
+
rows: rows
|
|
435
|
+
})
|
|
436
|
+
})
|
|
437
|
+
|
|
911
438
|
// finis
|
|
912
439
|
connection
|
|
913
440
|
}
|
|
@@ -917,7 +444,9 @@ closure termIDE(track, name, workerID, naancont, title, local target, connected)
|
|
|
917
444
|
// Update the naan controller on this target, which means updating for all the terminals.
|
|
918
445
|
//
|
|
919
446
|
target.updateController = function updateController(newnc, local conn) {
|
|
447
|
+
naancont.ioctl_close()
|
|
920
448
|
naancont = newnc
|
|
449
|
+
naancont.ioctl_open(ioctl_callback.proc)
|
|
921
450
|
target.naancont = newnc
|
|
922
451
|
for conn in connected {
|
|
923
452
|
if naancont {
|
|
@@ -934,12 +463,13 @@ closure termIDE(track, name, workerID, naancont, title, local target, connected)
|
|
|
934
463
|
//
|
|
935
464
|
// Mark the target window as closed.
|
|
936
465
|
//
|
|
937
|
-
function targetClose(local conn) {
|
|
466
|
+
target.targetClose = function targetClose(local conn) {
|
|
938
467
|
for conn in connected {
|
|
939
468
|
conn.db.detach(target)
|
|
940
469
|
conn.WriteLn("\x1b[90m\x1b[3m".concat("\ntarget closed", "\x1b[0m"))
|
|
941
470
|
}
|
|
942
471
|
target.execReset()
|
|
472
|
+
naancont.ioctl_close()
|
|
943
473
|
target.naancont = naancont = false
|
|
944
474
|
}
|
|
945
475
|
|
|
@@ -1012,12 +542,12 @@ closure termInstallVirtualWatcher(track, naancont) {
|
|
|
1012
542
|
target.attention()
|
|
1013
543
|
}
|
|
1014
544
|
else if msg.op == "VsiteClose" {
|
|
1015
|
-
target = findIDEtarget(track, msg.name, "NaanVsite", msg.naancont)
|
|
545
|
+
target = findIDEtarget(track, msg.name, "NaanVsite", msg.title, msg.naancont)
|
|
1016
546
|
if target
|
|
1017
547
|
target.updateController()
|
|
1018
548
|
}
|
|
1019
549
|
else if msg.op == "VsiteVisibilityChange" {
|
|
1020
|
-
target = findIDEtarget(track, msg.name, "NaanVsite", msg.naancont)
|
|
550
|
+
target = findIDEtarget(track, msg.name, "NaanVsite", msg.title, msg.naancont)
|
|
1021
551
|
if target
|
|
1022
552
|
target.setCheckStatus(msg.hidden, msg.window)
|
|
1023
553
|
}
|
|
@@ -1027,6 +557,120 @@ closure termInstallVirtualWatcher(track, naancont) {
|
|
|
1027
557
|
};
|
|
1028
558
|
|
|
1029
559
|
|
|
560
|
+
/*
|
|
561
|
+
* testTab
|
|
562
|
+
*
|
|
563
|
+
* Quick test of the InTop/InBot connection.
|
|
564
|
+
*
|
|
565
|
+
*/
|
|
566
|
+
|
|
567
|
+
closure testTab(destID,
|
|
568
|
+
local comMod, relay, error, found, dest, xc, inbotDestID, intop) {
|
|
569
|
+
|
|
570
|
+
// findBottomID
|
|
571
|
+
//
|
|
572
|
+
// Find the inbot destID that goes with our desired workerID.
|
|
573
|
+
//
|
|
574
|
+
function findBottomID(found, workerID, local item) {
|
|
575
|
+
for item in found
|
|
576
|
+
if item.name == "Play" && item.type == workerID
|
|
577
|
+
return (item.destID)
|
|
578
|
+
false
|
|
579
|
+
}
|
|
580
|
+
|
|
581
|
+
comMod = require("naanlib:frameworks/client/relaycon.nlg")
|
|
582
|
+
relay = comMod.RelayCon(App.imp)
|
|
583
|
+
`(error, found) = relay.clients(destID)
|
|
584
|
+
dest = found.find(function(item) { item.name == "NaanIDE" && item.services.indexOf("naan-remote-responder") >= 0 })
|
|
585
|
+
if !dest
|
|
586
|
+
return (list(Error("cannot locate remoting")))
|
|
587
|
+
`(error, xc)= relay.context(dest.destID)
|
|
588
|
+
if error
|
|
589
|
+
return (list(Error("cannot access remoting", error)))
|
|
590
|
+
inbotDestID = findBottomID(found, "Webworker-Play")
|
|
591
|
+
if !inbotDestID
|
|
592
|
+
return (list(Error("cannot find web worker")))
|
|
593
|
+
intop = require("../running/instances.nlg").InTop(App.nide.track, {
|
|
594
|
+
name: "NaanIDE-Play"
|
|
595
|
+
type: "Relay"
|
|
596
|
+
})
|
|
597
|
+
`(error) = intop.open(inbotDestID)
|
|
598
|
+
if error
|
|
599
|
+
return (list(Error("cannot create InTop", error)))
|
|
600
|
+
list(false, xc, intop)
|
|
601
|
+
};
|
|
602
|
+
|
|
603
|
+
|
|
604
|
+
/*
|
|
605
|
+
* relayTab
|
|
606
|
+
*
|
|
607
|
+
* Open a relay tab for the first peer NaanIDE found on the same server.
|
|
608
|
+
*
|
|
609
|
+
*/
|
|
610
|
+
|
|
611
|
+
closure relayTab(destID, local comMod, relay, error, found, dest, xc, reterm, originID, inbot) {
|
|
612
|
+
|
|
613
|
+
// remoteFindTerm
|
|
614
|
+
//
|
|
615
|
+
// Executes on remote to give us a (proxy) terminal.
|
|
616
|
+
//
|
|
617
|
+
function remoteFindTerm(name, workerID, local target) {
|
|
618
|
+
for target in App.nide.track.enumlist()
|
|
619
|
+
if target.name == name && target.workerID == workerID
|
|
620
|
+
return (target)
|
|
621
|
+
false
|
|
622
|
+
}
|
|
623
|
+
|
|
624
|
+
comMod = require("naanlib:frameworks/client/relaycon.nlg")
|
|
625
|
+
relay = comMod.RelayCon(App.imp)
|
|
626
|
+
if !destID {
|
|
627
|
+
`(error, found) = relay.clients()
|
|
628
|
+
if !error {
|
|
629
|
+
dest = found.find(function(item) { item.name == "NaanIDE Server" && item.type == "Server IMP" })
|
|
630
|
+
if !dest
|
|
631
|
+
error = Error("cannot locate server")
|
|
632
|
+
}
|
|
633
|
+
if !error
|
|
634
|
+
`(error, found) = relay.clients(dest.destID)
|
|
635
|
+
if !error {
|
|
636
|
+
dest = found.find(function(item) { item.name == "NaanIDE"
|
|
637
|
+
&& item.type == "Client IMP" && item.destID != App.imp.us.instanceID })
|
|
638
|
+
if !dest
|
|
639
|
+
error = Error("cannot locate peer tab")
|
|
640
|
+
else
|
|
641
|
+
destID = dest.destID
|
|
642
|
+
}
|
|
643
|
+
}
|
|
644
|
+
if error
|
|
645
|
+
return (list(Error("cannot locate target", error)))
|
|
646
|
+
`(error, xc) = relay.context(destID)
|
|
647
|
+
if error
|
|
648
|
+
return (list(Error("cannot access remoting", error)))
|
|
649
|
+
`(error) = xc.evalq(chns("browser"))
|
|
650
|
+
if error
|
|
651
|
+
return (list(Error("cannot switch namespace", error)))
|
|
652
|
+
`(error, reterm) = xc.evalq(remoteFindTerm("NaanIDE", "NaanIDE"), `(remoteFindTerm))
|
|
653
|
+
if error
|
|
654
|
+
return (list(Error("cannot get remote terminal", error)))
|
|
655
|
+
originID = App.imp.us.instanceID
|
|
656
|
+
`(error, inbot) = xc.evalq(InBot(window, {
|
|
657
|
+
name: "inbot"
|
|
658
|
+
type: reterm.workerID
|
|
659
|
+
topOriginID: originID
|
|
660
|
+
}), `(reterm, originID))
|
|
661
|
+
if error
|
|
662
|
+
return (list(Error("cannot create inBot", error)))
|
|
663
|
+
intop = require("../running/instances.nlg").InTop(App.nide.track, {
|
|
664
|
+
name: "NaanIDE Relay"
|
|
665
|
+
type: "Relay"
|
|
666
|
+
})
|
|
667
|
+
`(error) = intop.open(inbot.instanceID)
|
|
668
|
+
if error
|
|
669
|
+
return (list(Error("cannot create InTop", error)))
|
|
670
|
+
list(false, xc, intop)
|
|
671
|
+
};
|
|
672
|
+
|
|
673
|
+
|
|
1030
674
|
/*
|
|
1031
675
|
* termInit
|
|
1032
676
|
*
|
|
@@ -1035,15 +679,13 @@ closure termInstallVirtualWatcher(track, naancont) {
|
|
|
1035
679
|
*/
|
|
1036
680
|
|
|
1037
681
|
function termInit(local manifest) {
|
|
1038
|
-
manifest = `(TermHost, TermLocal,
|
|
1039
|
-
termIDE, termInstallVirtualWatcher, termInit)
|
|
682
|
+
manifest = `(TermHost, TermLocal,
|
|
683
|
+
findIDEtarget, termIDE, termInstallVirtualWatcher, testTab, relayTab, termInit)
|
|
1040
684
|
|
|
1041
685
|
Naan.module.build(module.id, "terminals", function(modobj, compobj) {
|
|
1042
|
-
require("./
|
|
686
|
+
require("./worker.nlg")
|
|
1043
687
|
compobj.manifest = manifest
|
|
1044
688
|
modobj.exports.TermLocal = TermLocal
|
|
1045
689
|
modobj.exports.TermHost = TermHost
|
|
1046
|
-
modobj.exports.WorkerConnect = WorkerConnect
|
|
1047
|
-
modobj.exports.WorkerToMain = WorkerToMain
|
|
1048
690
|
})
|
|
1049
691
|
} ();
|