@naanlang/naan 1.4.3 → 1.4.4
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 +4 -3
- package/dist/naan.min.js +5 -5
- package/frameworks/browser/https_request.nlg +39 -10
- package/frameworks/browser/sworker.js +23 -23
- package/frameworks/browser/terminals.nlg +19 -16
- package/frameworks/node/http_request.nlg +103 -0
- package/frameworks/node/https_request.nlg +42 -9
- package/frameworks/node/node.nlg +1 -0
- package/frameworks/node/worker.nlg +1 -0
- package/frameworks/project/projects.nlg +1 -1
- package/frameworks/running/executors.nlg +26 -7
- package/frameworks/running/taskexec.nlg +48 -14
- package/lib/browser/env_web.js +7 -7
- package/lib/core/naanlib.js +5 -5
- package/lib/env_node.js +9 -3
- package/lib/node_repl_init.nlg +2 -2
- package/package.json +1 -1
- package/plugins/nodeLib/node_util.nlg +14 -7
- package/plugins/openSearch/os_dynamo.nlg +5 -5
- package/plugins/serviceAws/aws_dynamo.nlg +25 -8
- package/plugins/serviceAws/aws_vm.nlg +198 -0
- package/plugins/serviceGC/gc_api.nlg +1 -0
- package/plugins/serviceNexara/serviceNexara.nlg +32 -0
- package/plugins/serviceNexara/speechrec.nlg +160 -0
- package/plugins/serviceYC/serviceYC.nlg +2 -3
- package/plugins/serviceYC/yc_speechrec.nlg +4 -3
- package/plugins/serviceYC/yc_vm.nlg +44 -54
- package/test/test_01_core.nlg +42 -33
- package/test/test_03_jsinterop.nlg +3 -3
|
@@ -25,6 +25,7 @@
|
|
|
25
25
|
* range: <string> // sets range header
|
|
26
26
|
* headers: [`(key, value)] // add header(s) to the request, overriding defaults
|
|
27
27
|
* keepalive: <boolean> // true to send data at unload
|
|
28
|
+
* retrier: <function> // retry selected failures
|
|
28
29
|
* debug: <boolean> // log errors and status results
|
|
29
30
|
* }
|
|
30
31
|
*
|
|
@@ -39,11 +40,35 @@
|
|
|
39
40
|
*/
|
|
40
41
|
|
|
41
42
|
closure HttpsApiRequest(url, options,
|
|
42
|
-
local urlq, fetchOptions, putdata, item, error, response,
|
|
43
|
+
local delayf, urlq, fetchOptions, putdata, item, error, response,
|
|
43
44
|
contentType, content, headers) {
|
|
44
|
-
global(window)
|
|
45
|
-
|
|
46
|
-
|
|
45
|
+
global(window, common)
|
|
46
|
+
//
|
|
47
|
+
// defRetrier -- backoff and retry selected errors
|
|
48
|
+
//
|
|
49
|
+
function defRetrier(error, headers, local retryAfter, retryms, waitms) {
|
|
50
|
+
if member(error.status, `(408, 500, 502, 503, 504)) { // retriable errors
|
|
51
|
+
retryAfter = headers["retry-after"]
|
|
52
|
+
if retryAfter {
|
|
53
|
+
retryms = toint(retryAfter) * 1000
|
|
54
|
+
if !retryms
|
|
55
|
+
retryms = Date(retryAfter).getTime() - Date.now()
|
|
56
|
+
if retryms < 0
|
|
57
|
+
retryms = false
|
|
58
|
+
}
|
|
59
|
+
if !delayf
|
|
60
|
+
delayf = common.ExbackFactory(12,30) // 12s max backoff, 30s deadline
|
|
61
|
+
waitms = delayf()
|
|
62
|
+
if !waitms || waitms < retryms
|
|
63
|
+
waitms = retryms
|
|
64
|
+
if options.debug
|
|
65
|
+
debuglog("HttpsApiRequest.defRetrier: wait ${waitms} msec using retry-after ${retryAfter}")
|
|
66
|
+
if waitms // return false to give up
|
|
67
|
+
sleep(waitms) // return true from sleep to retry
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
options = merge({ retrier: defRetrier }, options)
|
|
47
72
|
if options.query
|
|
48
73
|
urlq = url.concat(EncodeQuery("?", options.query))
|
|
49
74
|
else
|
|
@@ -92,16 +117,23 @@ closure HttpsApiRequest(url, options,
|
|
|
92
117
|
debuglog("HttpsApiRequest error:", url, "error:", error)
|
|
93
118
|
return (list(Error("HttpsApiRequest fetch failed:", error, url)))
|
|
94
119
|
}
|
|
120
|
+
headers = { }
|
|
121
|
+
response.headers.forEach(function(value, key) {
|
|
122
|
+
headers[key.toLowerCase()] = value
|
|
123
|
+
})
|
|
95
124
|
if response.status < 200 || response.status >= 299 { // 299 is "cancelled"
|
|
96
125
|
if options.debug
|
|
97
126
|
debuglog("HttpsApiRequest status:", url, response.statusCode)
|
|
98
127
|
error = Error("HttpsApiRequest status:", url, response.status, {
|
|
99
128
|
status: response.status
|
|
100
129
|
})
|
|
101
|
-
if options.retrier(error)
|
|
130
|
+
if options.retrier(error, headers)
|
|
102
131
|
continue // optional retry/delay logic
|
|
103
132
|
else
|
|
104
|
-
return (list(error, false, {
|
|
133
|
+
return (list(error, false, {
|
|
134
|
+
headers: headers
|
|
135
|
+
status: response.status
|
|
136
|
+
}))
|
|
105
137
|
} else
|
|
106
138
|
break
|
|
107
139
|
}
|
|
@@ -125,10 +157,6 @@ closure HttpsApiRequest(url, options,
|
|
|
125
157
|
`(error, content) = await(response.arrayBuffer())
|
|
126
158
|
else
|
|
127
159
|
`(error, content) = await(response.text())
|
|
128
|
-
headers = { }
|
|
129
|
-
response.headers.forEach(function(value, key) {
|
|
130
|
-
headers[key.toLowerCase()] = value
|
|
131
|
-
})
|
|
132
160
|
list(error, content, {
|
|
133
161
|
headers: headers
|
|
134
162
|
status: response.status
|
|
@@ -149,6 +177,7 @@ function https_browserInit(local manifest) {
|
|
|
149
177
|
|
|
150
178
|
Naan.module.build(module.id, "https_request", function(modobj, compobj) {
|
|
151
179
|
require("browser.nlg")
|
|
180
|
+
common = require("../common/utils.nlg")
|
|
152
181
|
compobj.manifest = manifest
|
|
153
182
|
modobj.exports.HttpsApiRequest = HttpsApiRequest
|
|
154
183
|
})
|
|
@@ -36,7 +36,7 @@
|
|
|
36
36
|
*
|
|
37
37
|
*/
|
|
38
38
|
|
|
39
|
-
var CurrentCacheName = "Naanlang-1.4.
|
|
39
|
+
var CurrentCacheName = "Naanlang-1.4.4+1";
|
|
40
40
|
|
|
41
41
|
|
|
42
42
|
//
|
|
@@ -92,18 +92,18 @@ var terminated; // flag that this service worker
|
|
|
92
92
|
var pubVersion = event.data.hereIsMyVersion;
|
|
93
93
|
var sourceId = event.source.id; // client id of sender of message
|
|
94
94
|
msgPorts[sourceId] = msgport;
|
|
95
|
-
console.log("[1.4.
|
|
96
|
-
if (pubVersion != "1.4.
|
|
95
|
+
console.log("[1.4.4+1] received new msgport for", sourceId, pubID, "-", pubVersion);
|
|
96
|
+
if (pubVersion != "1.4.4+1") {
|
|
97
97
|
if (upgradeMsgPorts) { // if not activated
|
|
98
|
-
console.log("[1.4.
|
|
98
|
+
console.log("[1.4.4+1] update pending for", sourceId);
|
|
99
99
|
upgradeMsgPorts[sourceId] = msgport;
|
|
100
100
|
}
|
|
101
101
|
else {
|
|
102
102
|
msgport.postMessage({ // notify new version available
|
|
103
103
|
id: "upgrade",
|
|
104
|
-
version: "1.4.
|
|
104
|
+
version: "1.4.4+1"
|
|
105
105
|
});
|
|
106
|
-
console.log("[1.4.
|
|
106
|
+
console.log("[1.4.4+1] update sent for:", sourceId);
|
|
107
107
|
}
|
|
108
108
|
}
|
|
109
109
|
Reaper(); // clean up obsolete info
|
|
@@ -134,10 +134,10 @@ var terminated; // flag that this service worker
|
|
|
134
134
|
msgport.onmessage = function(msg) {
|
|
135
135
|
msg = msg.data;
|
|
136
136
|
if (msg.id == "skipWaiting") { // try to activate this SW now
|
|
137
|
-
console.log("[1.4.
|
|
137
|
+
console.log("[1.4.4+1] attempting skipWaiting");
|
|
138
138
|
self.skipWaiting();
|
|
139
139
|
} else if (msg.id == "terminate") { // termiante this SW now
|
|
140
|
-
console.log("[1.4.
|
|
140
|
+
console.log("[1.4.4+1] terminated");
|
|
141
141
|
terminate();
|
|
142
142
|
} else if (msg.id == "abortURL") { // abort an I/O transaction
|
|
143
143
|
var href = new URL(msg.url).href;
|
|
@@ -150,7 +150,7 @@ var terminated; // flag that this service worker
|
|
|
150
150
|
} else if (msg.id == "response") // response from fetch request
|
|
151
151
|
processResponse(msg);
|
|
152
152
|
else if (msg.id == "text") // just log some text
|
|
153
|
-
console.log("[1.4.
|
|
153
|
+
console.log("[1.4.4+1] msg received:", msg.text);
|
|
154
154
|
};
|
|
155
155
|
|
|
156
156
|
// send text to IDE log
|
|
@@ -161,7 +161,7 @@ var terminated; // flag that this service worker
|
|
|
161
161
|
// don't clutter the log
|
|
162
162
|
msgport.postMessage({
|
|
163
163
|
id: "text",
|
|
164
|
-
text: "port received by 1.4.
|
|
164
|
+
text: "port received by 1.4.4+1",
|
|
165
165
|
});
|
|
166
166
|
*/
|
|
167
167
|
if (--pending === 0)
|
|
@@ -178,7 +178,7 @@ var terminated; // flag that this service worker
|
|
|
178
178
|
includeUncontrolled: true
|
|
179
179
|
}).then(function(clientList) {
|
|
180
180
|
clientList.every(function(client) {
|
|
181
|
-
console.log("[1.4.
|
|
181
|
+
console.log("[1.4.4+1] requesting new msgport for", client.id);
|
|
182
182
|
++pending;
|
|
183
183
|
client.postMessage({ // tell client(s) we need this fetch source
|
|
184
184
|
msg: "Naan_need_fetch_port",
|
|
@@ -224,12 +224,12 @@ function Reaper() {
|
|
|
224
224
|
clients[clientList[clidex].id] = clientList[clidex];
|
|
225
225
|
for (var sourceId in msgPorts)
|
|
226
226
|
if (!clients[sourceId]) {
|
|
227
|
-
console.log("[1.4.
|
|
227
|
+
console.log("[1.4.4+1] source gone:", sourceId);
|
|
228
228
|
delete msgPorts[sourceId]; // no longer a source
|
|
229
229
|
}
|
|
230
230
|
for (var clientId in fetchPorts)
|
|
231
231
|
if (!clients[clientId]) {
|
|
232
|
-
console.log("[1.4.
|
|
232
|
+
console.log("[1.4.4+1] client gone:", clientId);
|
|
233
233
|
delete fetchPorts[clientId]; // no longer a client
|
|
234
234
|
}
|
|
235
235
|
for (var fqdex = 0; fqdex < fetchQueue.length; ++fqdex) {
|
|
@@ -263,16 +263,16 @@ function ClearCaches() {
|
|
|
263
263
|
return (Promise.all(
|
|
264
264
|
cacheNames.map(function(cacheName) {
|
|
265
265
|
if (cacheName != CurrentCacheName) {
|
|
266
|
-
console.log('[1.4.
|
|
266
|
+
console.log('[1.4.4+1] deleting old cache:', cacheName);
|
|
267
267
|
return (caches.delete(cacheName));
|
|
268
268
|
}
|
|
269
269
|
})
|
|
270
270
|
));
|
|
271
271
|
}).then(function() { // claim all clients
|
|
272
|
-
console.log('[1.4.
|
|
272
|
+
console.log('[1.4.4+1] claiming clients');
|
|
273
273
|
return (self.clients.claim());
|
|
274
274
|
}).then(function() {
|
|
275
|
-
console.log('[1.4.
|
|
275
|
+
console.log('[1.4.4+1] clients claimed');
|
|
276
276
|
return (Promise.resolve(true));
|
|
277
277
|
});
|
|
278
278
|
return (promise);
|
|
@@ -315,7 +315,7 @@ function GetClientResponse(event, urlpath) {
|
|
|
315
315
|
msgport.postMessage({
|
|
316
316
|
id: "fetch",
|
|
317
317
|
seq: seqno,
|
|
318
|
-
version: "1.4.
|
|
318
|
+
version: "1.4.4+1",
|
|
319
319
|
request: {
|
|
320
320
|
method: event.request.method,
|
|
321
321
|
url: event.request.url
|
|
@@ -363,7 +363,7 @@ function GetClientResponse(event, urlpath) {
|
|
|
363
363
|
*/
|
|
364
364
|
|
|
365
365
|
self.addEventListener('install', function(event) {
|
|
366
|
-
console.log("[1.4.
|
|
366
|
+
console.log("[1.4.4+1] install");
|
|
367
367
|
self.skipWaiting();
|
|
368
368
|
});
|
|
369
369
|
|
|
@@ -376,20 +376,20 @@ self.addEventListener('install', function(event) {
|
|
|
376
376
|
*/
|
|
377
377
|
|
|
378
378
|
self.addEventListener('activate', function(event) {
|
|
379
|
-
console.log("[1.4.
|
|
379
|
+
console.log("[1.4.4+1] activate");
|
|
380
380
|
self.clients.matchAll({ // for debugging, list controlled clients
|
|
381
381
|
includeUncontrolled: true
|
|
382
382
|
}).then(function(clientList) {
|
|
383
383
|
var urls = clientList.map(function(client) {
|
|
384
384
|
return (client.url);
|
|
385
385
|
});
|
|
386
|
-
console.log('[1.4.
|
|
386
|
+
console.log('[1.4.4+1] matching clients:', urls.join(', '));
|
|
387
387
|
});
|
|
388
388
|
var promise = ClearCaches().then(function() {
|
|
389
389
|
for (var sourceId in upgradeMsgPorts) {
|
|
390
390
|
upgradeMsgPorts[sourceId].postMessage({ // notify new version available
|
|
391
391
|
id: "upgrade",
|
|
392
|
-
version: "1.4.
|
|
392
|
+
version: "1.4.4+1"
|
|
393
393
|
});
|
|
394
394
|
}
|
|
395
395
|
upgradeMsgPorts = false;
|
|
@@ -421,7 +421,7 @@ self.addEventListener('fetch', function(event) {
|
|
|
421
421
|
var promise;
|
|
422
422
|
var url = new URL(request.url);
|
|
423
423
|
var nocache = request.method != "GET"
|
|
424
|
-
|| url.search.length !== 0 && url.searchParams.get("naanver") !== "
|
|
424
|
+
|| url.search.length !== 0 && url.searchParams.get("naanver") !== "3a2321ac98091606ee7cf5cc8919f70c"
|
|
425
425
|
|| request.headers.get('range');
|
|
426
426
|
if (url.pathname.startsWith("/run/")) {
|
|
427
427
|
nocache = true;
|
|
@@ -455,7 +455,7 @@ self.addEventListener('fetch', function(event) {
|
|
|
455
455
|
statusText: "Request Cancelled"
|
|
456
456
|
}));
|
|
457
457
|
}
|
|
458
|
-
console.log("[1.4.
|
|
458
|
+
console.log("[1.4.4+1] fetch failed", request.url, e);
|
|
459
459
|
return (new Response(undefined, {
|
|
460
460
|
status: 404,
|
|
461
461
|
statusText: "Fetch Failed"
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
*
|
|
7
7
|
* column positioning: // // !
|
|
8
8
|
*
|
|
9
|
-
* Copyright (c) 2019-
|
|
9
|
+
* Copyright (c) 2019-2025 by Richard C. Zulch
|
|
10
10
|
*
|
|
11
11
|
*/
|
|
12
12
|
|
|
@@ -48,8 +48,8 @@ closure TermHost(track, api, name, options, local target, nlregex, xtarg)
|
|
|
48
48
|
nlregex = RegExp("\\n", "g")
|
|
49
49
|
target.workerID = options.workerID
|
|
50
50
|
target.msgQueue = []
|
|
51
|
-
target.dispatcher = call(options.dispatcher
|
|
52
|
-
|
|
51
|
+
target.dispatcher = call(options.dispatcher)
|
|
52
|
+
|
|
53
53
|
// findWorker
|
|
54
54
|
//
|
|
55
55
|
function findWorker(testID, local instance) {
|
|
@@ -135,19 +135,20 @@ closure TermHost(track, api, name, options, local target, nlregex, xtarg)
|
|
|
135
135
|
|
|
136
136
|
// dispatcher
|
|
137
137
|
// Respond to a host request while preserving context to permit reply routing
|
|
138
|
-
closure dispatcher(message
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
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
|
+
})
|
|
151
152
|
}
|
|
152
153
|
|
|
153
154
|
// onerror
|
|
@@ -334,6 +335,7 @@ closure TermHost(track, api, name, options, local target, nlregex, xtarg)
|
|
|
334
335
|
//
|
|
335
336
|
|
|
336
337
|
target.debugWrite = function(text, level) {
|
|
338
|
+
text = text.replaceAll("\n", "\r\n")
|
|
337
339
|
if (level >= 5)
|
|
338
340
|
target.term.WriteLn(text, target.term.Cyan) // cyan for builtin logging
|
|
339
341
|
else if (level >= 4)
|
|
@@ -596,6 +598,7 @@ closure TermLocal(track, name, options, local target, nlregex, listener)
|
|
|
596
598
|
//
|
|
597
599
|
|
|
598
600
|
target.debugWrite = function(text, level) {
|
|
601
|
+
text = text.replaceAll("\n", "\r\n")
|
|
599
602
|
if (level >= 5)
|
|
600
603
|
target.term.WriteLn(text, target.term.Cyan) // cyan for builtin logging
|
|
601
604
|
else if (level >= 4)
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* http_request.nlg
|
|
3
|
+
*
|
|
4
|
+
* Http operations for NodeJS.
|
|
5
|
+
*
|
|
6
|
+
* column positioning: // // !
|
|
7
|
+
*
|
|
8
|
+
* Copyright (c) 2024-2025 by Richard C. Zulch
|
|
9
|
+
*
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
/* HttpRequest
|
|
14
|
+
*
|
|
15
|
+
* Make a simple http request. This is not supported by the standard NaaN framework HttpsApiRequest
|
|
16
|
+
* because it is not SSL.
|
|
17
|
+
*
|
|
18
|
+
* Options:
|
|
19
|
+
* {
|
|
20
|
+
* method: <string> // HTTP method (defaults to GET)
|
|
21
|
+
* headers: <dictionary> // key/data pairs
|
|
22
|
+
* putdata: <data> // data to put
|
|
23
|
+
* json: <boolean> // ignore content-type of return and decode JSON
|
|
24
|
+
* }
|
|
25
|
+
*
|
|
26
|
+
* The return is a result tuple comprising:
|
|
27
|
+
* (<error>, -- false on success
|
|
28
|
+
* <content>, -- returned data
|
|
29
|
+
* {
|
|
30
|
+
* status: <integer> -- http response status
|
|
31
|
+
* headers: <array> -- headers if available
|
|
32
|
+
* })
|
|
33
|
+
*
|
|
34
|
+
*/
|
|
35
|
+
|
|
36
|
+
closure HttpRequest(url, options,
|
|
37
|
+
local pending, chunks, params, request) {
|
|
38
|
+
global(js, nodeHttp)
|
|
39
|
+
pending = new(nonce)
|
|
40
|
+
chunks = []
|
|
41
|
+
params = {
|
|
42
|
+
method: options.method || undefined
|
|
43
|
+
headers: options.headers || undefined
|
|
44
|
+
}
|
|
45
|
+
request = nodeHttp.request(url, params, closure (response) {
|
|
46
|
+
response.on("data", function (chunk) {
|
|
47
|
+
chunks.push(chunk)
|
|
48
|
+
})
|
|
49
|
+
response.on("end", function (local content, error) {
|
|
50
|
+
content = js.g.Buffer.concat(chunks)
|
|
51
|
+
if response.statusCode < 200 || response.statusCode >= 299 { // 299 is "cancelled"
|
|
52
|
+
debuglog("httpRequest status:", url, response.statusCode, "message:", content)
|
|
53
|
+
pending.signal(list(Error("httpRequest statusCode:", url, response.statusCode, {
|
|
54
|
+
status: response.statusCode
|
|
55
|
+
}), false, { status: response.statusCode }))
|
|
56
|
+
return
|
|
57
|
+
}
|
|
58
|
+
if response.complete {
|
|
59
|
+
content = content.toString()
|
|
60
|
+
if options.json
|
|
61
|
+
`(error, content) = JsonParse(content)
|
|
62
|
+
}
|
|
63
|
+
else
|
|
64
|
+
error = Error("httpRequest terminated prematurely:", url, response.statusCode)
|
|
65
|
+
pending.signal(list(error, content, {
|
|
66
|
+
headers: response.headers
|
|
67
|
+
status: response.statusCode
|
|
68
|
+
contentType: response.headers["content-type"]
|
|
69
|
+
}))
|
|
70
|
+
})
|
|
71
|
+
})
|
|
72
|
+
request.on("error", function hre(error) {
|
|
73
|
+
debuglog("httpRequest error:", url, "error:", error)
|
|
74
|
+
error = Error("httpRequest failed:", url, error)
|
|
75
|
+
pending.signal(list(error))
|
|
76
|
+
})
|
|
77
|
+
if options.putdata {
|
|
78
|
+
if string(options.putdata)
|
|
79
|
+
request.write(options.putdata)
|
|
80
|
+
else
|
|
81
|
+
request.write(JSONstringify(options.putdata))
|
|
82
|
+
}
|
|
83
|
+
request.end()
|
|
84
|
+
pending.wait()
|
|
85
|
+
};
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
/*
|
|
89
|
+
* http_nodeInit
|
|
90
|
+
*
|
|
91
|
+
* Initialize HTTP request operations for NodeJS.
|
|
92
|
+
*
|
|
93
|
+
*/
|
|
94
|
+
|
|
95
|
+
function http_nodeInit(local manifest) {
|
|
96
|
+
manifest = `(HttpRequest, http_nodeInit)
|
|
97
|
+
|
|
98
|
+
Naan.module.build(module.id, "http_request", function(modobj, compobj) {
|
|
99
|
+
require("./node.nlg")
|
|
100
|
+
compobj.manifest = manifest
|
|
101
|
+
modobj.exports.HttpRequest = HttpRequest
|
|
102
|
+
})
|
|
103
|
+
}();
|
|
@@ -47,7 +47,8 @@
|
|
|
47
47
|
*/
|
|
48
48
|
|
|
49
49
|
closure httpsApiReqOnce(url, options,
|
|
50
|
-
local urlq, reqOptions, putdata, item, xurl, pending, chunks, request) {
|
|
50
|
+
local urlq, reqOptions, putdata, error, item, xurl, pending, chunks, request) {
|
|
51
|
+
global(js, nodeHttps, nodeUrl)
|
|
51
52
|
if options.query
|
|
52
53
|
urlq = url.concat(EncodeQuery("?", options.query))
|
|
53
54
|
else
|
|
@@ -126,7 +127,10 @@ closure httpsApiReqOnce(url, options,
|
|
|
126
127
|
debuglog("HttpsApiRequest status:", url, response.statusCode, "message:", content)
|
|
127
128
|
pending.signal(list(Error("HttpsApiRequest statusCode:", url, response.statusCode, {
|
|
128
129
|
status: response.statusCode
|
|
129
|
-
}), false, {
|
|
130
|
+
}), false, {
|
|
131
|
+
headers: response.headers
|
|
132
|
+
status: response.statusCode
|
|
133
|
+
}))
|
|
130
134
|
return
|
|
131
135
|
}
|
|
132
136
|
if response.complete {
|
|
@@ -234,28 +238,56 @@ closure sseParserFactory(message, local parser) {
|
|
|
234
238
|
*
|
|
235
239
|
*/
|
|
236
240
|
|
|
237
|
-
closure HttpsApiRequest(url, options,
|
|
241
|
+
closure HttpsApiRequest(url, options,
|
|
242
|
+
local delayf, parser, decoder, error, content, status) {
|
|
243
|
+
global(stringDecoder, common)
|
|
244
|
+
//
|
|
245
|
+
// defRetrier -- backoff and retry selected errors
|
|
246
|
+
//
|
|
247
|
+
function defRetrier(error, headers, local retryAfter, retryms, waitms) {
|
|
248
|
+
if member(error.status, `(408, 500, 502, 503, 504)) { // retriable errors
|
|
249
|
+
retryAfter = headers["retry-after"]
|
|
250
|
+
if retryAfter {
|
|
251
|
+
retryms = toint(retryAfter) * 1000
|
|
252
|
+
if !retryms
|
|
253
|
+
retryms = Date(retryAfter).getTime() - Date.now()
|
|
254
|
+
if retryms < 0
|
|
255
|
+
retryms = false
|
|
256
|
+
}
|
|
257
|
+
if !delayf
|
|
258
|
+
delayf = common.ExbackFactory(12,30) // 12s max backoff, 30s deadline
|
|
259
|
+
waitms = delayf()
|
|
260
|
+
if !waitms || waitms < retryms
|
|
261
|
+
waitms = retryms
|
|
262
|
+
if options.debug
|
|
263
|
+
debuglog("HttpsApiRequest.defRetrier: wait ${waitms} msec using retry-after ${retryAfter}")
|
|
264
|
+
if waitms // return false to give up
|
|
265
|
+
sleep(waitms) // return true from sleep to retry
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
options = merge({ retrier: defRetrier }, options)
|
|
238
270
|
if options.sseHook {
|
|
239
271
|
parser = sseParserFactory(options.sseHook)
|
|
240
272
|
decoder = xnew(stringDecoder.StringDecoder, "utf8")
|
|
241
|
-
options = merge(
|
|
273
|
+
options = merge({
|
|
242
274
|
streamHook: function(chunk) {
|
|
243
275
|
if chunk
|
|
244
276
|
parser.write(decoder.write(chunk)) // data arrived
|
|
245
277
|
else
|
|
246
278
|
parser.write(decoder.end()) // end of data
|
|
247
279
|
}
|
|
248
|
-
})
|
|
280
|
+
}, options)
|
|
249
281
|
}
|
|
250
282
|
loop {
|
|
251
|
-
|
|
252
|
-
if
|
|
253
|
-
if !options.retrier(
|
|
283
|
+
`(error, content, status) = httpsApiReqOnce(url, options)
|
|
284
|
+
if error && error.status { // check for retries
|
|
285
|
+
if !options.retrier(error, status.headers)
|
|
254
286
|
break
|
|
255
287
|
} else
|
|
256
288
|
break
|
|
257
289
|
}
|
|
258
|
-
|
|
290
|
+
list(error, content, status)
|
|
259
291
|
};
|
|
260
292
|
|
|
261
293
|
|
|
@@ -271,6 +303,7 @@ function https_nodeInit(local manifest) {
|
|
|
271
303
|
|
|
272
304
|
Naan.module.build(module.id, "https_request", function(modobj, compobj) {
|
|
273
305
|
require("./node.nlg")
|
|
306
|
+
common = require("../common/utils.nlg")
|
|
274
307
|
compobj.manifest = manifest
|
|
275
308
|
modobj.exports.HttpsApiRequest = HttpsApiRequest
|
|
276
309
|
})
|
package/frameworks/node/node.nlg
CHANGED
|
@@ -296,7 +296,7 @@ closure projConnector(projman, projtype, local connector, watch) {
|
|
|
296
296
|
*
|
|
297
297
|
* Nide.proj/
|
|
298
298
|
* nide_cliser.cfg - JSON definition of the project (see below)
|
|
299
|
-
* NaanIDE_version.txt - [default] substitution file defining 1.4.
|
|
299
|
+
* NaanIDE_version.txt - [default] substitution file defining 1.4.4+1 etc.
|
|
300
300
|
* NaanIDE_version_builds.txt - [default] contains current build number as decimal string
|
|
301
301
|
* build/ - [optional] default build output location
|
|
302
302
|
* NaanIDE.lic - [optional] defines Zulch Laboratories, Inc. and other license info
|
|
@@ -22,6 +22,7 @@ closure ExecutorBase(track, type, name, local exec) {
|
|
|
22
22
|
exec = new(object, this)
|
|
23
23
|
exec.type = type
|
|
24
24
|
exec.name = name
|
|
25
|
+
exec.contexts = { }
|
|
25
26
|
|
|
26
27
|
// execReset
|
|
27
28
|
//
|
|
@@ -57,6 +58,18 @@ closure ExecutorBase(track, type, name, local exec) {
|
|
|
57
58
|
// The specified message was received from the instance, so signal it.
|
|
58
59
|
//
|
|
59
60
|
exec.execReceived = closure execReceived(data, local pending) {
|
|
61
|
+
if data.reverse {
|
|
62
|
+
if !exec.contexts[data.contextID]
|
|
63
|
+
return // ignore unknown context
|
|
64
|
+
if !exec.reverseDispatch
|
|
65
|
+
exec.reverseDispatch = require("./taskexec.nlg").TaskDispatcher(function(data) {
|
|
66
|
+
data.reverse = true
|
|
67
|
+
exec.PostMessage(data)
|
|
68
|
+
}, exec.contexts[data.contextID].coder)
|
|
69
|
+
data.reverse = false
|
|
70
|
+
exec.reverseDispatch(data)
|
|
71
|
+
return
|
|
72
|
+
}
|
|
60
73
|
pending = exec.pending[data.xid]
|
|
61
74
|
if !pending { // not waiting on message
|
|
62
75
|
if data.xmsg == "xready"
|
|
@@ -110,7 +123,7 @@ closure ExecutorBase(track, type, name, local exec) {
|
|
|
110
123
|
// persistent reconnection. Currently this does not ever reclaim old contexts on the instance
|
|
111
124
|
// end of things, but it should. ###
|
|
112
125
|
//
|
|
113
|
-
exec.context = closure context(state, local error, retries, ms, delta, excon) {
|
|
126
|
+
exec.context = closure context(state, coder, local error, retries, ms, delta, excon) {
|
|
114
127
|
retries = 0
|
|
115
128
|
ms = milliseconds()
|
|
116
129
|
delta = 1
|
|
@@ -127,8 +140,14 @@ closure ExecutorBase(track, type, name, local exec) {
|
|
|
127
140
|
sleep(delta)
|
|
128
141
|
if delta < 100
|
|
129
142
|
delta *= 2 }
|
|
130
|
-
excon = ExecutorContext(exec, state)
|
|
131
|
-
excon.register()
|
|
143
|
+
excon = ExecutorContext(exec, state, coder)
|
|
144
|
+
`(error) = excon.register()
|
|
145
|
+
if error
|
|
146
|
+
list(error)
|
|
147
|
+
else {
|
|
148
|
+
exec.contexts[excon.state.contextID] = excon
|
|
149
|
+
list(false, excon)
|
|
150
|
+
}
|
|
132
151
|
}
|
|
133
152
|
|
|
134
153
|
// attention
|
|
@@ -160,7 +179,7 @@ closure ExecutorBase(track, type, name, local exec) {
|
|
|
160
179
|
*
|
|
161
180
|
*/
|
|
162
181
|
|
|
163
|
-
closure ExecutorContext(exec, state, local context,
|
|
182
|
+
closure ExecutorContext(exec, state, coder, local context, util) {
|
|
164
183
|
global(apply)
|
|
165
184
|
context = new(object, this)
|
|
166
185
|
if !state || !state.contextID
|
|
@@ -168,7 +187,7 @@ closure ExecutorContext(exec, state, local context, coder, util) {
|
|
|
168
187
|
contextID: UUID()
|
|
169
188
|
}
|
|
170
189
|
context.state = state
|
|
171
|
-
coder = packageCoder(evalf)
|
|
190
|
+
context.coder = coder || packageCoder(evalf)
|
|
172
191
|
util = modlist().Util.exports
|
|
173
192
|
|
|
174
193
|
// getState
|
|
@@ -208,7 +227,7 @@ closure ExecutorContext(exec, state, local context, coder, util) {
|
|
|
208
227
|
pkg = util.pkgSave(`expr, roots, {
|
|
209
228
|
nsignore: true
|
|
210
229
|
comments: true
|
|
211
|
-
objectEncoder: coder.encodeObject
|
|
230
|
+
objectEncoder: context.coder.encodeObject
|
|
212
231
|
})
|
|
213
232
|
data = {
|
|
214
233
|
contextID: state.contextID
|
|
@@ -224,7 +243,7 @@ closure ExecutorContext(exec, state, local context, coder, util) {
|
|
|
224
243
|
localroots: false
|
|
225
244
|
intern: "symbols"
|
|
226
245
|
execute: false
|
|
227
|
-
objectDecoder: coder.decodeObject
|
|
246
|
+
objectDecoder: context.coder.decodeObject
|
|
228
247
|
})))
|
|
229
248
|
else
|
|
230
249
|
result
|