aboutsummaryrefslogtreecommitdiffstats
path: root/subprojects/frontend/src/xtext/XtextWebSocketClient.ts
diff options
context:
space:
mode:
authorLibravatar Kristóf Marussy <kristof@marussy.com>2022-08-12 19:54:46 +0200
committerLibravatar Kristóf Marussy <kristof@marussy.com>2022-08-12 19:54:46 +0200
commitd22c3b0c257f5daf5b401988a35ab9ce981a2341 (patch)
tree0a661c927c37b52197326d1c05e211daf9bd19e5 /subprojects/frontend/src/xtext/XtextWebSocketClient.ts
parentfix(language): rule parsing test (diff)
downloadrefinery-d22c3b0c257f5daf5b401988a35ab9ce981a2341.tar.gz
refinery-d22c3b0c257f5daf5b401988a35ab9ce981a2341.tar.zst
refinery-d22c3b0c257f5daf5b401988a35ab9ce981a2341.zip
refactor(frontend): move from Webpack to Vite
Also overhaulds the building and linting for frontend assets.
Diffstat (limited to 'subprojects/frontend/src/xtext/XtextWebSocketClient.ts')
-rw-r--r--subprojects/frontend/src/xtext/XtextWebSocketClient.ts94
1 files changed, 55 insertions, 39 deletions
diff --git a/subprojects/frontend/src/xtext/XtextWebSocketClient.ts b/subprojects/frontend/src/xtext/XtextWebSocketClient.ts
index 2ce20a54..ceb1f3fd 100644
--- a/subprojects/frontend/src/xtext/XtextWebSocketClient.ts
+++ b/subprojects/frontend/src/xtext/XtextWebSocketClient.ts
@@ -1,16 +1,17 @@
1import { nanoid } from 'nanoid'; 1import { nanoid } from 'nanoid';
2 2
3import { getLogger } from '../utils/logger'; 3import PendingTask from '../utils/PendingTask';
4import { PendingTask } from '../utils/PendingTask'; 4import Timer from '../utils/Timer';
5import { Timer } from '../utils/Timer'; 5import getLogger from '../utils/getLogger';
6
6import { 7import {
7 xtextWebErrorResponse, 8 XtextWebErrorResponse,
8 XtextWebRequest, 9 XtextWebRequest,
9 xtextWebOkResponse, 10 XtextWebOkResponse,
10 xtextWebPushMessage, 11 XtextWebPushMessage,
11 XtextWebPushService, 12 XtextWebPushService,
12} from './xtextMessages'; 13} from './xtextMessages';
13import { pongResult } from './xtextServiceResults'; 14import { PongResult } from './xtextServiceResults';
14 15
15const XTEXT_SUBPROTOCOL_V1 = 'tools.refinery.language.web.xtext.v1'; 16const XTEXT_SUBPROTOCOL_V1 = 'tools.refinery.language.web.xtext.v1';
16 17
@@ -18,7 +19,8 @@ const WEBSOCKET_CLOSE_OK = 1000;
18 19
19const RECONNECT_DELAY_MS = [200, 1000, 5000, 30_000]; 20const RECONNECT_DELAY_MS = [200, 1000, 5000, 30_000];
20 21
21const MAX_RECONNECT_DELAY_MS = RECONNECT_DELAY_MS[RECONNECT_DELAY_MS.length - 1]; 22const MAX_RECONNECT_DELAY_MS =
23 RECONNECT_DELAY_MS[RECONNECT_DELAY_MS.length - 1];
22 24
23const BACKGROUND_IDLE_TIMEOUT_MS = 5 * 60 * 1000; 25const BACKGROUND_IDLE_TIMEOUT_MS = 5 * 60 * 1000;
24 26
@@ -47,7 +49,7 @@ enum State {
47 TimedOut, 49 TimedOut,
48} 50}
49 51
50export class XtextWebSocketClient { 52export default class XtextWebSocketClient {
51 private nextMessageId = 0; 53 private nextMessageId = 0;
52 54
53 private connection!: WebSocket; 55 private connection!: WebSocket;
@@ -88,9 +90,11 @@ export class XtextWebSocketClient {
88 } 90 }
89 91
90 get isOpen(): boolean { 92 get isOpen(): boolean {
91 return this.state === State.TabVisible 93 return (
92 || this.state === State.TabHiddenIdle 94 this.state === State.TabVisible ||
93 || this.state === State.TabHiddenWaiting; 95 this.state === State.TabHiddenIdle ||
96 this.state === State.TabHiddenWaiting
97 );
94 } 98 }
95 99
96 private reconnect() { 100 private reconnect() {
@@ -104,7 +108,11 @@ export class XtextWebSocketClient {
104 this.connection = new WebSocket(webSocketUrl, XTEXT_SUBPROTOCOL_V1); 108 this.connection = new WebSocket(webSocketUrl, XTEXT_SUBPROTOCOL_V1);
105 this.connection.addEventListener('open', () => { 109 this.connection.addEventListener('open', () => {
106 if (this.connection.protocol !== XTEXT_SUBPROTOCOL_V1) { 110 if (this.connection.protocol !== XTEXT_SUBPROTOCOL_V1) {
107 log.error('Unknown subprotocol', this.connection.protocol, 'selected by server'); 111 log.error(
112 'Unknown subprotocol',
113 this.connection.protocol,
114 'selected by server',
115 );
108 this.forceReconnectOnError(); 116 this.forceReconnectOnError();
109 } 117 }
110 if (document.visibilityState === 'hidden') { 118 if (document.visibilityState === 'hidden') {
@@ -126,8 +134,11 @@ export class XtextWebSocketClient {
126 this.handleMessage(event.data); 134 this.handleMessage(event.data);
127 }); 135 });
128 this.connection.addEventListener('close', (event) => { 136 this.connection.addEventListener('close', (event) => {
129 if (this.isLogicallyClosed && event.code === WEBSOCKET_CLOSE_OK 137 if (
130 && this.pendingRequests.size === 0) { 138 this.isLogicallyClosed &&
139 event.code === WEBSOCKET_CLOSE_OK &&
140 this.pendingRequests.size === 0
141 ) {
131 log.info('Websocket closed'); 142 log.info('Websocket closed');
132 return; 143 return;
133 } 144 }
@@ -144,7 +155,10 @@ export class XtextWebSocketClient {
144 return; 155 return;
145 } 156 }
146 this.idleTimer.cancel(); 157 this.idleTimer.cancel();
147 if (this.state === State.TabHiddenIdle || this.state === State.TabHiddenWaiting) { 158 if (
159 this.state === State.TabHiddenIdle ||
160 this.state === State.TabHiddenWaiting
161 ) {
148 this.handleTabVisibleConnected(); 162 this.handleTabVisibleConnected();
149 return; 163 return;
150 } 164 }
@@ -183,7 +197,11 @@ export class XtextWebSocketClient {
183 this.closeConnection(1000, 'idle timeout'); 197 this.closeConnection(1000, 'idle timeout');
184 return; 198 return;
185 } 199 }
186 log.info('Waiting for', pending, 'pending requests before closing websocket'); 200 log.info(
201 'Waiting for',
202 pending,
203 'pending requests before closing websocket',
204 );
187 } 205 }
188 206
189 private sendPing() { 207 private sendPing() {
@@ -192,19 +210,21 @@ export class XtextWebSocketClient {
192 } 210 }
193 const ping = nanoid(); 211 const ping = nanoid();
194 log.trace('Ping', ping); 212 log.trace('Ping', ping);
195 this.send({ ping }).then((result) => { 213 this.send({ ping })
196 const parsedPongResult = pongResult.safeParse(result); 214 .then((result) => {
197 if (parsedPongResult.success && parsedPongResult.data.pong === ping) { 215 const parsedPongResult = PongResult.safeParse(result);
198 log.trace('Pong', ping); 216 if (parsedPongResult.success && parsedPongResult.data.pong === ping) {
199 this.pingTimer.schedule(); 217 log.trace('Pong', ping);
200 } else { 218 this.pingTimer.schedule();
201 log.error('Invalid pong:', parsedPongResult, 'expected:', ping); 219 } else {
220 log.error('Invalid pong:', parsedPongResult, 'expected:', ping);
221 this.forceReconnectOnError();
222 }
223 })
224 .catch((error) => {
225 log.error('Error while waiting for ping', error);
202 this.forceReconnectOnError(); 226 this.forceReconnectOnError();
203 } 227 });
204 }).catch((error) => {
205 log.error('Error while waiting for ping', error);
206 this.forceReconnectOnError();
207 });
208 } 228 }
209 229
210 send(request: unknown): Promise<unknown> { 230 send(request: unknown): Promise<unknown> {
@@ -250,13 +270,13 @@ export class XtextWebSocketClient {
250 this.forceReconnectOnError(); 270 this.forceReconnectOnError();
251 return; 271 return;
252 } 272 }
253 const okResponse = xtextWebOkResponse.safeParse(message); 273 const okResponse = XtextWebOkResponse.safeParse(message);
254 if (okResponse.success) { 274 if (okResponse.success) {
255 const { id, response } = okResponse.data; 275 const { id, response } = okResponse.data;
256 this.resolveRequest(id, response); 276 this.resolveRequest(id, response);
257 return; 277 return;
258 } 278 }
259 const errorResponse = xtextWebErrorResponse.safeParse(message); 279 const errorResponse = XtextWebErrorResponse.safeParse(message);
260 if (errorResponse.success) { 280 if (errorResponse.success) {
261 const { id, error, message: errorMessage } = errorResponse.data; 281 const { id, error, message: errorMessage } = errorResponse.data;
262 this.rejectRequest(id, new Error(`${error} error: ${errorMessage}`)); 282 this.rejectRequest(id, new Error(`${error} error: ${errorMessage}`));
@@ -266,14 +286,9 @@ export class XtextWebSocketClient {
266 } 286 }
267 return; 287 return;
268 } 288 }
269 const pushMessage = xtextWebPushMessage.safeParse(message); 289 const pushMessage = XtextWebPushMessage.safeParse(message);
270 if (pushMessage.success) { 290 if (pushMessage.success) {
271 const { 291 const { resource, stateId, service, push } = pushMessage.data;
272 resource,
273 stateId,
274 service,
275 push,
276 } = pushMessage.data;
277 this.onPush(resource, stateId, service, push); 292 this.onPush(resource, stateId, service, push);
278 } else { 293 } else {
279 log.error( 294 log.error(
@@ -343,7 +358,8 @@ export class XtextWebSocketClient {
343 private handleErrorState() { 358 private handleErrorState() {
344 this.state = State.Error; 359 this.state = State.Error;
345 this.reconnectTryCount += 1; 360 this.reconnectTryCount += 1;
346 const delay = RECONNECT_DELAY_MS[this.reconnectTryCount - 1] || MAX_RECONNECT_DELAY_MS; 361 const delay =
362 RECONNECT_DELAY_MS[this.reconnectTryCount - 1] || MAX_RECONNECT_DELAY_MS;
347 log.info('Reconnecting in', delay, 'ms'); 363 log.info('Reconnecting in', delay, 'ms');
348 this.reconnectTimer.schedule(delay); 364 this.reconnectTimer.schedule(delay);
349 } 365 }