@naanlang/naan 1.0.2 → 1.0.5
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 +10 -8
- package/bin/index.js +2 -2
- package/dist/env_web.js +172 -22
- package/dist/naan.min.js +6 -6
- package/frameworks/browser/https_request.nlg +120 -0
- package/frameworks/browser/sworker.js +299 -91
- package/frameworks/browser/terminals.nlg +28 -13
- package/frameworks/browser/workers.nlg +27 -12
- package/frameworks/client/apiclient.nlg +17 -4
- package/frameworks/client/psm_client.nlg +184 -81
- package/frameworks/common/common.nlg +105 -25
- package/frameworks/common/preferences.nlg +1 -0
- package/frameworks/common/watching.nlg +1 -0
- package/frameworks/node/apiserver.nlg +31 -15
- package/frameworks/node/filesystem.nlg +230 -46
- package/frameworks/node/gitter.nlg +27 -6
- package/frameworks/node/https_request.nlg +119 -0
- package/frameworks/node/node.nlg +1 -0
- package/frameworks/node/psm_server.nlg +113 -37
- package/frameworks/project/build.nlg +40 -23
- package/frameworks/project/proj_cliser.nlg +11 -3
- package/frameworks/project/proj_console.nlg +13 -4
- package/frameworks/project/proj_folder.nlg +10 -1
- package/frameworks/project/proj_lambda.nlg +13 -4
- package/frameworks/project/proj_static.nlg +11 -3
- package/frameworks/project/projects.nlg +128 -40
- package/frameworks/running/debugnub.nlg +2 -5
- package/frameworks/running/executors.nlg +1 -0
- package/frameworks/storage/csv.nlg +120 -0
- package/frameworks/storage/dbt_pouch.nlg +41 -25
- package/frameworks/storage/psm.nlg +108 -28
- package/frameworks/storage/psm_dbtables.nlg +7 -3
- package/frameworks/storage/resources.nlg +30 -2
- package/lib/browser/env_web.js +170 -20
- package/lib/browser/env_webworker.js +1 -1
- package/lib/browser/require.js +1 -1
- package/lib/core/naanlib.js +6 -6
- package/package.json +2 -1
- package/plugins/serviceAws/aws/aws-sdk-node.min.js +2 -0
- package/plugins/serviceAws/aws/aws-sdk.min.js +2 -88
- package/plugins/serviceAws/aws_cloudwatchlogs.nlg +8 -7
- package/plugins/serviceAws/aws_dynamo.nlg +715 -148
- package/plugins/serviceAws/aws_dynextra.nlg +294 -0
- package/plugins/serviceAws/aws_lambda.nlg +11 -4
- package/plugins/serviceAws/aws_s3.nlg +44 -14
- package/plugins/serviceAws/dbt_aws.nlg +58 -45
- package/plugins/serviceAws/psm_aws.nlg +61 -40
- package/plugins/serviceAws/serviceAws.nlg +7 -4
- package/plugins/serviceGitHub/psm_github.nlg +41 -25
- package/plugins/serviceGitLab/psm_gitlab.nlg +41 -25
- package/test/harness.nlg +3 -1
- package/test/test_01_core.nlg +5 -5
- package/test/test_02_context.nlg +4 -4
- package/test/test_03_jsinterop.nlg +9 -3
- package/plugins/serviceAws/aws_cognito.nlg +0 -76
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* https_browser.nlg
|
|
3
|
+
*
|
|
4
|
+
* Https operations for the browser.
|
|
5
|
+
*
|
|
6
|
+
* column positioning: // // !
|
|
7
|
+
*
|
|
8
|
+
* Copyright (c) 2021-2022 by Richard C. Zulch
|
|
9
|
+
*
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
/*
|
|
14
|
+
* HttpsApiRequest
|
|
15
|
+
*
|
|
16
|
+
* Perform an API request from the browser. This operates the same as HttpsApiRequest for NodeJS.
|
|
17
|
+
*
|
|
18
|
+
* Options:
|
|
19
|
+
* {
|
|
20
|
+
* method: <string> // HTTP method (defaults to GET/PUT)
|
|
21
|
+
* query: <dictionary> // query variables added to the URL
|
|
22
|
+
* putdata: <data> // data to put
|
|
23
|
+
* contentType: <string> // sets Content-Type header, otherwise auto-determined
|
|
24
|
+
* encoding: <string> // "binary" to receive binary data as arrayBuffer
|
|
25
|
+
* range: <string> // sets range header
|
|
26
|
+
* headers: [`(key, value)] // add header(s) to the request, overriding defaults
|
|
27
|
+
* }
|
|
28
|
+
*
|
|
29
|
+
*/
|
|
30
|
+
|
|
31
|
+
closure HttpsApiRequest(url, options,
|
|
32
|
+
local urlq, fetchOptions, putdata, error, response, contentType, content) {
|
|
33
|
+
if !options
|
|
34
|
+
options = { }
|
|
35
|
+
if options.query
|
|
36
|
+
urlq = url.concat(EncodeQuery("?", options.query))
|
|
37
|
+
else
|
|
38
|
+
urlq = url
|
|
39
|
+
putdata = options.putdata
|
|
40
|
+
fetchOptions = {
|
|
41
|
+
mode: 'cors'
|
|
42
|
+
cache: 'no-cache'
|
|
43
|
+
credentials: 'same-origin'
|
|
44
|
+
headers: { }
|
|
45
|
+
redirect: 'follow'
|
|
46
|
+
referrerPolicy: 'no-referrer'
|
|
47
|
+
}
|
|
48
|
+
if options.method
|
|
49
|
+
fetchOptions.method = options.method
|
|
50
|
+
else if putdata
|
|
51
|
+
fetchOptions.method = "POST"
|
|
52
|
+
else
|
|
53
|
+
fetchOptions.method = "GET"
|
|
54
|
+
if putdata {
|
|
55
|
+
if options.contentType
|
|
56
|
+
fetchOptions.headers['Content-Type'] = options.contentType
|
|
57
|
+
else if jsTypedArray(options.putdata)
|
|
58
|
+
fetchOptions.headers['Content-Type'] = "application/octet-stream"
|
|
59
|
+
else if member(typeof(options.putdata), `(dictionary, array, xobject)) {
|
|
60
|
+
fetchOptions.headers['Content-Type'] = "application/json"
|
|
61
|
+
`(error, putdata) = JsonStringify(options.putdata)
|
|
62
|
+
if error
|
|
63
|
+
return (list(Error("HttpsApiRequest encode:", url)))
|
|
64
|
+
}
|
|
65
|
+
fetchOptions.body = putdata
|
|
66
|
+
}
|
|
67
|
+
if options.range
|
|
68
|
+
fetchOptions.headers.Range = options.range
|
|
69
|
+
if array(options.headers)
|
|
70
|
+
for item in options.headers
|
|
71
|
+
fetchOptions.headers[item.0] = item.1
|
|
72
|
+
//
|
|
73
|
+
// perform the fetch and return when complete
|
|
74
|
+
//
|
|
75
|
+
`(error, response) = await(js.w.fetch(urlq, fetchOptions))
|
|
76
|
+
if error
|
|
77
|
+
return (list(Error("HttpsApiRequest fetch failed:", error, url)))
|
|
78
|
+
contentType = response.headers.get("content-type")
|
|
79
|
+
if response.status < 200 || response.status >= 300
|
|
80
|
+
return (list(Error("HttpsApiRequest status:", url, response.status, {
|
|
81
|
+
status: response.status
|
|
82
|
+
})))
|
|
83
|
+
if contentType.startsWith("application/json") {
|
|
84
|
+
`(error, content) = await(response.text())
|
|
85
|
+
if !error
|
|
86
|
+
`(error, content) = JsonParse(content)
|
|
87
|
+
if error
|
|
88
|
+
error = Error("HttpsApiRequest decode:", url, error)
|
|
89
|
+
else
|
|
90
|
+
content = new(content)
|
|
91
|
+
if array(content) { // deencapsulate to get API result
|
|
92
|
+
content = totuple(content)
|
|
93
|
+
error = content.0
|
|
94
|
+
content = content.1
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
else if options.encoding == "binary"
|
|
98
|
+
`(error, content) = await(response.arrayBuffer())
|
|
99
|
+
else
|
|
100
|
+
`(error, content) = await(response.text())
|
|
101
|
+
list(error, content)
|
|
102
|
+
};
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
/*
|
|
106
|
+
* https_browserInit
|
|
107
|
+
*
|
|
108
|
+
* Initialize HTTPS request operations for browsers.
|
|
109
|
+
*
|
|
110
|
+
*/
|
|
111
|
+
|
|
112
|
+
function https_browserInit(local manifest) {
|
|
113
|
+
manifest = `(HttpsApiRequest, https_browserInit)
|
|
114
|
+
|
|
115
|
+
Naan.module.build(module.id, "https_request", function(modobj, compobj) {
|
|
116
|
+
require("./browser.nlg")
|
|
117
|
+
compobj.manifest = manifest
|
|
118
|
+
modobj.exports.HttpsApiRequest = HttpsApiRequest
|
|
119
|
+
})
|
|
120
|
+
}();
|
|
@@ -4,66 +4,309 @@
|
|
|
4
4
|
*
|
|
5
5
|
* Nide service worker script.
|
|
6
6
|
*
|
|
7
|
+
* The goal of this service worker is to 1) cache fetch requests for static content, and 2) relay
|
|
8
|
+
* fetch requests in the /run/ URL path namespace to instances of the IDE that can provide it. The
|
|
9
|
+
* identifier for the various browser windows is by "clientId", which is a GUID reported by the
|
|
10
|
+
* service worker and message channel APIs. Here we use the term clientId to refer to windows that
|
|
11
|
+
* consume data in the /run/ path, i.e. the IDE targets, and the term sourceId to refer to windows
|
|
12
|
+
* that provide data, i.e. the IDE instances.
|
|
13
|
+
* When the service worker is first executed it sends messages to all known windows requesting
|
|
14
|
+
* that they establish a message channel and forward the service worker's port to it. This secondary
|
|
15
|
+
* channel is used to communicate fetch requests from the service worker to the source IDE and then
|
|
16
|
+
* get the response. If an IDE is executed subsequently then it registers itself by sending the port
|
|
17
|
+
* unilatterally, instead of waiting to be requested.
|
|
18
|
+
* The service worker gets a fetch request when a non-cached resource is requested by a client
|
|
19
|
+
* window. If the URL path is not within /run/ then this executes a normal network request. IF the
|
|
20
|
+
* URL path is within /run/ then this asks the IDE source(s) to fetch it. Initially every IDE source
|
|
21
|
+
* is sent the request, but when one provides a 200 response then this stores that source port under
|
|
22
|
+
* the clientId in fetchPorts so that subsequent requests can go only to the correct IDE. This works
|
|
23
|
+
* great until an IDE goes away or becomes unresponsive.
|
|
24
|
+
* Unfortunately there is no event that tells us when a window is closed or goes away. The first
|
|
25
|
+
* indication of trouble is when an IDE fails to respond within a reasonable amount of time, which
|
|
26
|
+
* could be anything. We can enumerates the valid clients, which gives us a chance to validate our
|
|
27
|
+
* knowledge of which ones are responding. If a request takes longer than a second to respond then
|
|
28
|
+
* this executes a validate operation, which eliminates any clients that have gone away and rejects
|
|
29
|
+
* their pending operations.
|
|
30
|
+
* One potential problem is stale caches. When an older version is discovered then we notify the
|
|
31
|
+
* client and invalidate the old cache.
|
|
32
|
+
*
|
|
7
33
|
* column positioning: // // !
|
|
8
34
|
*
|
|
9
|
-
* Copyright (c) 2020 by Richard C. Zulch
|
|
35
|
+
* Copyright (c) 2020-2022 by Richard C. Zulch
|
|
10
36
|
*
|
|
11
37
|
*/
|
|
12
38
|
|
|
13
|
-
var CurrentCacheName = "
|
|
39
|
+
var CurrentCacheName = "Naanlang-1.0.5-2";
|
|
14
40
|
|
|
15
41
|
|
|
16
42
|
//
|
|
17
43
|
// locals
|
|
18
44
|
//
|
|
19
45
|
|
|
20
|
-
var fetchQueue = [];
|
|
21
|
-
var fetchNextSeq = 1;
|
|
22
|
-
var
|
|
46
|
+
var fetchQueue = []; // queue for outstanding requests to sources
|
|
47
|
+
var fetchNextSeq = 1; // sequence number for source requests
|
|
48
|
+
var msgPorts = {}; // message ports keyed by sourceId
|
|
49
|
+
var fetchPorts = {}; // message ports keyed by clientId
|
|
50
|
+
var waitingForInit = []; // initialization functions, or false after done
|
|
23
51
|
|
|
24
52
|
|
|
25
53
|
/*
|
|
26
|
-
*
|
|
54
|
+
* initialize
|
|
27
55
|
*
|
|
28
|
-
*
|
|
56
|
+
* Initiate listening for incoming messages from our clients. This waits for any client responses
|
|
57
|
+
* and then quits. Any clients that want to participate after that must unilaterally send a port for
|
|
58
|
+
* communication.
|
|
29
59
|
*
|
|
30
60
|
*/
|
|
31
61
|
|
|
32
|
-
|
|
62
|
+
(function initialize() {
|
|
63
|
+
if (!waitingForInit)
|
|
64
|
+
return; // already initialized
|
|
65
|
+
var pending = 0;
|
|
66
|
+
|
|
67
|
+
// doneInit
|
|
68
|
+
//
|
|
69
|
+
// Call this to resolve any waiting promises and release them for attempting to fetch from the
|
|
70
|
+
// IDEs (sources.)
|
|
71
|
+
//
|
|
72
|
+
function doneInit() {
|
|
73
|
+
if (!waitingForInit)
|
|
74
|
+
return; // already done
|
|
75
|
+
var waiters = waitingForInit;
|
|
76
|
+
waitingForInit = false; // no more waiters allowed
|
|
77
|
+
for (var wdex in waiters)
|
|
78
|
+
waiters[wdex](); // call each waiter
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// self.onmessage events
|
|
82
|
+
//
|
|
83
|
+
// This receives channel port messages from the IDEs as they either 1) respond to a request to
|
|
84
|
+
// register, or 2) spontaneously register themselves as they notice that we're running.
|
|
85
|
+
//
|
|
33
86
|
self.addEventListener('message', function(event) {
|
|
34
|
-
|
|
35
|
-
|
|
87
|
+
var msgport = event.data.hereIsYourPort; // message port of a client
|
|
88
|
+
var pubID = event.data.hereIsMyID;
|
|
89
|
+
var pubVersion = event.data.hereIsMyVersion;
|
|
90
|
+
var sourceId = event.source.id; // client id of sender of message
|
|
91
|
+
msgPorts[sourceId] = msgport;
|
|
92
|
+
console.log("[1.0.5-2] received new msgport for", sourceId, pubID, "-", pubVersion);
|
|
93
|
+
if (pubVersion != "1.0.5-2")
|
|
94
|
+
msgport.postMessage({ // notify new version available
|
|
95
|
+
id: "upgrade",
|
|
96
|
+
version: "1.0.5-2"
|
|
97
|
+
});
|
|
98
|
+
Reaper(); // clean up obsolete info
|
|
99
|
+
|
|
100
|
+
// msgport.onmessage events
|
|
101
|
+
//
|
|
102
|
+
// This receives channel port messages that are responding to our fetch requests. The IDE
|
|
103
|
+
// can also send a text message for logging, but that is used only for debugging.
|
|
104
|
+
//
|
|
36
105
|
msgport.onmessage = function(msg) {
|
|
37
106
|
msg = msg.data;
|
|
38
107
|
if (msg.id == "response")
|
|
39
|
-
|
|
108
|
+
processResponse(msg);
|
|
40
109
|
else if (msg.id == "text")
|
|
41
|
-
console.log("[1.0.2
|
|
110
|
+
console.log("[1.0.5-2] msg received:", msg.text);
|
|
42
111
|
};
|
|
43
|
-
|
|
44
|
-
//
|
|
45
|
-
msgport.postMessage({
|
|
46
|
-
id: "text",
|
|
47
|
-
text: "port received by 1.0.2-1",
|
|
48
|
-
});
|
|
49
|
-
*/
|
|
50
|
-
resolve(msgport);
|
|
51
|
-
|
|
112
|
+
|
|
113
|
+
// send text to IDE log
|
|
52
114
|
//
|
|
53
|
-
//
|
|
115
|
+
// This is only for debugging.
|
|
54
116
|
//
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
117
|
+
/*
|
|
118
|
+
// don't clutter the log
|
|
119
|
+
msgport.postMessage({
|
|
120
|
+
id: "text",
|
|
121
|
+
text: "port received by 1.0.5-2",
|
|
122
|
+
});
|
|
123
|
+
*/
|
|
124
|
+
if (--pending === 0)
|
|
125
|
+
doneInit(); // we finished all known clients
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
// initialize known IDE instances.
|
|
129
|
+
//
|
|
130
|
+
// This sends a port request to each known IDE instance. Fetches that occur prior to completion
|
|
131
|
+
// of initialization will wait for these instances to respond. A timeout prevents one errant IDE
|
|
132
|
+
// from hanging all requests, by releasing the fetches even before all source IDEs respond.
|
|
133
|
+
//
|
|
134
|
+
self.clients.matchAll({
|
|
135
|
+
includeUncontrolled: true
|
|
136
|
+
}).then(function(clientList) {
|
|
137
|
+
clientList.every(function(client) {
|
|
138
|
+
console.log("[1.0.5-2] requesting new msgport for", client.id);
|
|
139
|
+
++pending;
|
|
140
|
+
client.postMessage({ // tell client(s) we need this fetch source
|
|
141
|
+
msg: "Naan_need_fetch_port",
|
|
142
|
+
});
|
|
143
|
+
});
|
|
144
|
+
setTimeout(doneInit, 10000); // release fetches
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
// processResponse
|
|
148
|
+
//
|
|
149
|
+
// An IDE source has responded to our fetch request. If this was successful then we record the
|
|
150
|
+
// IDE (sourceId) so that subsequent requests from that target (clientId) will go to the same
|
|
151
|
+
// source.
|
|
152
|
+
//
|
|
153
|
+
function processResponse(msg) {
|
|
154
|
+
var fqdex, response, item;
|
|
155
|
+
for (fqdex = 0; fqdex < fetchQueue.length; ++fqdex)
|
|
156
|
+
if (fetchQueue[fqdex].seq === msg.seq) {
|
|
157
|
+
item = fetchQueue.splice(fqdex, 1)[0];
|
|
158
|
+
if (item.clientId && msg.init.status == 200)
|
|
159
|
+
fetchPorts[item.clientId] = item.msgport; // successful lookup
|
|
160
|
+
item.resolve(new Response(msg.body, msg.init));
|
|
161
|
+
break;
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
})();
|
|
165
|
+
|
|
166
|
+
|
|
167
|
+
/*
|
|
168
|
+
* Reaper
|
|
169
|
+
*
|
|
170
|
+
* Periodic cleanup returning a promise. This removes anything that is obsolete and resolve all
|
|
171
|
+
* associated transactions.
|
|
172
|
+
*
|
|
173
|
+
*/
|
|
174
|
+
|
|
175
|
+
function Reaper() {
|
|
176
|
+
var promise = self.clients.matchAll({
|
|
177
|
+
includeUncontrolled: true
|
|
178
|
+
}).then(function(clientList) { // both sources and clients
|
|
179
|
+
var clients = {};
|
|
180
|
+
for (var clidex in clientList)
|
|
181
|
+
clients[clientList[clidex].id] = clientList[clidex];
|
|
182
|
+
for (var sourceId in msgPorts)
|
|
183
|
+
if (!clients[sourceId]) {
|
|
184
|
+
console.log("[1.0.5-2] source gone:", sourceId);
|
|
185
|
+
delete msgPorts[sourceId]; // no longer a source
|
|
186
|
+
}
|
|
187
|
+
for (var clientId in fetchPorts)
|
|
188
|
+
if (!clients[clientId]) {
|
|
189
|
+
console.log("[1.0.5-2] client gone:", clientId);
|
|
190
|
+
delete fetchPorts[clientId]; // no longer a client
|
|
191
|
+
}
|
|
192
|
+
for (var fqdex = 0; fqdex < fetchQueue.length; ++fqdex) {
|
|
193
|
+
var item = fetchQueue[fqdex];
|
|
194
|
+
while (item.clientId && !clients[item.clientId]
|
|
195
|
+
|| !Object.values(msgPorts).includes(item.msgport)) {
|
|
196
|
+
fetchQueue.splice(fqdex, 1); // either client or source missing
|
|
197
|
+
item.resolve(new Response(undefined, {
|
|
198
|
+
status: 404,
|
|
199
|
+
statusText: "Source Disappeared" // if client is gone this disappears too
|
|
200
|
+
}));
|
|
201
|
+
if (fqdex >= fetchQueue.length)
|
|
202
|
+
break; // we've run out of transactions
|
|
203
|
+
item = fetchQueue[fqdex];
|
|
204
|
+
}
|
|
64
205
|
}
|
|
65
206
|
});
|
|
66
|
-
|
|
207
|
+
return (promise);
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
|
|
211
|
+
/*
|
|
212
|
+
* ClearCaches
|
|
213
|
+
*
|
|
214
|
+
* Clear obsolete caches, returning a promise.
|
|
215
|
+
*
|
|
216
|
+
*/
|
|
217
|
+
|
|
218
|
+
function ClearCaches() {
|
|
219
|
+
var promise = caches.keys().then(function(cacheNames) { // delete old cache entries
|
|
220
|
+
return (Promise.all(
|
|
221
|
+
cacheNames.map(function(cacheName) {
|
|
222
|
+
if (cacheName != CurrentCacheName) {
|
|
223
|
+
console.log('[1.0.5-2] deleting old cache:', cacheName);
|
|
224
|
+
return (caches.delete(cacheName));
|
|
225
|
+
}
|
|
226
|
+
})
|
|
227
|
+
));
|
|
228
|
+
}).then(function() { // claim all clients
|
|
229
|
+
console.log('[1.0.5-2] claiming clients');
|
|
230
|
+
return (self.clients.claim());
|
|
231
|
+
});
|
|
232
|
+
return (promise);
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
|
|
236
|
+
/*
|
|
237
|
+
* GetClientResponse
|
|
238
|
+
*
|
|
239
|
+
* Get message ports from the current clients if they can supply contents for the specified URL.
|
|
240
|
+
* This returns a promise that is resolved after the msgPorts object is updated. Note that the
|
|
241
|
+
* clientId argument is the requester, but the client that actually has the available data will
|
|
242
|
+
* often be a different window.
|
|
243
|
+
* On the first request from a given client, every source is requested to respond to the URL
|
|
244
|
+
* pathname, and the first one that does is designated the official source for that client. While
|
|
245
|
+
* asking all the sources, this checks every second to see if any of them have gone away so that it
|
|
246
|
+
* does not hang waiting. A source can be unresponsive and delay the fetch forever, e.g. in the
|
|
247
|
+
* debugger, but if the window has closed then it will get reaped and the fetch will complete.
|
|
248
|
+
* On subsequent requests, to a known source, this does not have a timeout. If the source goes
|
|
249
|
+
* away then the fetch will not complete, but the client is screwed anyway in that case. Eventually
|
|
250
|
+
* the reaper will be called for other reasons and it will clean things up then.
|
|
251
|
+
*
|
|
252
|
+
*/
|
|
253
|
+
|
|
254
|
+
function GetClientResponse(event, urlpath) {
|
|
255
|
+
|
|
256
|
+
// delegate
|
|
257
|
+
//
|
|
258
|
+
// Delegate to a source window and return a promise
|
|
259
|
+
//
|
|
260
|
+
function delegate(msgport, clientId) {
|
|
261
|
+
return (new Promise(function(resolve, reject) {
|
|
262
|
+
var seqno = fetchNextSeq++;
|
|
263
|
+
fetchQueue.push({
|
|
264
|
+
seq: seqno,
|
|
265
|
+
msgport: msgport,
|
|
266
|
+
clientId: clientId,
|
|
267
|
+
resolve: resolve
|
|
268
|
+
});
|
|
269
|
+
msgport.postMessage({
|
|
270
|
+
id: "fetch",
|
|
271
|
+
seq: seqno,
|
|
272
|
+
version: "1.0.5-2",
|
|
273
|
+
request: {
|
|
274
|
+
method: event.request.method,
|
|
275
|
+
url: event.request.url
|
|
276
|
+
},
|
|
277
|
+
});
|
|
278
|
+
}));
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
var clientId;
|
|
282
|
+
if (event.clientId !== "") {
|
|
283
|
+
clientId = event.clientId;
|
|
284
|
+
if (fetchPorts[clientId])
|
|
285
|
+
return (delegate(fetchPorts[clientId], false));
|
|
286
|
+
}
|
|
287
|
+
else
|
|
288
|
+
clientId = event.resultingClientId; // new window
|
|
289
|
+
var pending = [];
|
|
290
|
+
var sourceIds = Object.getOwnPropertyNames(msgPorts);
|
|
291
|
+
for (var mdex = 0; mdex < sourceIds.length; ++mdex)
|
|
292
|
+
{
|
|
293
|
+
var sourceId = sourceIds[mdex];
|
|
294
|
+
pending.push(delegate(msgPorts[sourceId], clientId));
|
|
295
|
+
}
|
|
296
|
+
if (pending.length === 0)
|
|
297
|
+
return (Promise.resolve(new Response(undefined, {
|
|
298
|
+
status: 404,
|
|
299
|
+
statusText: "No Sources"
|
|
300
|
+
})));
|
|
301
|
+
var toid = setInterval(Reaper, 1000); // reap every second while pending
|
|
302
|
+
return (Promise.all(pending).then(function(responses) {
|
|
303
|
+
clearInterval(toid); // all completed
|
|
304
|
+
for (var idex in responses)
|
|
305
|
+
if (responses[idex].status == 200)
|
|
306
|
+
return (responses[idex]); // this is the one we want
|
|
307
|
+
return (responses[0]); // fall back to first
|
|
308
|
+
}));
|
|
309
|
+
}
|
|
67
310
|
|
|
68
311
|
|
|
69
312
|
/*
|
|
@@ -74,7 +317,7 @@ var promiseport = new Promise(function (resolve, reject) {
|
|
|
74
317
|
*/
|
|
75
318
|
|
|
76
319
|
self.addEventListener('install', function(event) {
|
|
77
|
-
console.log("[1.0.2
|
|
320
|
+
console.log("[1.0.5-2] install");
|
|
78
321
|
self.skipWaiting();
|
|
79
322
|
});
|
|
80
323
|
|
|
@@ -95,53 +338,30 @@ self.addEventListener('fetch', function(event) {
|
|
|
95
338
|
var tid;
|
|
96
339
|
var promise;
|
|
97
340
|
var url = new URL(event.request.url);
|
|
98
|
-
var nocache = event.method != "GET"
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
var urls = clientList.map(function(client) {
|
|
108
|
-
client.postMessage({ // tell client(s) we need a fetch source
|
|
109
|
-
msg: "Naan_need_fetch_port"
|
|
110
|
-
});
|
|
111
|
-
return (client.url);
|
|
341
|
+
var nocache = event.request.method != "GET"
|
|
342
|
+
|| url.search.length !== 0
|
|
343
|
+
|| event.request.headers.get('range');
|
|
344
|
+
if (url.pathname.startsWith("/run/")) {
|
|
345
|
+
nocache = true;
|
|
346
|
+
if (waitingForInit) {
|
|
347
|
+
promise = new Promise(function(resolve, reject) {
|
|
348
|
+
waitingForInit.push(function(){
|
|
349
|
+
resolve(); // init was complete
|
|
112
350
|
});
|
|
113
|
-
|
|
114
|
-
return (
|
|
351
|
+
}).then(function(){
|
|
352
|
+
return (GetClientResponse(event, url.pathname)); // then get the response
|
|
115
353
|
});
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
/*
|
|
119
|
-
tid = setTimeout( function() {
|
|
120
|
-
reject("timeout!");
|
|
121
|
-
}, 250); */
|
|
122
|
-
var seqno = fetchNextSeq++;
|
|
123
|
-
if (msgport) {
|
|
124
|
-
fetchQueue.push({
|
|
125
|
-
seq: seqno,
|
|
126
|
-
resolve: resolve
|
|
127
|
-
});
|
|
128
|
-
msgport.postMessage({
|
|
129
|
-
id: "fetch",
|
|
130
|
-
seq: seqno,
|
|
131
|
-
version: "1.0.2-1",
|
|
132
|
-
request: {
|
|
133
|
-
method: event.request.method,
|
|
134
|
-
url: event.request.url
|
|
135
|
-
},
|
|
136
|
-
});
|
|
137
|
-
} else {
|
|
138
|
-
console.log("[1.0.2-1] fetch has no msgport");
|
|
139
|
-
return (reject("fatal delegation error"));
|
|
140
|
-
}
|
|
141
|
-
}) });
|
|
354
|
+
} else
|
|
355
|
+
promise = GetClientResponse(event, url.pathname);
|
|
142
356
|
}
|
|
143
357
|
else
|
|
144
|
-
promise = fetch(event.request)
|
|
358
|
+
promise = fetch(event.request).catch(function (e) {
|
|
359
|
+
console.log("[1.0.5-2] fetch failed", e);
|
|
360
|
+
return (new Response(undefined, {
|
|
361
|
+
status: 404,
|
|
362
|
+
statusText: "Fetch Failed"
|
|
363
|
+
}));
|
|
364
|
+
});
|
|
145
365
|
return (promise.then(function(response) {
|
|
146
366
|
// delete tid timer ###
|
|
147
367
|
if (!nocache) {
|
|
@@ -165,28 +385,16 @@ self.addEventListener('fetch', function(event) {
|
|
|
165
385
|
*/
|
|
166
386
|
|
|
167
387
|
self.addEventListener('activate', function(event) {
|
|
168
|
-
console.log("[1.0.2
|
|
388
|
+
console.log("[1.0.5-2] activate");
|
|
169
389
|
self.clients.matchAll({ // for debugging, list controlled clients
|
|
170
390
|
includeUncontrolled: true
|
|
171
391
|
}).then(function(clientList) {
|
|
172
392
|
var urls = clientList.map(function(client) {
|
|
173
393
|
return (client.url);
|
|
174
394
|
});
|
|
175
|
-
console.log('[1.0.2
|
|
395
|
+
console.log('[1.0.5-2] matching clients:', urls.join(', '));
|
|
176
396
|
});
|
|
177
|
-
var promise =
|
|
178
|
-
return (Promise.all(
|
|
179
|
-
cacheNames.map(function(cacheName) {
|
|
180
|
-
if (cacheName !== CurrentCacheName) {
|
|
181
|
-
console.log('[1.0.2-1] deleting old cache:', cacheName);
|
|
182
|
-
return (caches.delete(cacheName));
|
|
183
|
-
}
|
|
184
|
-
})
|
|
185
|
-
));
|
|
186
|
-
}).then(function() { // claim all clients
|
|
187
|
-
console.log('[1.0.2-1] claiming clients for version', CurrentCacheName);
|
|
188
|
-
return (self.clients.claim());
|
|
189
|
-
});
|
|
397
|
+
var promise = ClearCaches();
|
|
190
398
|
if (event.waitUntil)
|
|
191
399
|
event.waitUntil(promise);
|
|
192
400
|
});
|