@naanlang/naan 1.0.2 → 1.0.3
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 +3 -3
- package/bin/index.js +2 -2
- package/dist/env_web.js +149 -20
- package/dist/naan.min.js +5 -5
- package/frameworks/browser/sworker.js +309 -91
- package/frameworks/browser/terminals.nlg +22 -9
- package/frameworks/browser/workers.nlg +19 -11
- package/frameworks/client/apiclient.nlg +17 -4
- package/frameworks/client/psm_client.nlg +116 -53
- package/frameworks/common/common.nlg +12 -2
- package/frameworks/node/apiserver.nlg +25 -13
- package/frameworks/node/filesystem.nlg +173 -30
- package/frameworks/node/psm_server.nlg +95 -32
- package/frameworks/project/build.nlg +40 -23
- package/frameworks/project/projects.nlg +47 -26
- package/frameworks/running/debugnub.nlg +2 -5
- 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 +147 -18
- package/lib/browser/env_webworker.js +1 -1
- package/lib/browser/require.js +1 -1
- package/lib/core/naanlib.js +5 -5
- package/package.json +1 -1
- package/plugins/serviceAws/aws_cloudwatchlogs.nlg +1 -1
- package/plugins/serviceAws/aws_dynamo.nlg +625 -141
- package/plugins/serviceAws/aws_dynextra.nlg +294 -0
- package/plugins/serviceAws/dbt_aws.nlg +31 -11
- package/plugins/serviceAws/psm_aws.nlg +42 -26
- package/plugins/serviceAws/serviceAws.nlg +1 -0
- package/plugins/serviceGitHub/psm_github.nlg +41 -25
- package/plugins/serviceGitLab/psm_gitlab.nlg +41 -25
|
@@ -4,66 +4,319 @@
|
|
|
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, where a new publisher (e.g. NaanIDE) or new version
|
|
31
|
+
* arises but this worker is still serving old data. The solution is that every publisher provides
|
|
32
|
+
* its ID and version along with the mesage port. If that is different from the previous version then
|
|
33
|
+
* the old caches are cleared and data re-fetched.
|
|
34
|
+
*
|
|
7
35
|
* column positioning: // // !
|
|
8
36
|
*
|
|
9
|
-
* Copyright (c) 2020 by Richard C. Zulch
|
|
37
|
+
* Copyright (c) 2020-2022 by Richard C. Zulch
|
|
10
38
|
*
|
|
11
39
|
*/
|
|
12
40
|
|
|
13
|
-
var CurrentCacheName = "
|
|
41
|
+
var CurrentCacheName = "Naanlang 1.0.3-1";
|
|
14
42
|
|
|
15
43
|
|
|
16
44
|
//
|
|
17
45
|
// locals
|
|
18
46
|
//
|
|
19
47
|
|
|
20
|
-
var fetchQueue = [];
|
|
21
|
-
var fetchNextSeq = 1;
|
|
22
|
-
var
|
|
48
|
+
var fetchQueue = []; // queue for outstanding requests to sources
|
|
49
|
+
var fetchNextSeq = 1; // sequence number for source requests
|
|
50
|
+
var msgPorts = {}; // message ports keyed by sourceId
|
|
51
|
+
var fetchPorts = {}; // message ports keyed by clientId
|
|
52
|
+
var waitingForInit = []; // initialization functions, or false after done
|
|
23
53
|
|
|
24
54
|
|
|
25
55
|
/*
|
|
26
|
-
*
|
|
56
|
+
* initialize
|
|
27
57
|
*
|
|
28
|
-
*
|
|
58
|
+
* Initiate listening for incoming messages from our clients. This waits for any client responses
|
|
59
|
+
* and then quits. Any clients that want to participate after that must unilaterally send a port for
|
|
60
|
+
* communication.
|
|
29
61
|
*
|
|
30
62
|
*/
|
|
31
63
|
|
|
32
|
-
|
|
64
|
+
(function initialize() {
|
|
65
|
+
if (!waitingForInit)
|
|
66
|
+
return; // already initialized
|
|
67
|
+
var pending = 0;
|
|
68
|
+
|
|
69
|
+
// doneInit
|
|
70
|
+
//
|
|
71
|
+
// Call this to resolve any waiting promises and release them for attempting to fetch from the
|
|
72
|
+
// IDEs (sources.)
|
|
73
|
+
//
|
|
74
|
+
function doneInit() {
|
|
75
|
+
if (!waitingForInit)
|
|
76
|
+
return; // already done
|
|
77
|
+
var waiters = waitingForInit;
|
|
78
|
+
waitingForInit = false; // no more waiters allowed
|
|
79
|
+
for (var waiter in waiters)
|
|
80
|
+
waiter(); // call each waiter
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// self.onmessage events
|
|
84
|
+
//
|
|
85
|
+
// This receives channel port messages from the IDEs as they either 1) respond to a request to
|
|
86
|
+
// register, or 2) spontaneously register themselves as they notice that we're running.
|
|
87
|
+
//
|
|
33
88
|
self.addEventListener('message', function(event) {
|
|
34
|
-
|
|
35
|
-
|
|
89
|
+
var msgport = event.data.hereIsYourPort; // message port of a client
|
|
90
|
+
var pubID = event.data.hereIsMyID;
|
|
91
|
+
var pubVersion = event.data.hereIsMyVersion;
|
|
92
|
+
var sourceId = event.source.id; // client id of sender of message
|
|
93
|
+
msgPorts[sourceId] = msgport;
|
|
94
|
+
var newCacheName = "Naanlang".concat("-", pubID, "-", pubVersion);
|
|
95
|
+
console.log("[1.0.3-1] received new msgport for", sourceId, pubID, "-", pubVersion);
|
|
96
|
+
if (CurrentCacheName != newCacheName) {
|
|
97
|
+
for (var srcid in msgPorts)
|
|
98
|
+
msgPorts[srcid].postMessage({
|
|
99
|
+
id: "upgrade",
|
|
100
|
+
previous: "1.0.3-1",
|
|
101
|
+
version: pubVersion
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
ClearCaches(newCacheName)
|
|
105
|
+
.then(Reaper); // clean up obsolete info
|
|
106
|
+
|
|
107
|
+
// msgport.onmessage events
|
|
108
|
+
//
|
|
109
|
+
// This receives channel port messages that are responding to our fetch requests. The IDE
|
|
110
|
+
// can also send a text message for logging, but that is used only for debugging.
|
|
111
|
+
//
|
|
36
112
|
msgport.onmessage = function(msg) {
|
|
37
113
|
msg = msg.data;
|
|
38
114
|
if (msg.id == "response")
|
|
39
|
-
|
|
115
|
+
processResponse(msg);
|
|
40
116
|
else if (msg.id == "text")
|
|
41
|
-
console.log("[1.0.
|
|
117
|
+
console.log("[1.0.3-1] msg received:", msg.text);
|
|
42
118
|
};
|
|
43
|
-
|
|
44
|
-
//
|
|
45
|
-
msgport.postMessage({
|
|
46
|
-
id: "text",
|
|
47
|
-
text: "port received by 1.0.2-1",
|
|
48
|
-
});
|
|
49
|
-
*/
|
|
50
|
-
resolve(msgport);
|
|
51
|
-
|
|
119
|
+
|
|
120
|
+
// send text to IDE log
|
|
52
121
|
//
|
|
53
|
-
//
|
|
122
|
+
// This is only for debugging.
|
|
54
123
|
//
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
124
|
+
/*
|
|
125
|
+
// don't clutter the log
|
|
126
|
+
msgport.postMessage({
|
|
127
|
+
id: "text",
|
|
128
|
+
text: "port received by 1.0.3-1",
|
|
129
|
+
});
|
|
130
|
+
*/
|
|
131
|
+
if (--pending === 0)
|
|
132
|
+
doneInit(); // we finished all known clients
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
// initialize known IDE instances.
|
|
136
|
+
//
|
|
137
|
+
// This sends a port request to each known IDE instance. Fetches that occur prior to completion
|
|
138
|
+
// of initialization will wait for these instances to respond. A timeout prevents one errant IDE
|
|
139
|
+
// from hanging all requests, by releasing the fetches even before all source IDEs respond.
|
|
140
|
+
//
|
|
141
|
+
self.clients.matchAll({
|
|
142
|
+
includeUncontrolled: true
|
|
143
|
+
}).then(function(clientList) {
|
|
144
|
+
clientList.every(function(client) {
|
|
145
|
+
console.log("[1.0.3-1] requesting new msgport for", client.id);
|
|
146
|
+
++pending;
|
|
147
|
+
client.postMessage({ // tell client(s) we need this fetch source
|
|
148
|
+
msg: "Naan_need_fetch_port",
|
|
149
|
+
});
|
|
150
|
+
});
|
|
151
|
+
setTimeout(doneInit, 1000); // release fetches
|
|
152
|
+
});
|
|
153
|
+
|
|
154
|
+
// processResponse
|
|
155
|
+
//
|
|
156
|
+
// An IDE source has responded to our fetch request. If this was successful then we record the
|
|
157
|
+
// IDE (sourceId) so that subsequent requests from that target (clientId) will go to the same
|
|
158
|
+
// source.
|
|
159
|
+
//
|
|
160
|
+
function processResponse(msg) {
|
|
161
|
+
var fqdex, response, item;
|
|
162
|
+
for (fqdex = 0; fqdex < fetchQueue.length; ++fqdex)
|
|
163
|
+
if (fetchQueue[fqdex].seq === msg.seq) {
|
|
164
|
+
item = fetchQueue.splice(fqdex, 1)[0];
|
|
165
|
+
if (item.clientId && msg.init.status == 200)
|
|
166
|
+
fetchPorts[item.clientId] = item.msgport; // successful lookup
|
|
167
|
+
item.resolve(new Response(msg.body, msg.init));
|
|
168
|
+
break;
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
})();
|
|
172
|
+
|
|
173
|
+
|
|
174
|
+
/*
|
|
175
|
+
* Reaper
|
|
176
|
+
*
|
|
177
|
+
* Periodic cleanup returning a promise. This removes anything that is obsolete and resolve all
|
|
178
|
+
* associated transactions.
|
|
179
|
+
*
|
|
180
|
+
*/
|
|
181
|
+
|
|
182
|
+
function Reaper() {
|
|
183
|
+
var promise = self.clients.matchAll({
|
|
184
|
+
includeUncontrolled: true
|
|
185
|
+
}).then(function(clientList) { // both sources and clients
|
|
186
|
+
var clients = {};
|
|
187
|
+
for (var clidex in clientList)
|
|
188
|
+
clients[clientList[clidex].id] = clientList[clidex];
|
|
189
|
+
for (var sourceId in msgPorts)
|
|
190
|
+
if (!clients[sourceId]) {
|
|
191
|
+
console.log("[1.0.3-1] source gone:", sourceId);
|
|
192
|
+
delete msgPorts[sourceId]; // no longer a source
|
|
193
|
+
}
|
|
194
|
+
for (var clientId in fetchPorts)
|
|
195
|
+
if (!clients[clientId]) {
|
|
196
|
+
console.log("[1.0.3-1] client gone:", clientId);
|
|
197
|
+
delete fetchPorts[clientId]; // no longer a client
|
|
198
|
+
}
|
|
199
|
+
for (var fqdex = 0; fqdex < fetchQueue.length; ++fqdex) {
|
|
200
|
+
var item = fetchQueue[fqdex];
|
|
201
|
+
while (item.clientId && !clients[item.clientId]
|
|
202
|
+
|| !Object.values(msgPorts).includes(item.msgport)) {
|
|
203
|
+
fetchQueue.splice(fqdex, 1); // either client or source missing
|
|
204
|
+
item.resolve(new Response(undefined, {
|
|
205
|
+
status: 404,
|
|
206
|
+
statusText: "Source Disappeared" // if client is gone this disappears too
|
|
207
|
+
}));
|
|
208
|
+
if (fqdex >= fetchQueue.length)
|
|
209
|
+
break; // we've run out of transactions
|
|
210
|
+
item = fetchQueue[fqdex];
|
|
211
|
+
}
|
|
64
212
|
}
|
|
65
213
|
});
|
|
66
|
-
|
|
214
|
+
return (promise);
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
|
|
218
|
+
/*
|
|
219
|
+
* ClearCaches
|
|
220
|
+
*
|
|
221
|
+
* Clear obsolete caches in favor of the new name, returning a promise.
|
|
222
|
+
*
|
|
223
|
+
*/
|
|
224
|
+
|
|
225
|
+
function ClearCaches(newCacheName) {
|
|
226
|
+
if (CurrentCacheName == newCacheName)
|
|
227
|
+
return (Promise.resolve()); // no change
|
|
228
|
+
CurrentCacheName = newCacheName;
|
|
229
|
+
var promise = caches.keys().then(function(cacheNames) { // delete old cache entries
|
|
230
|
+
return (Promise.all(
|
|
231
|
+
cacheNames.map(function(cacheName) {
|
|
232
|
+
if (cacheName !== CurrentCacheName) {
|
|
233
|
+
console.log('[1.0.3-1] deleting old cache:', cacheName);
|
|
234
|
+
return (caches.delete(cacheName));
|
|
235
|
+
}
|
|
236
|
+
})
|
|
237
|
+
));
|
|
238
|
+
}).then(function() { // claim all clients
|
|
239
|
+
console.log('[1.0.3-1] claiming clients for version', CurrentCacheName);
|
|
240
|
+
return (self.clients.claim());
|
|
241
|
+
});
|
|
242
|
+
return (promise);
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
|
|
246
|
+
/*
|
|
247
|
+
* GetClientResponse
|
|
248
|
+
*
|
|
249
|
+
* Get message ports from the current clients if they can supply contents for the specified URL.
|
|
250
|
+
* This returns a promise that is resolved after the msgPorts object is updated. Note that the
|
|
251
|
+
* clientId argument is the requester, but the client that actually has the available data will
|
|
252
|
+
* often be a different window.
|
|
253
|
+
* On the first request from a given client, every source is requested to respond to the URL
|
|
254
|
+
* pathname, and the first one that does is designated the official source for that client. While
|
|
255
|
+
* asking all the sources, this checks every second to see if any of them have gone away so that it
|
|
256
|
+
* does not hang waiting. A source can be unresponsive and delay the fetch forever, e.g. in the
|
|
257
|
+
* debugger, but if the window has closed then it will get reaped and the fetch will complete.
|
|
258
|
+
* On subsequent requests, to a known source, this does not have a timeout. If the source goes
|
|
259
|
+
* away then the fetch will not complete, but the client is screwed anyway in that case. Eventually
|
|
260
|
+
* the reaper will be called for other reasons and it will clean things up then.
|
|
261
|
+
*
|
|
262
|
+
*/
|
|
263
|
+
|
|
264
|
+
function GetClientResponse(event, urlpath) {
|
|
265
|
+
|
|
266
|
+
// delegate
|
|
267
|
+
//
|
|
268
|
+
// Delegate to a source window and return a promise
|
|
269
|
+
//
|
|
270
|
+
function delegate(msgport, clientId) {
|
|
271
|
+
return (new Promise(function(resolve, reject) {
|
|
272
|
+
var seqno = fetchNextSeq++;
|
|
273
|
+
fetchQueue.push({
|
|
274
|
+
seq: seqno,
|
|
275
|
+
msgport: msgport,
|
|
276
|
+
clientId: clientId,
|
|
277
|
+
resolve: resolve
|
|
278
|
+
});
|
|
279
|
+
msgport.postMessage({
|
|
280
|
+
id: "fetch",
|
|
281
|
+
seq: seqno,
|
|
282
|
+
version: "1.0.3-1",
|
|
283
|
+
request: {
|
|
284
|
+
method: event.request.method,
|
|
285
|
+
url: event.request.url
|
|
286
|
+
},
|
|
287
|
+
});
|
|
288
|
+
}));
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
var clientId;
|
|
292
|
+
if (event.clientId !== "") {
|
|
293
|
+
clientId = event.clientId;
|
|
294
|
+
if (fetchPorts[clientId])
|
|
295
|
+
return (delegate(fetchPorts[clientId], false));
|
|
296
|
+
}
|
|
297
|
+
else
|
|
298
|
+
clientId = event.resultingClientId; // new window
|
|
299
|
+
var pending = [];
|
|
300
|
+
var sourceIds = Object.getOwnPropertyNames(msgPorts);
|
|
301
|
+
for (var mdex = 0; mdex < sourceIds.length; ++mdex)
|
|
302
|
+
{
|
|
303
|
+
var sourceId = sourceIds[mdex];
|
|
304
|
+
pending.push(delegate(msgPorts[sourceId], clientId));
|
|
305
|
+
}
|
|
306
|
+
if (pending.length === 0)
|
|
307
|
+
return (Promise.resolve(new Response(undefined, {
|
|
308
|
+
status: 404,
|
|
309
|
+
statusText: "No Sources"
|
|
310
|
+
})));
|
|
311
|
+
var toid = setInterval(Reaper, 1000); // reap every second while pending
|
|
312
|
+
return (Promise.all(pending).then(function(responses) {
|
|
313
|
+
clearInterval(toid); // all completed
|
|
314
|
+
for (var idex in responses)
|
|
315
|
+
if (responses[idex].status == 200)
|
|
316
|
+
return (responses[idex]); // this is the one we want
|
|
317
|
+
return (responses[0]); // fall back to first
|
|
318
|
+
}));
|
|
319
|
+
}
|
|
67
320
|
|
|
68
321
|
|
|
69
322
|
/*
|
|
@@ -74,7 +327,7 @@ var promiseport = new Promise(function (resolve, reject) {
|
|
|
74
327
|
*/
|
|
75
328
|
|
|
76
329
|
self.addEventListener('install', function(event) {
|
|
77
|
-
console.log("[1.0.
|
|
330
|
+
console.log("[1.0.3-1] install");
|
|
78
331
|
self.skipWaiting();
|
|
79
332
|
});
|
|
80
333
|
|
|
@@ -95,53 +348,30 @@ self.addEventListener('fetch', function(event) {
|
|
|
95
348
|
var tid;
|
|
96
349
|
var promise;
|
|
97
350
|
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);
|
|
351
|
+
var nocache = event.request.method != "GET"
|
|
352
|
+
|| url.search.length !== 0
|
|
353
|
+
|| event.request.headers.get('range');
|
|
354
|
+
if (url.pathname.startsWith("/run/")) {
|
|
355
|
+
nocache = true;
|
|
356
|
+
if (waitingForInit) {
|
|
357
|
+
promise = new Promise(function(resolve, reject) {
|
|
358
|
+
waitingForInit.push(function(){
|
|
359
|
+
resolve(); // init was complete
|
|
112
360
|
});
|
|
113
|
-
|
|
114
|
-
return (
|
|
361
|
+
}).then(function(){
|
|
362
|
+
return (GetClientResponse(event, url.pathname)); // then get the response
|
|
115
363
|
});
|
|
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
|
-
}) });
|
|
364
|
+
} else
|
|
365
|
+
promise = GetClientResponse(event, url.pathname);
|
|
142
366
|
}
|
|
143
367
|
else
|
|
144
|
-
promise = fetch(event.request)
|
|
368
|
+
promise = fetch(event.request).catch(function (e) {
|
|
369
|
+
console.log("[1.0.3-1] fetch failed", e);
|
|
370
|
+
return (new Response(undefined, {
|
|
371
|
+
status: 404,
|
|
372
|
+
statusText: "Fetch Failed"
|
|
373
|
+
}));
|
|
374
|
+
});
|
|
145
375
|
return (promise.then(function(response) {
|
|
146
376
|
// delete tid timer ###
|
|
147
377
|
if (!nocache) {
|
|
@@ -165,28 +395,16 @@ self.addEventListener('fetch', function(event) {
|
|
|
165
395
|
*/
|
|
166
396
|
|
|
167
397
|
self.addEventListener('activate', function(event) {
|
|
168
|
-
console.log("[1.0.
|
|
398
|
+
console.log("[1.0.3-1] activate");
|
|
169
399
|
self.clients.matchAll({ // for debugging, list controlled clients
|
|
170
400
|
includeUncontrolled: true
|
|
171
401
|
}).then(function(clientList) {
|
|
172
402
|
var urls = clientList.map(function(client) {
|
|
173
403
|
return (client.url);
|
|
174
404
|
});
|
|
175
|
-
console.log('[1.0.
|
|
405
|
+
console.log('[1.0.3-1] matching clients:', urls.join(', '));
|
|
176
406
|
});
|
|
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
|
-
});
|
|
407
|
+
var promise = ClearCaches(CurrentCacheName);
|
|
190
408
|
if (event.waitUntil)
|
|
191
409
|
event.waitUntil(promise);
|
|
192
410
|
});
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
*
|
|
7
7
|
* column positioning: // // !
|
|
8
8
|
*
|
|
9
|
-
* Copyright (c) 2019-
|
|
9
|
+
* Copyright (c) 2019-2022 by Richard C. Zulch
|
|
10
10
|
*
|
|
11
11
|
*/
|
|
12
12
|
|
|
@@ -170,6 +170,7 @@ closure TermHost(track, api, name, workerID, options,
|
|
|
170
170
|
|
|
171
171
|
target.sendControl = function sendControl(workerOp, payload) {
|
|
172
172
|
target.ws.send(js.w.JSON.stringify({
|
|
173
|
+
guid: api.guid
|
|
173
174
|
clientID: clientID
|
|
174
175
|
serverID: serverID
|
|
175
176
|
workerID: target.workerID
|
|
@@ -355,7 +356,7 @@ closure TermHost(track, api, name, workerID, options,
|
|
|
355
356
|
*/
|
|
356
357
|
|
|
357
358
|
closure TermLocal(track, name, workerID, options,
|
|
358
|
-
local target, nlregex)
|
|
359
|
+
local target, nlregex, listener)
|
|
359
360
|
{
|
|
360
361
|
if workerID == "NaanIDE" {
|
|
361
362
|
if !js.t
|
|
@@ -363,8 +364,6 @@ closure TermLocal(track, name, workerID, options,
|
|
|
363
364
|
termInstallVirtualWatcher(track, js.t)
|
|
364
365
|
return (termIDE(track, name, workerID, js.t)) // connect to IDE execution instance itself
|
|
365
366
|
}
|
|
366
|
-
if not js.w.Worker
|
|
367
|
-
return (list(Error("Local environment does not support workers")))
|
|
368
367
|
if dictionary(options)
|
|
369
368
|
options = new(options)
|
|
370
369
|
else
|
|
@@ -372,13 +371,27 @@ closure TermLocal(track, name, workerID, options,
|
|
|
372
371
|
target = runningExecutors.ExecutorBase(track, "Local", name)
|
|
373
372
|
nlregex = RegExp("\\n", "g")
|
|
374
373
|
target.workerID = workerID
|
|
375
|
-
target.worker = xnew(js.w.Worker, "env_webworker.js")
|
|
376
374
|
target.msgQueue = []
|
|
375
|
+
if workerID == "NaanIDE-Debug" {
|
|
376
|
+
target.worker = js.w.open(js.w.location.href, "_blank")
|
|
377
|
+
target.worker.addEventListener("beforeunload", function(e) { // our target is closing
|
|
378
|
+
destroy()
|
|
379
|
+
})
|
|
380
|
+
js.w.addEventListener("beforeunload", function(e) { // we are closing
|
|
381
|
+
// ### tell target we are closing (if needed)
|
|
382
|
+
})
|
|
383
|
+
listener = js.w
|
|
384
|
+
} else {
|
|
385
|
+
if not js.w.Worker
|
|
386
|
+
return (list(Error("Local environment does not support workers")))
|
|
387
|
+
target.worker = xnew(js.w.Worker, "env_webworker.js")
|
|
388
|
+
listener = target.worker
|
|
389
|
+
}
|
|
377
390
|
|
|
378
391
|
// onmessage
|
|
379
392
|
// A message was received from the worker.
|
|
380
393
|
|
|
381
|
-
|
|
394
|
+
listener.addEventListener("message", function(e, msg) {
|
|
382
395
|
msg = new(e.data)
|
|
383
396
|
if msg.id != "targetout" && msg.id != "loaded" {
|
|
384
397
|
if msg.id == "status"
|
|
@@ -388,14 +401,14 @@ closure TermLocal(track, name, workerID, options,
|
|
|
388
401
|
target.msgQueue.push(msg)
|
|
389
402
|
return } }
|
|
390
403
|
target.doMessage(msg)
|
|
391
|
-
}
|
|
404
|
+
})
|
|
392
405
|
|
|
393
406
|
// onerror
|
|
394
407
|
// The worker had an error.
|
|
395
408
|
|
|
396
|
-
target.worker.
|
|
409
|
+
target.worker.addEventListener("error", function(e) {
|
|
397
410
|
target.execClosed(Error("instance error", e.message))
|
|
398
|
-
}
|
|
411
|
+
})
|
|
399
412
|
|
|
400
413
|
//
|
|
401
414
|
// oninterrupt
|
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
*
|
|
19
19
|
*/
|
|
20
20
|
|
|
21
|
-
closure ServiceWorker(local serv, callback) {
|
|
21
|
+
closure ServiceWorker(pubID, pubVersion, local serv, callback) {
|
|
22
22
|
serv = new(object, this)
|
|
23
23
|
|
|
24
24
|
//
|
|
@@ -32,7 +32,11 @@ closure ServiceWorker(local serv, callback) {
|
|
|
32
32
|
mchan = xnew(js.w.MessageChannel)
|
|
33
33
|
serv.msgport = mchan.port2
|
|
34
34
|
serv.msgport.onmessage = workerMsg.proc
|
|
35
|
-
serv.sw.postMessage({
|
|
35
|
+
serv.sw.postMessage({
|
|
36
|
+
hereIsYourPort: mchan.port1
|
|
37
|
+
hereIsMyID: pubID
|
|
38
|
+
hereIsMyVersion: pubVersion
|
|
39
|
+
}, [mchan.port1])
|
|
36
40
|
}
|
|
37
41
|
|
|
38
42
|
//
|
|
@@ -50,7 +54,11 @@ closure ServiceWorker(local serv, callback) {
|
|
|
50
54
|
request: msg.request
|
|
51
55
|
version: msg.version
|
|
52
56
|
})
|
|
53
|
-
} else if msg.id == "
|
|
57
|
+
} else if msg.id == "upgrade" {
|
|
58
|
+
if msg.version != msg.previous // same version: new install
|
|
59
|
+
debuglog("service worker version upgrade to:", msg.version, "from", msg.previous)
|
|
60
|
+
}
|
|
61
|
+
else if msg.id == "text"
|
|
54
62
|
debuglog("sw[".concat(serv.scope, "]: "), msg.text) // handy remote debug capability
|
|
55
63
|
}
|
|
56
64
|
|
|
@@ -174,10 +182,10 @@ closure ServiceWorker(local serv, callback) {
|
|
|
174
182
|
*
|
|
175
183
|
*/
|
|
176
184
|
|
|
177
|
-
closure ScopedServiceWorker(local scoper, result) {
|
|
185
|
+
closure ScopedServiceWorker(pubID, pubVersion, local scoper, result) {
|
|
178
186
|
scoper = new(object, ScopedServiceWorker)
|
|
179
187
|
scoper.scopes = {}
|
|
180
|
-
scoper.serv = ServiceWorker()
|
|
188
|
+
scoper.serv = ServiceWorker(pubID, pubVersion)
|
|
181
189
|
result = scoper.serv.register("/", closure(error, data, local response, filepath, scope) {
|
|
182
190
|
if data.message == "fetch" {
|
|
183
191
|
response = {
|
|
@@ -201,7 +209,7 @@ closure ScopedServiceWorker(local scoper, result) {
|
|
|
201
209
|
filepath = xnew(js.w.URL, data.request.url).pathname
|
|
202
210
|
filepath = DecodeURIComponent(filepath) // "/run/<scope>/path..."
|
|
203
211
|
filepath = filepath.slice(4) // "/<scope>/path..."
|
|
204
|
-
error = true
|
|
212
|
+
error = true // stays true iff not in scope
|
|
205
213
|
for scope in scoper.scopes {
|
|
206
214
|
if filepath.startsWith(scope) {
|
|
207
215
|
filepath = filepath.slice(scope.length+1) // remove scope including "/"
|
|
@@ -209,8 +217,6 @@ closure ScopedServiceWorker(local scoper, result) {
|
|
|
209
217
|
break
|
|
210
218
|
}
|
|
211
219
|
}
|
|
212
|
-
if error === true
|
|
213
|
-
debuglog("ScopedServiceWorker: couldn't find scope", scope, "in", totuple(scoper.scopes))
|
|
214
220
|
|
|
215
221
|
// read resource failed
|
|
216
222
|
if error {
|
|
@@ -353,12 +359,14 @@ closure TrackedScope(track, scope, fs, rootpath, local trope, result) {
|
|
|
353
359
|
/*
|
|
354
360
|
* TrackServiceWorkers
|
|
355
361
|
*
|
|
356
|
-
* Configure service workers to be tracked in the execution tracker.
|
|
362
|
+
* Configure service workers to be tracked in the execution tracker. The pubID identifies us as
|
|
363
|
+
* the publisher for this service worker, and the version allows it to clear its cache when versions
|
|
364
|
+
* change.
|
|
357
365
|
*
|
|
358
366
|
*/
|
|
359
367
|
|
|
360
|
-
closure TrackServiceWorkers(track, local error) {
|
|
361
|
-
`(error, serviceWorker) = ScopedServiceWorker()
|
|
368
|
+
closure TrackServiceWorkers(track, pubID, pubVersion, local error) {
|
|
369
|
+
`(error, serviceWorker) = ScopedServiceWorker(pubID, pubVersion)
|
|
362
370
|
if error
|
|
363
371
|
ErrorDebugLog("TrackServiceWorkers: cannot load service worker", error)
|
|
364
372
|
track.register(TrackedScope, "V-Site")
|