@naanlang/naan 1.6.0 → 1.7.1
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 +1 -1
- package/README.md +1 -1
- package/bin/index.js +2 -2
- package/dist/env_web.js +3 -32
- package/dist/naan.min.js +10 -10
- package/frameworks/browser/sworker.js +23 -23
- package/frameworks/browser/terminals.nlg +161 -212
- package/frameworks/browser/worker.nlg +78 -30
- package/frameworks/browser/workers.nlg +1 -1
- package/frameworks/browser/ws_client.nlg +23 -87
- package/frameworks/client/apiclient.nlg +91 -58
- package/frameworks/client/client.nlg +22 -2
- package/frameworks/client/psm_client.nlg +10 -14
- package/frameworks/client/relaycon.nlg +1 -1
- package/frameworks/common/common.nlg +13 -9
- package/frameworks/node/apiserver.nlg +1 -2
- package/frameworks/node/node.nlg +1 -0
- package/frameworks/node/pty.nlg +21 -21
- package/frameworks/node/shell.nlg +26 -3
- package/frameworks/node/worker.nlg +166 -84
- package/frameworks/node/ws_client.nlg +25 -84
- package/frameworks/project/build.nlg +83 -32
- package/frameworks/project/projects.nlg +2 -2
- package/frameworks/running/debugcom.nlg +20 -3
- package/frameworks/running/debugnub.nlg +16 -7
- package/frameworks/running/executors.nlg +36 -26
- package/frameworks/running/instances.nlg +34 -22
- package/frameworks/running/remote_req.nlg +6 -9
- package/frameworks/running/remote_res.nlg +2 -2
- package/frameworks/running/sourcecode.nlg +3 -2
- package/frameworks/running/taskexec.nlg +14 -57
- package/frameworks/service/imp.nlg +37 -5
- package/frameworks/service/nubnode.nlg +39 -8
- package/frameworks/service/nubweb.nlg +28 -10
- package/frameworks/storage/file_manager.nlg +3 -2
- package/lib/browser/env_web.js +10 -39
- package/lib/browser/env_webworker.js +1 -30
- package/lib/core/naanlib.js +10 -10
- package/lib/env_node.js +5 -22
- package/lib/env_nodeworker.js +8 -43
- 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/test/test_01_core.nlg +2 -2
- package/test/test_02_context.nlg +8 -8
- package/test/test_03_jsinterop.nlg +3 -3
- package/test/test_07_lingo.nlg +1 -1
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* worker.nlg
|
|
3
3
|
* Naanlib/frameworks/browser
|
|
4
4
|
*
|
|
5
|
-
* Manage NaaN instances.
|
|
5
|
+
* Manage web-based NaaN instances.
|
|
6
6
|
*
|
|
7
7
|
* NaaN instances are managed by a top/bottom pair of of objects. InBot (INstance BOTtom) objects
|
|
8
8
|
* reside in the same JavaScript environment (node/browser) as their worker and communicate with the
|
|
@@ -24,7 +24,8 @@
|
|
|
24
24
|
*
|
|
25
25
|
* Create a remote interface for a single execution instance, returning the object. This provides
|
|
26
26
|
* instance access to zero or more InTops via IMP connections. The tops subscribe to receive
|
|
27
|
-
* notifications/responses.
|
|
27
|
+
* notifications/responses. This runs in the main thread and communicates with the worker via the
|
|
28
|
+
* standard JS messaging interface.
|
|
28
29
|
*
|
|
29
30
|
* Options:
|
|
30
31
|
* {
|
|
@@ -32,7 +33,6 @@
|
|
|
32
33
|
* type: <string> // target category, e.g. "Local"
|
|
33
34
|
* startup: <dictionary> // startup options
|
|
34
35
|
* workerID: <string> // initialize worker with this
|
|
35
|
-
* workerGUID: <string> // initialize worker with this
|
|
36
36
|
* topOriginID: <string> // so top can route to us through IMP
|
|
37
37
|
* }
|
|
38
38
|
*
|
|
@@ -49,7 +49,7 @@ closure InBot(worker, options, local inbot)
|
|
|
49
49
|
inbot.workerID = options.workerID
|
|
50
50
|
inbot.worker = worker
|
|
51
51
|
|
|
52
|
-
inbot.instanceID =
|
|
52
|
+
inbot.instanceID = App.imp.getUUID("InBot(${options.name}) instanceID")
|
|
53
53
|
inbot.sender = App.imp.register(inbot, {
|
|
54
54
|
name: options.name
|
|
55
55
|
type: options.type
|
|
@@ -133,9 +133,9 @@ closure InBot(worker, options, local inbot)
|
|
|
133
133
|
// A message was received from the worker.
|
|
134
134
|
//
|
|
135
135
|
inbot.worker.addEventListener("message", function(e, local msg) {
|
|
136
|
-
msg =
|
|
137
|
-
if msg.scope == "naan-imp-
|
|
138
|
-
inbot.impconn.dispatch(msg.data)
|
|
136
|
+
msg = e.data
|
|
137
|
+
if msg.scope == "naan-imp-out" {
|
|
138
|
+
inbot.impconn.dispatch(new(msg.data))
|
|
139
139
|
return
|
|
140
140
|
}
|
|
141
141
|
if msg.scope != "naan-env-web"
|
|
@@ -148,10 +148,10 @@ closure InBot(worker, options, local inbot)
|
|
|
148
148
|
state: false // resume state, if we have any
|
|
149
149
|
altcmd: options.startup.initcmds
|
|
150
150
|
workerID: options.workerID
|
|
151
|
-
workerGUID: options.workerGUID
|
|
152
151
|
metadata: {
|
|
153
152
|
mainInstanceID: App.imp.us.instanceID
|
|
154
153
|
name: options.name
|
|
154
|
+
maintext: options.startup.maintext.concat("\n")
|
|
155
155
|
}
|
|
156
156
|
})
|
|
157
157
|
inbot.started = true
|
|
@@ -164,15 +164,29 @@ closure InBot(worker, options, local inbot)
|
|
|
164
164
|
// The worker had an error.
|
|
165
165
|
//
|
|
166
166
|
inbot.worker.addEventListener("error", function(e) {
|
|
167
|
-
debuglog("worker error:", e.message)
|
|
167
|
+
debuglog("worker error:", e.message, "in", e.filename, "at", e.lineno)
|
|
168
168
|
notifyAll({
|
|
169
169
|
id: "error"
|
|
170
|
-
data:
|
|
170
|
+
data: {
|
|
171
|
+
message: e.message
|
|
172
|
+
filename: e.filename
|
|
173
|
+
lineno: e.lineno
|
|
174
|
+
}
|
|
171
175
|
})
|
|
172
176
|
inbot.worker = false
|
|
173
177
|
destroy()
|
|
174
178
|
})
|
|
175
179
|
|
|
180
|
+
// close
|
|
181
|
+
//
|
|
182
|
+
// Close and remove our IMP resources, but leave the worker alone.
|
|
183
|
+
//
|
|
184
|
+
inbot.close = function close() {
|
|
185
|
+
inbot.impconn.destroy()
|
|
186
|
+
inbot.impconn = false
|
|
187
|
+
App.imp.unregister(inbot.instanceID)
|
|
188
|
+
}
|
|
189
|
+
|
|
176
190
|
// destroy
|
|
177
191
|
//
|
|
178
192
|
// Ensure the worker is destroyed and notify everyone.
|
|
@@ -185,13 +199,9 @@ closure InBot(worker, options, local inbot)
|
|
|
185
199
|
notifyAll({
|
|
186
200
|
id: "terminated"
|
|
187
201
|
})
|
|
188
|
-
|
|
189
|
-
inbot.impconn = false
|
|
190
|
-
App.imp.unregister(inbot.instanceID)
|
|
202
|
+
close()
|
|
191
203
|
}
|
|
192
204
|
|
|
193
|
-
// register our connects *after* the receivers are configured above
|
|
194
|
-
|
|
195
205
|
// finis
|
|
196
206
|
|
|
197
207
|
inbot
|
|
@@ -199,41 +209,77 @@ closure InBot(worker, options, local inbot)
|
|
|
199
209
|
|
|
200
210
|
|
|
201
211
|
/*
|
|
202
|
-
*
|
|
212
|
+
* MewBot
|
|
213
|
+
*
|
|
214
|
+
* Create a remote InBot interface for the Main WEb browser thread.
|
|
215
|
+
*
|
|
216
|
+
*/
|
|
217
|
+
|
|
218
|
+
closure MewBot(exec, options, local mewbot, inbot_impReceive)
|
|
219
|
+
{
|
|
220
|
+
global(App)
|
|
221
|
+
mewbot = InBot(exec, options)
|
|
222
|
+
mewbot.dispatcher = require("naanlib:frameworks/running/taskexec.nlg").TaskDispatcher()
|
|
223
|
+
inbot_impReceive = mewbot.impReceive
|
|
224
|
+
|
|
225
|
+
// impReceive
|
|
226
|
+
//
|
|
227
|
+
// Received a message from InTop.
|
|
228
|
+
//
|
|
229
|
+
mewbot.impReceive = function impReceive(message, sourceID) {
|
|
230
|
+
if message.id == "targetin"
|
|
231
|
+
mewbot.dispatcher(message.data, function(reply) {
|
|
232
|
+
mewbot.sender(sourceID, {
|
|
233
|
+
id: "targetout",
|
|
234
|
+
data: reply
|
|
235
|
+
})
|
|
236
|
+
})
|
|
237
|
+
else
|
|
238
|
+
inbot_impReceive(message, sourceID)
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
// finis
|
|
242
|
+
|
|
243
|
+
mewbot
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
|
|
247
|
+
/*
|
|
248
|
+
* WowBot
|
|
203
249
|
*
|
|
204
|
-
* Create a remote interface
|
|
205
|
-
* the worker.
|
|
250
|
+
* Create a remote InBot interface for WebWorkerNub running in the worker. This forwards remoting
|
|
251
|
+
* messages to the worker so they can be handled in the correct place.
|
|
206
252
|
*
|
|
207
253
|
*/
|
|
208
254
|
|
|
209
|
-
closure
|
|
255
|
+
closure WowBot(worker, options, local wowbot)
|
|
210
256
|
{
|
|
211
257
|
global(App)
|
|
212
|
-
|
|
258
|
+
wowbot = InBot(worker, options)
|
|
213
259
|
|
|
214
260
|
App.imp.addEventListener("active", function(event, info) {
|
|
215
|
-
if info.ourID ==
|
|
216
|
-
|
|
217
|
-
|
|
261
|
+
if info.ourID == wowbot.instanceID {
|
|
262
|
+
wowbot.workerDestID = info.destID // handshake completed
|
|
263
|
+
wowbot.notifyAll({ // send to tops
|
|
218
264
|
id: "workerDestID"
|
|
219
|
-
workerDestID:
|
|
265
|
+
workerDestID: wowbot.workerDestID
|
|
220
266
|
})
|
|
221
267
|
}
|
|
222
268
|
})
|
|
223
269
|
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
scope: "naan-imp-
|
|
270
|
+
wowbot.impconn = App.imp.responder(function(data) {
|
|
271
|
+
wowbot.worker.postMessage({ // send IMP messages to worker
|
|
272
|
+
scope: "naan-imp-in" // scoped for WebWorkerNub
|
|
227
273
|
data: data
|
|
228
274
|
})
|
|
229
275
|
list(false, { sent: true })
|
|
230
276
|
}, {
|
|
231
|
-
ourID:
|
|
277
|
+
ourID: wowbot.instanceID
|
|
232
278
|
})
|
|
233
279
|
|
|
234
280
|
// finis
|
|
235
281
|
|
|
236
|
-
|
|
282
|
+
wowbot
|
|
237
283
|
};
|
|
238
284
|
|
|
239
285
|
|
|
@@ -245,11 +291,13 @@ closure NubBot(worker, options, local nubbot)
|
|
|
245
291
|
*/
|
|
246
292
|
|
|
247
293
|
function workInit(local manifest) {
|
|
248
|
-
manifest = `(InBot,
|
|
294
|
+
manifest = `(InBot, MewBot, WowBot, workInit)
|
|
249
295
|
|
|
250
296
|
Naan.module.build(module.id, "worker", function(modobj, compobj) {
|
|
251
297
|
require("./browser.nlg")
|
|
252
298
|
compobj.manifest = manifest
|
|
253
299
|
modobj.exports.InBot = InBot
|
|
300
|
+
modobj.exports.MewBot = MewBot
|
|
301
|
+
modobj.exports.WowBot = WowBot
|
|
254
302
|
})
|
|
255
303
|
} ();
|
|
@@ -314,7 +314,7 @@ closure ScopedServiceWorker(pubID, pubVersion, callback, local scoper, result) {
|
|
|
314
314
|
//
|
|
315
315
|
// Destroy the service worker.
|
|
316
316
|
|
|
317
|
-
|
|
317
|
+
scoper.destroy = function destroy() {
|
|
318
318
|
scoper.serv.unregister()
|
|
319
319
|
scoper.serv = false
|
|
320
320
|
}
|
|
@@ -13,107 +13,43 @@
|
|
|
13
13
|
/*
|
|
14
14
|
* WebSocket
|
|
15
15
|
*
|
|
16
|
-
* Create a WebSocket client connection object.
|
|
16
|
+
* Create a WebSocket client connection object, returning a tuple.
|
|
17
17
|
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
18
|
+
* Required:
|
|
19
|
+
* urlstr: <string>
|
|
20
20
|
*
|
|
21
21
|
* Options:
|
|
22
22
|
* {
|
|
23
23
|
* wss: <boolean> // true to use secure connection
|
|
24
|
+
* query: <string> // query string starting with ?
|
|
24
25
|
* onopen: <proc>(e) // connection has opened
|
|
25
26
|
* onmessage: <proc>(e, message) // message received
|
|
26
27
|
* onerror: <proc>(e) // error occurred
|
|
27
28
|
* onclose: <proc>(e) // connection has closed
|
|
28
|
-
* query: <string> // query string starting with ? for insecure connections
|
|
29
|
-
* querys: <string> // query string starting with ? for secure connections
|
|
30
29
|
* }
|
|
31
30
|
*
|
|
32
31
|
*/
|
|
33
32
|
|
|
34
|
-
closure WebSocket(
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
host = window.location.host
|
|
40
|
-
options.wss = window.location.protocol == "https:"
|
|
33
|
+
closure WebSocket(urlstr, options, local url, ws) {
|
|
34
|
+
try {
|
|
35
|
+
url = xnew(js.w.URL, urlstr)
|
|
36
|
+
} catch {
|
|
37
|
+
return (list(Error("invalid URL ${urlstr}", exception)))
|
|
41
38
|
}
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
// onopen
|
|
58
|
-
// The WebSocket connection is now open.
|
|
59
|
-
wsock.ws.onopen = closure onopen(e) {
|
|
60
|
-
pending.signal(list(false, { ok: true }))
|
|
61
|
-
options.onopen(e)
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
// onmessage
|
|
65
|
-
// A message was received from the worker via WebSockets.
|
|
66
|
-
wsock.ws.onmessage = closure onmessage(e, local message) {
|
|
67
|
-
try {
|
|
68
|
-
message = new(JSONparse(e.data))
|
|
69
|
-
} catch {
|
|
70
|
-
debuglog("can't decode incoming ws message:", exception)
|
|
71
|
-
options.onerror(Error("can't decode incoming message:", exception))
|
|
72
|
-
return
|
|
73
|
-
}
|
|
74
|
-
options.onmessage(e, message)
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
// onerror
|
|
78
|
-
// An error occurred on the WebSocket connection.
|
|
79
|
-
wsock.ws.onerror = closure onerror(e, local error) {
|
|
80
|
-
error = Error("websocket failed", e)
|
|
81
|
-
options.onerror(e, error)
|
|
82
|
-
pending.signal(list(error)) // ensure connect completes
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
// onclose
|
|
86
|
-
// The WebSocket connection was closed.
|
|
87
|
-
wsock.ws.onclose = closure onclose(e) {
|
|
88
|
-
options.onclose(e, e.code, e.reason)
|
|
89
|
-
pending.signal(list(Error("connection closed"))) // ensure connect completes
|
|
90
|
-
wsock.ws = false
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
pending.wait()
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
// send
|
|
97
|
-
//
|
|
98
|
-
// Send a message dictionary.
|
|
99
|
-
//
|
|
100
|
-
wsock.send = function send(message) {
|
|
101
|
-
wsock.ws.send(JSONstringify(message))
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
// close
|
|
105
|
-
//
|
|
106
|
-
// Close the connection.
|
|
107
|
-
//
|
|
108
|
-
wsock.close = function close(reason) {
|
|
109
|
-
if !reason
|
|
110
|
-
reason = 1000 // normal close
|
|
111
|
-
wsock.ws.close(reason)
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
// finis
|
|
115
|
-
|
|
116
|
-
wsock
|
|
39
|
+
options = merge({
|
|
40
|
+
query: url.search || ''
|
|
41
|
+
wss: url.protocol == "https:"
|
|
42
|
+
}, options)
|
|
43
|
+
if options.wss
|
|
44
|
+
url = "wss://${url.host}${options.query}"
|
|
45
|
+
else
|
|
46
|
+
url = "ws://${url.host}${options.query}"
|
|
47
|
+
ws = xnew(window.WebSocket, url)
|
|
48
|
+
ws.onopen = options.onopen
|
|
49
|
+
ws.onmessage = options.onmessage
|
|
50
|
+
ws.onerror = options.onerror
|
|
51
|
+
ws.onclose = options.onclose
|
|
52
|
+
list(false, ws)
|
|
117
53
|
};
|
|
118
54
|
|
|
119
55
|
|
|
@@ -19,7 +19,7 @@ serviceMod;;
|
|
|
19
19
|
/*
|
|
20
20
|
* APIClient
|
|
21
21
|
*
|
|
22
|
-
* Make an API client object.
|
|
22
|
+
* Make an API client object. If you want websockets, and you do, call connect() on the object.
|
|
23
23
|
*
|
|
24
24
|
* Options:
|
|
25
25
|
* {
|
|
@@ -46,18 +46,20 @@ closure APIClient(imp, options, local client, url, guid) {
|
|
|
46
46
|
client.requester = clirRequester()
|
|
47
47
|
|
|
48
48
|
//
|
|
49
|
-
//
|
|
49
|
+
// connect
|
|
50
50
|
//
|
|
51
51
|
|
|
52
|
-
client.
|
|
53
|
-
if !client.wesc
|
|
52
|
+
client.connect = function connect(error) {
|
|
53
|
+
if !client.wesc
|
|
54
54
|
client.wesc = WebSocketClient(options, imp)
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
55
|
+
`(error) = client.wesc.connect()
|
|
56
|
+
if error {
|
|
57
|
+
ErrorDebuglog("APIClient: cannot connect to", url, error)
|
|
58
|
+
return (list(error))
|
|
58
59
|
}
|
|
60
|
+
client.serverID = client.wesc.serverID // serverID
|
|
61
|
+
list(false, { connected: true })
|
|
59
62
|
}
|
|
60
|
-
wsopen()
|
|
61
63
|
|
|
62
64
|
// clientRequest() - append our guid to the headers
|
|
63
65
|
|
|
@@ -178,10 +180,12 @@ closure APIClient(imp, options, local client, url, guid) {
|
|
|
178
180
|
// Close down the client and release all resources.
|
|
179
181
|
//
|
|
180
182
|
client.destroy = closure destroy() {
|
|
181
|
-
debuglog("client
|
|
183
|
+
debuglog("API client destroyed") // ### not pretty, but uncommon
|
|
182
184
|
client.wesc.destroy()
|
|
183
185
|
client.wesc = false
|
|
184
186
|
}
|
|
187
|
+
|
|
188
|
+
// finis
|
|
185
189
|
|
|
186
190
|
client
|
|
187
191
|
};
|
|
@@ -197,104 +201,129 @@ closure APIClient(imp, options, local client, url, guid) {
|
|
|
197
201
|
* {
|
|
198
202
|
* url: <string> // hostname or URL of the remote server
|
|
199
203
|
* guid: <string> // shared secret for access to remote server
|
|
200
|
-
* instanceID: <string> // UUID for our client; can be persisted by caller
|
|
201
204
|
* }
|
|
202
205
|
*
|
|
203
206
|
*/
|
|
204
207
|
|
|
205
|
-
closure WebSocketClient(options, imp, local wesc, ws) {
|
|
208
|
+
closure WebSocketClient(options, imp, local wesc, ws, pending) {
|
|
206
209
|
global(js)
|
|
207
210
|
wesc = new(object, this)
|
|
211
|
+
|
|
212
|
+
|
|
213
|
+
// reconnect
|
|
214
|
+
//
|
|
215
|
+
// Attempt to reconnect if needed, returning false on success or an error tuple otherwise.
|
|
216
|
+
//
|
|
217
|
+
function reconnect() {
|
|
218
|
+
if !ws || wesc.fatal || pending {
|
|
219
|
+
connect() // try to connect
|
|
220
|
+
if wesc.fatal
|
|
221
|
+
return (list(wesc.fatal))
|
|
222
|
+
}
|
|
223
|
+
false
|
|
224
|
+
}
|
|
208
225
|
|
|
209
226
|
// connect
|
|
210
227
|
//
|
|
211
228
|
// Establish a websocket connection with the host.
|
|
212
229
|
//
|
|
213
|
-
wesc.connect = closure connect(local url,
|
|
214
|
-
if ws
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
try {
|
|
220
|
-
url = xnew(js.w.URL, options.url)
|
|
221
|
-
} catch {
|
|
222
|
-
return(list(Error("invalid URL ${options.url}", exception)))
|
|
230
|
+
wesc.connect = closure connect(local url, result, error) {
|
|
231
|
+
if ws {
|
|
232
|
+
if pending
|
|
233
|
+
return (pending.wait()) // connect in process
|
|
234
|
+
if !wesc.fatal
|
|
235
|
+
return(list(false, { connected: true })) // already open
|
|
223
236
|
}
|
|
224
|
-
|
|
225
|
-
url.protocol = "wss:"
|
|
226
|
-
else
|
|
227
|
-
url.protocol = "ws:"
|
|
228
|
-
ws = xnew(js.w.WebSocket, url.href)
|
|
229
|
-
pending = new(nonce)
|
|
230
|
-
|
|
237
|
+
|
|
231
238
|
// onopen
|
|
232
239
|
// The WebSocket connection is now open.
|
|
233
|
-
|
|
234
|
-
wesc.impconn
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
240
|
+
function onopen(e) {
|
|
241
|
+
if wesc.impconn {
|
|
242
|
+
result = wesc.impconn.reopen()
|
|
243
|
+
pending.signal(result)
|
|
244
|
+
return
|
|
245
|
+
}
|
|
246
|
+
wesc.impconn = imp.requester(function(data, local error, text) {
|
|
247
|
+
if !pending && reconnect() // !pending means not opening/reopening
|
|
248
|
+
return // failed to reconnect
|
|
249
|
+
`(error, text) = JsonStringify(data)
|
|
250
|
+
if error
|
|
251
|
+
return (list(error))
|
|
252
|
+
ws.send(text)
|
|
238
253
|
list(false, { sent: true })
|
|
239
254
|
}, {
|
|
240
255
|
secret: options.guid
|
|
241
256
|
label: "api-server"
|
|
242
|
-
wesc: wesc
|
|
243
257
|
})
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
else
|
|
258
|
+
wesc.impconn.addEventListener("active", function (event, info) {
|
|
259
|
+
wesc.serverID = info.destID // serverID we connected to
|
|
247
260
|
pending.signal(list(false, { ok: true }))
|
|
261
|
+
pending = false
|
|
262
|
+
})
|
|
248
263
|
}
|
|
249
|
-
|
|
264
|
+
|
|
250
265
|
// onmessage
|
|
251
266
|
// A message was received via WebSockets.
|
|
252
|
-
|
|
267
|
+
function onmessage(e, local error, message) {
|
|
253
268
|
`(error, message) = JsonParse(e.data)
|
|
254
269
|
if !error {
|
|
255
270
|
message = new(message)
|
|
256
271
|
if wesc.impconn.dispatch(message)
|
|
257
272
|
return
|
|
258
273
|
}
|
|
259
|
-
|
|
274
|
+
pending.signal(list(Error("incompatible responder")))
|
|
275
|
+
pending = false
|
|
276
|
+
debuglog("socket message:", e.data) // unexpected incoming data
|
|
260
277
|
}
|
|
261
|
-
|
|
278
|
+
|
|
262
279
|
// onerror
|
|
263
280
|
// An error occurred on the WebSocket connection.
|
|
264
281
|
// This can happen in normal operation when the connection times out.
|
|
265
|
-
|
|
282
|
+
function onerror(e) {
|
|
266
283
|
if !wesc.fatal
|
|
267
284
|
wesc.fatal = Error("websocket failed", e)
|
|
268
285
|
pending.signal(list(wesc.fatal))
|
|
286
|
+
pending = false
|
|
269
287
|
}
|
|
270
288
|
|
|
271
289
|
// onclose
|
|
272
290
|
// The WebSocket connection was closed.
|
|
273
|
-
|
|
291
|
+
function onclose(e) {
|
|
274
292
|
// if e.code != 1000 && e.code != 1001 && e.code != 1005 && e.code != 1006
|
|
275
|
-
debuglog("WebSocketClient: closed:", e.code, e.reason)
|
|
293
|
+
debuglog("WebSocketClient: closed:", e.code, e.reason) // ### not pretty to see this
|
|
276
294
|
ws = false
|
|
277
295
|
if !wesc.fatal
|
|
278
296
|
wesc.fatal = Error("websocket closed", e.code, e.reason)
|
|
279
297
|
pending.signal(list(wesc.fatal))
|
|
280
|
-
|
|
281
|
-
code: e.code
|
|
282
|
-
reason: e.reason
|
|
283
|
-
})
|
|
284
|
-
wesc.impconn = false
|
|
298
|
+
pending = false
|
|
285
299
|
}
|
|
286
300
|
|
|
287
|
-
|
|
301
|
+
`(error, ws) = call(clirWebsocket(), options.url, {
|
|
302
|
+
onopen: onopen.proc
|
|
303
|
+
onmessage: onmessage.proc
|
|
304
|
+
onerror: onerror.proc
|
|
305
|
+
onclose: onclose.proc
|
|
306
|
+
})
|
|
307
|
+
if error
|
|
308
|
+
return (list(wesc.fatal = error)) // failed to even get started
|
|
309
|
+
|
|
310
|
+
if wesc.fatal
|
|
311
|
+
debuglog("WebSocketClient reopen") // ### not pretty to see this
|
|
312
|
+
wesc.fatal = false
|
|
313
|
+
pending = new(nonce)
|
|
314
|
+
result = pending.wait(10000, list(Error("IMP connection timeout")))
|
|
315
|
+
pending = false
|
|
316
|
+
result
|
|
288
317
|
}
|
|
289
|
-
|
|
318
|
+
|
|
290
319
|
// close
|
|
291
320
|
//
|
|
292
321
|
// Close the connection, but can be opened again with connect().
|
|
293
322
|
//
|
|
294
323
|
wesc.close = function close() {
|
|
295
|
-
if
|
|
296
|
-
|
|
297
|
-
ws
|
|
324
|
+
if ws
|
|
325
|
+
ws.close(1000) // 1000: normal close
|
|
326
|
+
ws = false
|
|
298
327
|
}
|
|
299
328
|
|
|
300
329
|
// destroy
|
|
@@ -303,23 +332,27 @@ closure WebSocketClient(options, imp, local wesc, ws) {
|
|
|
303
332
|
//
|
|
304
333
|
wesc.destroy = function destroy() {
|
|
305
334
|
close()
|
|
335
|
+
wesc.impconn.destroy()
|
|
336
|
+
wesc.impconn = false
|
|
306
337
|
}
|
|
307
338
|
|
|
308
339
|
// send
|
|
309
340
|
//
|
|
310
|
-
// Send a message.
|
|
341
|
+
// Send a message, returning result tuple.
|
|
311
342
|
//
|
|
312
343
|
wesc.send = closure send(data) {
|
|
313
|
-
if
|
|
314
|
-
return
|
|
344
|
+
if reconnect()
|
|
345
|
+
return // failed to reconnect
|
|
315
346
|
wesc.impconn.send(data)
|
|
316
347
|
}
|
|
317
348
|
|
|
318
349
|
// sendRaw
|
|
319
350
|
//
|
|
320
|
-
// Send a message with reconnect but no routing.
|
|
351
|
+
// Send a message with reconnect but no routing. Returns a result tuple.
|
|
321
352
|
//
|
|
322
353
|
wesc.sendRaw = closure sendRaw(data) {
|
|
354
|
+
if reconnect()
|
|
355
|
+
return // failed to reconnect
|
|
323
356
|
ws.send(data)
|
|
324
357
|
}
|
|
325
358
|
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
*
|
|
7
7
|
* column positioning: // // !
|
|
8
8
|
*
|
|
9
|
-
* Copyright (c) 2020-
|
|
9
|
+
* Copyright (c) 2020-2026 by Richard C. Zulch
|
|
10
10
|
*
|
|
11
11
|
*/
|
|
12
12
|
|
|
@@ -31,6 +31,26 @@ function clirRequester() {
|
|
|
31
31
|
};
|
|
32
32
|
|
|
33
33
|
|
|
34
|
+
/*
|
|
35
|
+
* clirWebsocket
|
|
36
|
+
*
|
|
37
|
+
* Return an appropriate Websocket client based on our environment.
|
|
38
|
+
*
|
|
39
|
+
*/
|
|
40
|
+
|
|
41
|
+
clirWebsocketApi = false;
|
|
42
|
+
|
|
43
|
+
function clirWebsocket() {
|
|
44
|
+
if !clirWebsocketApi {
|
|
45
|
+
if js.w
|
|
46
|
+
clirWebsocketApi = require("naanlib:frameworks/browser/ws_client.nlg").WebSocket
|
|
47
|
+
else
|
|
48
|
+
clirWebsocketApi = require("naanlib:frameworks/node/ws_client.nlg").WebSocket
|
|
49
|
+
}
|
|
50
|
+
clirWebsocketApi
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
|
|
34
54
|
/*
|
|
35
55
|
* clirInit
|
|
36
56
|
*
|
|
@@ -40,7 +60,7 @@ function clirRequester() {
|
|
|
40
60
|
*/
|
|
41
61
|
|
|
42
62
|
function clirInit(local manifest) {
|
|
43
|
-
manifest = `(clirRequester, clirInit)
|
|
63
|
+
manifest = `(clirRequester, clirWebsocket, clirInit)
|
|
44
64
|
|
|
45
65
|
Naan.module.build(module.id, "client", function(modobj, compobj) {
|
|
46
66
|
require("../common/").LiveImport()
|