@jsenv/core 27.6.1 → 27.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/js/autoreload.js +3 -6
- package/dist/js/html_supervisor_installer.js +36 -32
- package/dist/js/html_supervisor_setup.js +10 -2
- package/dist/js/server_events_client.js +249 -216
- package/dist/js/wrapper.mjs +4233 -0
- package/dist/main.js +21292 -21641
- package/package.json +3 -3
- package/src/build/build.js +15 -13
- package/src/dev/start_dev_server.js +6 -10
- package/src/execute/runtimes/browsers/chromium.js +1 -1
- package/src/execute/runtimes/browsers/firefox.js +1 -1
- package/src/execute/runtimes/browsers/webkit.js +1 -1
- package/src/omega/omega_server.js +11 -0
- package/src/omega/server/file_service.js +2 -18
- package/src/plugins/autoreload/client/autoreload.js +3 -4
- package/src/plugins/html_supervisor/client/error_formatter.js +43 -37
- package/src/plugins/html_supervisor/client/html_supervisor_installer.js +1 -4
- package/src/plugins/html_supervisor/client/html_supervisor_setup.js +10 -2
- package/src/plugins/html_supervisor/jsenv_plugin_html_supervisor.js +3 -1
- package/src/plugins/server_events/client/connection_manager.js +165 -0
- package/src/plugins/server_events/client/event_source_connection.js +50 -256
- package/src/plugins/server_events/client/events_manager.js +75 -0
- package/src/plugins/server_events/client/server_events_client.js +12 -11
- package/src/plugins/server_events/client/web_socket_connection.js +81 -0
- package/src/plugins/server_events/server_events_dispatcher.js +70 -54
package/dist/js/autoreload.js
CHANGED
|
@@ -350,12 +350,9 @@ const applyHotReload = async ({
|
|
|
350
350
|
|
|
351
351
|
window.__reloader__ = reloader;
|
|
352
352
|
|
|
353
|
-
window.__server_events__.
|
|
354
|
-
reload:
|
|
355
|
-
data
|
|
356
|
-
}) => {
|
|
357
|
-
const reloadMessage = JSON.parse(data);
|
|
358
|
-
reloader.addMessage(reloadMessage);
|
|
353
|
+
window.__server_events__.listenEvents({
|
|
354
|
+
reload: reloadServerEvent => {
|
|
355
|
+
reloader.addMessage(reloadServerEvent.data);
|
|
359
356
|
}
|
|
360
357
|
}); // const findHotMetaUrl = (originalFileRelativeUrl) => {
|
|
361
358
|
// return Object.keys(urlHotMetas).find((compileUrl) => {
|
|
@@ -164,45 +164,50 @@ const formatError = (error, {
|
|
|
164
164
|
errorUrlSite = urlSite;
|
|
165
165
|
|
|
166
166
|
errorDetailsPromiseReference.current = (async () => {
|
|
167
|
-
|
|
168
|
-
|
|
167
|
+
try {
|
|
168
|
+
if (errorMeta.type === "dynamic_import_fetch_error") {
|
|
169
|
+
const response = await window.fetch(`/__get_error_cause__/${urlSite.isInline ? urlSite.originalUrl : urlSite.url}`);
|
|
169
170
|
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
171
|
+
if (response.status !== 200) {
|
|
172
|
+
return null;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
const causeInfo = await response.json();
|
|
173
176
|
|
|
174
|
-
|
|
177
|
+
if (!causeInfo) {
|
|
178
|
+
return null;
|
|
179
|
+
}
|
|
175
180
|
|
|
176
|
-
|
|
177
|
-
|
|
181
|
+
const causeText = causeInfo.code === "NOT_FOUND" ? formatErrorText({
|
|
182
|
+
message: causeInfo.reason,
|
|
183
|
+
stack: causeInfo.codeFrame
|
|
184
|
+
}) : formatErrorText({
|
|
185
|
+
message: causeInfo.stack,
|
|
186
|
+
stack: causeInfo.codeFrame
|
|
187
|
+
});
|
|
188
|
+
return {
|
|
189
|
+
cause: causeText
|
|
190
|
+
};
|
|
178
191
|
}
|
|
179
192
|
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
stack: causeInfo.codeFrame
|
|
183
|
-
}) : formatErrorText({
|
|
184
|
-
message: causeInfo.stack,
|
|
185
|
-
stack: causeInfo.codeFrame
|
|
186
|
-
});
|
|
187
|
-
return {
|
|
188
|
-
cause: causeText
|
|
189
|
-
};
|
|
190
|
-
}
|
|
193
|
+
if (urlSite.line !== undefined) {
|
|
194
|
+
let ressourceToFetch = `/__get_code_frame__/${formatUrlWithLineAndColumn(urlSite)}`;
|
|
191
195
|
|
|
192
|
-
|
|
193
|
-
|
|
196
|
+
if (!Error.captureStackTrace) {
|
|
197
|
+
ressourceToFetch += `?remap`;
|
|
198
|
+
}
|
|
194
199
|
|
|
195
|
-
|
|
196
|
-
|
|
200
|
+
const response = await window.fetch(ressourceToFetch);
|
|
201
|
+
const codeFrame = await response.text();
|
|
202
|
+
return {
|
|
203
|
+
codeFrame: formatErrorText({
|
|
204
|
+
message: codeFrame
|
|
205
|
+
})
|
|
206
|
+
};
|
|
197
207
|
}
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
return {
|
|
202
|
-
codeFrame: formatErrorText({
|
|
203
|
-
message: codeFrame
|
|
204
|
-
})
|
|
205
|
-
};
|
|
208
|
+
} catch (e) {
|
|
209
|
+
// happens if server is closed for instance
|
|
210
|
+
return null;
|
|
206
211
|
}
|
|
207
212
|
|
|
208
213
|
return null;
|
|
@@ -923,7 +928,6 @@ const installHtmlSupervisor = ({
|
|
|
923
928
|
const useDeferQueue = scriptToExecute.defer || scriptToExecute.type === "module";
|
|
924
929
|
|
|
925
930
|
if (useDeferQueue) {
|
|
926
|
-
// defer must wait for classic script to be done
|
|
927
931
|
const classicExecutionPromise = classicExecutionQueue.getPromise();
|
|
928
932
|
|
|
929
933
|
if (classicExecutionPromise) {
|
|
@@ -9,11 +9,12 @@ window.__html_supervisor__ = {
|
|
|
9
9
|
window.__html_supervisor__.scriptsToExecute.push(scriptToExecute)
|
|
10
10
|
},
|
|
11
11
|
superviseScript: ({ src, isInline, crossorigin, integrity }) => {
|
|
12
|
+
const { currentScript } = document
|
|
12
13
|
window.__html_supervisor__.addScriptToExecute({
|
|
13
14
|
src,
|
|
14
15
|
type: "js_classic",
|
|
15
16
|
isInline,
|
|
16
|
-
currentScript
|
|
17
|
+
currentScript,
|
|
17
18
|
execute: (url) => {
|
|
18
19
|
return new Promise((resolve, reject) => {
|
|
19
20
|
const script = document.createElement("script")
|
|
@@ -50,7 +51,14 @@ window.__html_supervisor__ = {
|
|
|
50
51
|
resolve()
|
|
51
52
|
}
|
|
52
53
|
})
|
|
53
|
-
|
|
54
|
+
if (currentScript) {
|
|
55
|
+
currentScript.parentNode.insertBefore(
|
|
56
|
+
script,
|
|
57
|
+
currentScript.nextSibling,
|
|
58
|
+
)
|
|
59
|
+
} else {
|
|
60
|
+
document.body.appendChild(script)
|
|
61
|
+
}
|
|
54
62
|
})
|
|
55
63
|
},
|
|
56
64
|
})
|
|
@@ -1,244 +1,105 @@
|
|
|
1
|
-
const
|
|
1
|
+
const READY_STATES = {
|
|
2
2
|
CONNECTING: "connecting",
|
|
3
|
-
|
|
4
|
-
|
|
3
|
+
OPEN: "open",
|
|
4
|
+
CLOSING: "closing",
|
|
5
|
+
CLOSED: "closed"
|
|
5
6
|
};
|
|
6
|
-
const
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
}
|
|
12
|
-
const {
|
|
13
|
-
|
|
14
|
-
} = window;
|
|
15
|
-
|
|
16
|
-
if (typeof EventSource !== "function") {
|
|
17
|
-
return () => {};
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
let eventSource;
|
|
21
|
-
const listenersMap = new Map();
|
|
22
|
-
const callbacksMap = new Map();
|
|
23
|
-
const eventSourceOrigin = new URL(eventSourceUrl).origin;
|
|
24
|
-
|
|
25
|
-
const addEventCallbacks = namedCallbacks => {
|
|
26
|
-
let listenersMapSize = listenersMap.size;
|
|
27
|
-
Object.keys(namedCallbacks).forEach(eventName => {
|
|
28
|
-
const callback = namedCallbacks[eventName];
|
|
29
|
-
const existingCallbacks = callbacksMap.get(eventName);
|
|
30
|
-
let callbacks;
|
|
31
|
-
|
|
32
|
-
if (existingCallbacks) {
|
|
33
|
-
callbacks = existingCallbacks;
|
|
34
|
-
} else {
|
|
35
|
-
callbacks = [];
|
|
36
|
-
callbacksMap.set(eventName, callbacks);
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
if (callbacks.length === 0) {
|
|
40
|
-
const eventListener = e => {
|
|
41
|
-
if (e.origin === eventSourceOrigin) {
|
|
42
|
-
if (e.lastEventId) {
|
|
43
|
-
lastEventId = e.lastEventId;
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
callbacks.forEach(eventCallback => {
|
|
47
|
-
eventCallback(e);
|
|
48
|
-
});
|
|
49
|
-
}
|
|
50
|
-
};
|
|
51
|
-
|
|
52
|
-
listenersMap.set(eventName, eventListener);
|
|
53
|
-
|
|
54
|
-
if (eventSource) {
|
|
55
|
-
eventSource.addEventListener(eventName, eventListener);
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
callbacks.push(callback);
|
|
60
|
-
});
|
|
61
|
-
|
|
62
|
-
if (useEventsToManageConnection && listenersMapSize === 0 && listenersMap.size > 0 && status.value !== STATUSES.CONNECTING && status.value !== STATUSES.CONNECTED) {
|
|
63
|
-
_connect();
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
let removed = false;
|
|
67
|
-
return () => {
|
|
68
|
-
if (removed) return;
|
|
69
|
-
removed = true;
|
|
70
|
-
listenersMapSize = listenersMap.size;
|
|
71
|
-
Object.keys(namedCallbacks).forEach(eventName => {
|
|
72
|
-
const callback = namedCallbacks[eventName];
|
|
73
|
-
const callbacks = callbacksMap.get(eventName);
|
|
74
|
-
|
|
75
|
-
if (callbacks) {
|
|
76
|
-
const index = callbacks.indexOf(callback);
|
|
77
|
-
|
|
78
|
-
if (index > -1) {
|
|
79
|
-
callbacks.splice(index, 1);
|
|
80
|
-
|
|
81
|
-
if (callbacks.length === 0) {
|
|
82
|
-
const listener = listenersMap.get(eventName);
|
|
83
|
-
|
|
84
|
-
if (listener) {
|
|
85
|
-
listenersMap.delete(listener);
|
|
86
|
-
|
|
87
|
-
if (eventSource) {
|
|
88
|
-
eventSource.removeEventListener(eventName, listener);
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
|
-
}
|
|
94
|
-
});
|
|
95
|
-
namedCallbacks = null; // allow garbage collect
|
|
96
|
-
|
|
97
|
-
if (useEventsToManageConnection && listenersMapSize > 0 && listenersMap.size === 0 && (status.value === STATUSES.CONNECTING || status.value === STATUSES.CONNECTED)) {
|
|
98
|
-
_disconnect();
|
|
99
|
-
}
|
|
100
|
-
};
|
|
101
|
-
};
|
|
102
|
-
|
|
103
|
-
const status = {
|
|
104
|
-
value: "default",
|
|
7
|
+
const createConnectionManager = (attemptConnection, {
|
|
8
|
+
retry,
|
|
9
|
+
retryAfter,
|
|
10
|
+
retryMaxAttempt,
|
|
11
|
+
retryAllocatedMs
|
|
12
|
+
}) => {
|
|
13
|
+
const readyState = {
|
|
14
|
+
value: READY_STATES.CLOSED,
|
|
105
15
|
goTo: value => {
|
|
106
|
-
if (value ===
|
|
16
|
+
if (value === readyState.value) {
|
|
107
17
|
return;
|
|
108
18
|
}
|
|
109
19
|
|
|
110
|
-
|
|
111
|
-
|
|
20
|
+
readyState.value = value;
|
|
21
|
+
readyState.onchange();
|
|
112
22
|
},
|
|
113
23
|
onchange: () => {}
|
|
114
24
|
};
|
|
115
25
|
|
|
116
26
|
let _disconnect = () => {};
|
|
117
27
|
|
|
118
|
-
const
|
|
119
|
-
if (
|
|
28
|
+
const connect = () => {
|
|
29
|
+
if (readyState.value === READY_STATES.CONNECTING || readyState.value === READY_STATES.OPEN) {
|
|
120
30
|
return;
|
|
121
31
|
}
|
|
122
32
|
|
|
123
|
-
eventSource = new EventSource(url, {
|
|
124
|
-
withCredentials: true
|
|
125
|
-
});
|
|
126
|
-
|
|
127
|
-
_disconnect = () => {
|
|
128
|
-
if (status.value !== STATUSES.CONNECTING && status.value !== STATUSES.CONNECTED) {
|
|
129
|
-
console.warn(`disconnect() ignored because connection is ${status.value}`);
|
|
130
|
-
return;
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
if (eventSource) {
|
|
134
|
-
eventSource.onerror = undefined;
|
|
135
|
-
eventSource.close();
|
|
136
|
-
listenersMap.forEach((listener, eventName) => {
|
|
137
|
-
eventSource.removeEventListener(eventName, listener);
|
|
138
|
-
});
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
eventSource = null;
|
|
142
|
-
status.goTo(STATUSES.DISCONNECTED);
|
|
143
|
-
};
|
|
144
|
-
|
|
145
33
|
let retryCount = 0;
|
|
146
|
-
let
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
return;
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
if (retryCount === 0) {
|
|
159
|
-
firstRetryMs = Date.now();
|
|
160
|
-
} else {
|
|
161
|
-
const allRetryDuration = Date.now() - firstRetryMs;
|
|
162
|
-
|
|
163
|
-
if (retryAllocatedMs && allRetryDuration > retryAllocatedMs) {
|
|
164
|
-
console.info(`could not connect in less than ${retryAllocatedMs} ms`);
|
|
165
|
-
|
|
166
|
-
_disconnect();
|
|
167
|
-
|
|
34
|
+
let msSpent = 0;
|
|
35
|
+
|
|
36
|
+
const attempt = () => {
|
|
37
|
+
readyState.goTo(READY_STATES.CONNECTING);
|
|
38
|
+
_disconnect = attemptConnection({
|
|
39
|
+
onClosed: () => {
|
|
40
|
+
if (!retry) {
|
|
41
|
+
readyState.goTo(READY_STATES.CLOSED);
|
|
42
|
+
console.info(`[jsenv] failed to connect to server`);
|
|
168
43
|
return;
|
|
169
44
|
}
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
retryCount++;
|
|
173
|
-
status.goTo(STATUSES.CONNECTING);
|
|
174
|
-
return;
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
if (errorEvent.target.readyState === EventSource.CLOSED) {
|
|
178
|
-
_disconnect();
|
|
179
45
|
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
46
|
+
if (retryCount > retryMaxAttempt) {
|
|
47
|
+
readyState.goTo(READY_STATES.CLOSED);
|
|
48
|
+
console.info(`[jsenv] could not connect to server after ${retryMaxAttempt} attempt`);
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
183
51
|
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
52
|
+
if (retryAllocatedMs && msSpent > retryAllocatedMs) {
|
|
53
|
+
readyState.goTo(READY_STATES.CLOSED);
|
|
54
|
+
console.info(`[jsenv] could not connect to server in less than ${retryAllocatedMs}ms`);
|
|
55
|
+
return;
|
|
56
|
+
} // if closed while open -> connection lost
|
|
57
|
+
// otherwise it's the attempt to connect for the first time
|
|
58
|
+
// or to reconnect
|
|
187
59
|
|
|
188
|
-
listenersMap.forEach((listener, eventName) => {
|
|
189
|
-
eventSource.addEventListener(eventName, listener);
|
|
190
|
-
});
|
|
191
60
|
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
61
|
+
if (readyState.value === READY_STATES.OPEN) {
|
|
62
|
+
console.info(`[jsenv] server connection lost; retrying to connect`);
|
|
63
|
+
}
|
|
195
64
|
|
|
65
|
+
retryCount++;
|
|
66
|
+
setTimeout(() => {
|
|
67
|
+
msSpent += retryAfter;
|
|
68
|
+
attempt();
|
|
69
|
+
}, retryAfter);
|
|
70
|
+
},
|
|
71
|
+
onOpen: () => {
|
|
72
|
+
readyState.goTo(READY_STATES.OPEN); // console.info(`[jsenv] connected to server`)
|
|
73
|
+
}
|
|
196
74
|
});
|
|
197
|
-
}
|
|
75
|
+
};
|
|
198
76
|
|
|
199
|
-
|
|
77
|
+
attempt();
|
|
200
78
|
};
|
|
201
79
|
|
|
202
|
-
|
|
203
|
-
|
|
80
|
+
const disconnect = () => {
|
|
81
|
+
if (readyState.value !== READY_STATES.CONNECTING && readyState.value !== READY_STATES.OPEN) {
|
|
82
|
+
console.warn(`disconnect() ignored because connection is ${readyState.value}`);
|
|
83
|
+
return null;
|
|
84
|
+
}
|
|
204
85
|
|
|
205
|
-
|
|
206
|
-
attemptConnection(lastEventId ? addLastEventIdIntoUrlSearchParams(eventSourceUrl, lastEventId) : eventSourceUrl);
|
|
207
|
-
};
|
|
86
|
+
return _disconnect();
|
|
208
87
|
};
|
|
209
88
|
|
|
210
89
|
const removePageUnloadListener = listenPageUnload(() => {
|
|
211
|
-
if (
|
|
90
|
+
if (readyState.value === READY_STATES.CONNECTING || readyState.value === READY_STATES.OPEN) {
|
|
212
91
|
_disconnect();
|
|
213
92
|
}
|
|
214
93
|
});
|
|
215
|
-
|
|
216
|
-
const destroy = () => {
|
|
217
|
-
removePageUnloadListener();
|
|
218
|
-
|
|
219
|
-
_disconnect();
|
|
220
|
-
|
|
221
|
-
listenersMap.clear();
|
|
222
|
-
callbacksMap.clear();
|
|
223
|
-
};
|
|
224
|
-
|
|
225
94
|
return {
|
|
226
|
-
|
|
227
|
-
connect
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
95
|
+
readyState,
|
|
96
|
+
connect,
|
|
97
|
+
disconnect,
|
|
98
|
+
destroy: () => {
|
|
99
|
+
removePageUnloadListener();
|
|
100
|
+
disconnect();
|
|
101
|
+
}
|
|
231
102
|
};
|
|
232
|
-
};
|
|
233
|
-
|
|
234
|
-
const addLastEventIdIntoUrlSearchParams = (url, lastEventId) => {
|
|
235
|
-
if (url.indexOf("?") === -1) {
|
|
236
|
-
url += "?";
|
|
237
|
-
} else {
|
|
238
|
-
url += "&";
|
|
239
|
-
}
|
|
240
|
-
|
|
241
|
-
return `${url}last-event-id=${encodeURIComponent(lastEventId)}`;
|
|
242
103
|
}; // const listenPageMightFreeze = (callback) => {
|
|
243
104
|
// const removePageHideListener = listenEvent(window, "pagehide", (pageHideEvent) => {
|
|
244
105
|
// if (pageHideEvent.persisted === true) {
|
|
@@ -271,7 +132,6 @@ const addLastEventIdIntoUrlSearchParams = (url, lastEventId) => {
|
|
|
271
132
|
// }
|
|
272
133
|
// }
|
|
273
134
|
|
|
274
|
-
|
|
275
135
|
const listenPageUnload = callback => {
|
|
276
136
|
const removePageHideListener = listenEvent(window, "pagehide", pageHideEvent => {
|
|
277
137
|
if (pageHideEvent.persisted !== true) {
|
|
@@ -288,20 +148,193 @@ const listenEvent = (emitter, event, callback) => {
|
|
|
288
148
|
};
|
|
289
149
|
};
|
|
290
150
|
|
|
291
|
-
const
|
|
292
|
-
|
|
293
|
-
|
|
151
|
+
const createEventsManager = ({
|
|
152
|
+
effect = () => {}
|
|
153
|
+
} = {}) => {
|
|
154
|
+
const callbacksMap = new Map();
|
|
155
|
+
let cleanup;
|
|
156
|
+
|
|
157
|
+
const addCallbacks = namedCallbacks => {
|
|
158
|
+
let callbacksMapSize = callbacksMap.size;
|
|
159
|
+
Object.keys(namedCallbacks).forEach(eventName => {
|
|
160
|
+
const callback = namedCallbacks[eventName];
|
|
161
|
+
const existingCallbacks = callbacksMap.get(eventName);
|
|
162
|
+
let callbacks;
|
|
163
|
+
|
|
164
|
+
if (existingCallbacks) {
|
|
165
|
+
callbacks = existingCallbacks;
|
|
166
|
+
} else {
|
|
167
|
+
callbacks = [];
|
|
168
|
+
callbacksMap.set(eventName, callbacks);
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
callbacks.push(callback);
|
|
172
|
+
});
|
|
173
|
+
|
|
174
|
+
if (effect && callbacksMapSize === 0 && callbacksMapSize.size > 0) {
|
|
175
|
+
cleanup = effect();
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
let removed = false;
|
|
179
|
+
return () => {
|
|
180
|
+
if (removed) return;
|
|
181
|
+
removed = true;
|
|
182
|
+
callbacksMapSize = callbacksMap.size;
|
|
183
|
+
Object.keys(namedCallbacks).forEach(eventName => {
|
|
184
|
+
const callback = namedCallbacks[eventName];
|
|
185
|
+
const callbacks = callbacksMap.get(eventName);
|
|
186
|
+
|
|
187
|
+
if (callbacks) {
|
|
188
|
+
const index = callbacks.indexOf(callback);
|
|
189
|
+
|
|
190
|
+
if (index > -1) {
|
|
191
|
+
callbacks.splice(index, 1);
|
|
192
|
+
|
|
193
|
+
if (callbacks.length === 0) {
|
|
194
|
+
callbacksMap.delete(eventName);
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
});
|
|
199
|
+
namedCallbacks = null; // allow garbage collect
|
|
200
|
+
|
|
201
|
+
if (cleanup && typeof cleanup === "function" && callbacksMapSize > 0 && callbacksMapSize.size === 0) {
|
|
202
|
+
cleanup();
|
|
203
|
+
cleanup = null;
|
|
204
|
+
}
|
|
205
|
+
};
|
|
206
|
+
};
|
|
207
|
+
|
|
208
|
+
const triggerCallbacks = event => {
|
|
209
|
+
const callbacks = callbacksMap.get(event.type);
|
|
210
|
+
|
|
211
|
+
if (callbacks) {
|
|
212
|
+
callbacks.forEach(callback => {
|
|
213
|
+
callback(event);
|
|
214
|
+
});
|
|
215
|
+
}
|
|
216
|
+
};
|
|
217
|
+
|
|
218
|
+
const destroy = () => {
|
|
219
|
+
callbacksMap.clear();
|
|
220
|
+
|
|
221
|
+
if (cleanup) {
|
|
222
|
+
cleanup();
|
|
223
|
+
cleanup = null;
|
|
224
|
+
}
|
|
225
|
+
};
|
|
226
|
+
|
|
227
|
+
return {
|
|
228
|
+
addCallbacks,
|
|
229
|
+
triggerCallbacks,
|
|
230
|
+
destroy
|
|
231
|
+
};
|
|
232
|
+
};
|
|
233
|
+
|
|
234
|
+
const createWebSocketConnection = (websocketUrl, {
|
|
235
|
+
protocols = ["jsenv"],
|
|
236
|
+
useEventsToManageConnection = true,
|
|
237
|
+
retry = false,
|
|
238
|
+
retryAfter = 1000,
|
|
239
|
+
retryMaxAttempt = Infinity,
|
|
240
|
+
retryAllocatedMs = Infinity
|
|
241
|
+
} = {}) => {
|
|
242
|
+
const connectionManager = createConnectionManager(({
|
|
243
|
+
onClosed,
|
|
244
|
+
onOpen
|
|
245
|
+
}) => {
|
|
246
|
+
let socket = new WebSocket(websocketUrl, protocols);
|
|
247
|
+
let interval;
|
|
248
|
+
|
|
249
|
+
const cleanup = () => {
|
|
250
|
+
if (socket) {
|
|
251
|
+
socket.onerror = null;
|
|
252
|
+
socket.onopen = null;
|
|
253
|
+
socket.onclose = null;
|
|
254
|
+
socket.onmessage = null;
|
|
255
|
+
socket = null;
|
|
256
|
+
clearInterval(interval);
|
|
257
|
+
}
|
|
258
|
+
};
|
|
259
|
+
|
|
260
|
+
socket.onerror = () => {
|
|
261
|
+
cleanup();
|
|
262
|
+
onClosed();
|
|
263
|
+
};
|
|
264
|
+
|
|
265
|
+
socket.onopen = () => {
|
|
266
|
+
socket.onopen = null;
|
|
267
|
+
onOpen();
|
|
268
|
+
interval = setInterval(() => {
|
|
269
|
+
socket.send('{"type":"ping"}');
|
|
270
|
+
}, 30_000);
|
|
271
|
+
};
|
|
272
|
+
|
|
273
|
+
socket.onclose = () => {
|
|
274
|
+
cleanup();
|
|
275
|
+
onClosed();
|
|
276
|
+
};
|
|
277
|
+
|
|
278
|
+
socket.onmessage = messageEvent => {
|
|
279
|
+
const event = JSON.parse(messageEvent.data);
|
|
280
|
+
eventsManager.triggerCallbacks(event);
|
|
281
|
+
};
|
|
282
|
+
|
|
283
|
+
return () => {
|
|
284
|
+
if (socket) {
|
|
285
|
+
socket.close();
|
|
286
|
+
cleanup();
|
|
287
|
+
}
|
|
288
|
+
};
|
|
289
|
+
}, {
|
|
290
|
+
retry,
|
|
291
|
+
retryAfter,
|
|
292
|
+
retryMaxAttempt,
|
|
293
|
+
retryAllocatedMs
|
|
294
|
+
});
|
|
295
|
+
const eventsManager = createEventsManager({
|
|
296
|
+
effect: () => {
|
|
297
|
+
if (useEventsToManageConnection) {
|
|
298
|
+
connectionManager.connect();
|
|
299
|
+
return () => {
|
|
300
|
+
connectionManager.disconnect();
|
|
301
|
+
};
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
return null;
|
|
305
|
+
}
|
|
306
|
+
});
|
|
307
|
+
return {
|
|
308
|
+
readyState: connectionManager.readyState,
|
|
309
|
+
connect: connectionManager.connect,
|
|
310
|
+
disconnect: connectionManager.disconnect,
|
|
311
|
+
listenEvents: namedCallbacks => {
|
|
312
|
+
return eventsManager.addCallbacks(namedCallbacks);
|
|
313
|
+
},
|
|
314
|
+
destroy: () => {
|
|
315
|
+
connectionManager.destroy();
|
|
316
|
+
eventsManager.destroy();
|
|
317
|
+
}
|
|
318
|
+
};
|
|
319
|
+
};
|
|
320
|
+
|
|
321
|
+
/* globals self */
|
|
322
|
+
const websocketScheme = self.location.protocol === "https" ? "wss" : "ws";
|
|
323
|
+
const websocketUrl = `${websocketScheme}://${self.location.host}${self.location.pathname}${self.location.search}`;
|
|
324
|
+
const websocketConnection = createWebSocketConnection(websocketUrl, {
|
|
325
|
+
retry: true,
|
|
326
|
+
retryAllocatedMs: 10_000
|
|
294
327
|
});
|
|
295
328
|
const {
|
|
296
|
-
|
|
329
|
+
readyState,
|
|
297
330
|
connect,
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
} =
|
|
331
|
+
disconnect,
|
|
332
|
+
listenEvents
|
|
333
|
+
} = websocketConnection;
|
|
301
334
|
window.__server_events__ = {
|
|
302
|
-
|
|
303
|
-
status,
|
|
335
|
+
readyState,
|
|
304
336
|
connect,
|
|
305
|
-
disconnect
|
|
337
|
+
disconnect,
|
|
338
|
+
listenEvents
|
|
306
339
|
};
|
|
307
340
|
connect();
|