aboutsummaryrefslogtreecommitdiffstats
path: root/subprojects/frontend/src/xtext/XtextWebSocketClient.ts
diff options
context:
space:
mode:
Diffstat (limited to 'subprojects/frontend/src/xtext/XtextWebSocketClient.ts')
-rw-r--r--subprojects/frontend/src/xtext/XtextWebSocketClient.ts65
1 files changed, 35 insertions, 30 deletions
diff --git a/subprojects/frontend/src/xtext/XtextWebSocketClient.ts b/subprojects/frontend/src/xtext/XtextWebSocketClient.ts
index a39620cb..6b734546 100644
--- a/subprojects/frontend/src/xtext/XtextWebSocketClient.ts
+++ b/subprojects/frontend/src/xtext/XtextWebSocketClient.ts
@@ -7,7 +7,8 @@ import CancelledError from '../utils/CancelledError';
7import PendingTask from '../utils/PendingTask'; 7import PendingTask from '../utils/PendingTask';
8import getLogger from '../utils/getLogger'; 8import getLogger from '../utils/getLogger';
9 9
10import webSocketMachine, { isWebSocketURLLocal } from './webSocketMachine'; 10import fetchBackendConfig from './fetchBackendConfig';
11import webSocketMachine from './webSocketMachine';
11import { 12import {
12 type XtextWebPushService, 13 type XtextWebPushService,
13 XtextResponse, 14 XtextResponse,
@@ -42,26 +43,18 @@ export default class XtextWebSocketClient {
42 private readonly pendingRequests = new Map<string, PendingTask<unknown>>(); 43 private readonly pendingRequests = new Map<string, PendingTask<unknown>>();
43 44
44 private readonly interpreter = interpret( 45 private readonly interpreter = interpret(
45 webSocketMachine 46 webSocketMachine.withConfig({
46 .withContext({ 47 actions: {
47 ...webSocketMachine.context, 48 openWebSocket: () => this.openWebSocket(),
48 webSocketURL: `${window.location.origin.replace( 49 closeWebSocket: () => this.closeWebSocket(),
49 /^http/, 50 notifyReconnect: () => this.onReconnect(),
50 'ws', 51 notifyDisconnect: () => this.onDisconnect(),
51 )}/xtext-service`, 52 cancelPendingRequests: () => this.cancelPendingRequests(),
52 }) 53 },
53 .withConfig({ 54 services: {
54 actions: { 55 pingService: () => this.sendPing(),
55 openWebSocket: ({ webSocketURL }) => this.openWebSocket(webSocketURL), 56 },
56 closeWebSocket: () => this.closeWebSocket(), 57 }),
57 notifyReconnect: () => this.onReconnect(),
58 notifyDisconnect: () => this.onDisconnect(),
59 cancelPendingRequests: () => this.cancelPendingRequests(),
60 },
61 services: {
62 pingService: () => this.sendPing(),
63 },
64 }),
65 { 58 {
66 logger: log.log.bind(log), 59 logger: log.log.bind(log),
67 }, 60 },
@@ -151,6 +144,7 @@ export default class XtextWebSocketClient {
151 | 'webSocket' 144 | 'webSocket'
152 | 'interpreter' 145 | 'interpreter'
153 | 'openListener' 146 | 'openListener'
147 | 'openWebSocket'
154 | 'errorListener' 148 | 'errorListener'
155 | 'closeListener' 149 | 'closeListener'
156 | 'messageListener' 150 | 'messageListener'
@@ -160,6 +154,7 @@ export default class XtextWebSocketClient {
160 webSocket: observable.ref, 154 webSocket: observable.ref,
161 interpreter: false, 155 interpreter: false,
162 openListener: false, 156 openListener: false,
157 openWebSocket: false,
163 errorListener: false, 158 errorListener: false,
164 closeListener: false, 159 closeListener: false,
165 messageListener: false, 160 messageListener: false,
@@ -221,9 +216,7 @@ export default class XtextWebSocketClient {
221 get networkMissing(): boolean { 216 get networkMissing(): boolean {
222 return ( 217 return (
223 this.state.matches('connection.temporarilyOffline') || 218 this.state.matches('connection.temporarilyOffline') ||
224 (this.disconnectedByUser && 219 (this.disconnectedByUser && this.state.matches('network.offline'))
225 this.state.matches('network.offline') &&
226 !isWebSocketURLLocal(this.state.context.webSocketURL))
227 ); 220 );
228 } 221 }
229 222
@@ -275,17 +268,27 @@ export default class XtextWebSocketClient {
275 this.interpreter.send(document.hidden ? 'TAB_HIDDEN' : 'TAB_VISIBLE'); 268 this.interpreter.send(document.hidden ? 'TAB_HIDDEN' : 'TAB_VISIBLE');
276 } 269 }
277 270
278 private openWebSocket(webSocketURL: string | undefined): void { 271 private openWebSocket(): void {
279 if (this.webSocket !== undefined) { 272 if (this.webSocket !== undefined) {
280 throw new Error('WebSocket already open'); 273 throw new Error('WebSocket already open');
281 } 274 }
282 275
283 if (webSocketURL === undefined) {
284 throw new Error('URL not configured');
285 }
286
287 log.debug('Creating WebSocket'); 276 log.debug('Creating WebSocket');
288 277
278 (async () => {
279 const { webSocketURL } = await fetchBackendConfig();
280 this.openWebSocketWithURL(webSocketURL);
281 })().catch((error) => {
282 log.error('Error while initializing connection', error);
283 const message = error instanceof Error ? error.message : String(error);
284 this.interpreter.send({
285 type: 'ERROR',
286 message,
287 });
288 });
289 }
290
291 private openWebSocketWithURL(webSocketURL: string): void {
289 this.webSocket = new WebSocket(webSocketURL, XTEXT_SUBPROTOCOL_V1); 292 this.webSocket = new WebSocket(webSocketURL, XTEXT_SUBPROTOCOL_V1);
290 this.webSocket.addEventListener('open', this.openListener); 293 this.webSocket.addEventListener('open', this.openListener);
291 this.webSocket.addEventListener('close', this.closeListener); 294 this.webSocket.addEventListener('close', this.closeListener);
@@ -295,7 +298,9 @@ export default class XtextWebSocketClient {
295 298
296 private closeWebSocket() { 299 private closeWebSocket() {
297 if (this.webSocket === undefined) { 300 if (this.webSocket === undefined) {
298 throw new Error('WebSocket already closed'); 301 // We might get here when there is a network error before the socket is initialized
302 // and we don't have to do anything to close it.
303 return;
299 } 304 }
300 305
301 log.debug('Closing WebSocket'); 306 log.debug('Closing WebSocket');