aboutsummaryrefslogtreecommitdiffstats
path: root/language-web
diff options
context:
space:
mode:
authorLibravatar Kristóf Marussy <kristof@marussy.com>2021-10-25 20:34:47 +0200
committerLibravatar Kristóf Marussy <kristof@marussy.com>2021-10-31 19:26:12 +0100
commitc975961ea6b9a0ebc8896fb56deef7e973c2ce23 (patch)
tree6f89fc9125b49bf751df5856e72a2e6bed109bee /language-web
parentfix(web): only try to read properties of objects (diff)
downloadrefinery-c975961ea6b9a0ebc8896fb56deef7e973c2ce23.tar.gz
refinery-c975961ea6b9a0ebc8896fb56deef7e973c2ce23.tar.zst
refinery-c975961ea6b9a0ebc8896fb56deef7e973c2ce23.zip
feat(web): disconnect background tabs only
Diffstat (limited to 'language-web')
-rw-r--r--language-web/src/main/js/editor/XtextWebSocketClient.ts47
1 files changed, 29 insertions, 18 deletions
diff --git a/language-web/src/main/js/editor/XtextWebSocketClient.ts b/language-web/src/main/js/editor/XtextWebSocketClient.ts
index f930160a..c034f8c8 100644
--- a/language-web/src/main/js/editor/XtextWebSocketClient.ts
+++ b/language-web/src/main/js/editor/XtextWebSocketClient.ts
@@ -16,7 +16,7 @@ const WEBSOCKET_CLOSE_OK = 1000;
16 16
17const RECONNECT_DELAY_MS = 1000; 17const RECONNECT_DELAY_MS = 1000;
18 18
19const IDLE_TIMEOUT_MS = 10 * 60 * 1000; 19const BACKGROUND_IDLE_TIMEOUT_MS = 5 * 60 * 1000;
20 20
21const PING_TIMEOUT_MS = 10 * 1000; 21const PING_TIMEOUT_MS = 10 * 1000;
22 22
@@ -48,6 +48,9 @@ export class XtextWebSocketClient {
48 constructor(onReconnect: ReconnectHandler, onPush: PushHandler) { 48 constructor(onReconnect: ReconnectHandler, onPush: PushHandler) {
49 this.onReconnect = onReconnect; 49 this.onReconnect = onReconnect;
50 this.onPush = onPush; 50 this.onPush = onPush;
51 document.addEventListener('visibilitychange', () => {
52 this.scheduleIdleTimeout();
53 });
51 this.reconnect(); 54 this.reconnect();
52 } 55 }
53 56
@@ -79,6 +82,8 @@ export class XtextWebSocketClient {
79 return; 82 return;
80 } 83 }
81 log.info('Connected to xtext web services'); 84 log.info('Connected to xtext web services');
85 this.scheduleIdleTimeout();
86 this.schedulePingTimeout();
82 this.onReconnect(); 87 this.onReconnect();
83 }); 88 });
84 this.connection.addEventListener('error', (event) => { 89 this.connection.addEventListener('error', (event) => {
@@ -94,18 +99,29 @@ export class XtextWebSocketClient {
94 } 99 }
95 this.cleanupAndMaybeReconnect(); 100 this.cleanupAndMaybeReconnect();
96 }); 101 });
97 this.scheduleIdleTimeout();
98 this.schedulePingTimeout();
99 } 102 }
100 103
101 private scheduleIdleTimeout() { 104 private scheduleIdleTimeout() {
102 if (this.idleTimeout !== null) { 105 if (document.visibilityState === 'hidden') {
103 clearTimeout(this.idleTimeout); 106 if (this.idleTimeout !== null) {
107 return;
108 }
109 log.info('Lost visibility, will disconnect in', BACKGROUND_IDLE_TIMEOUT_MS, 'ms');
110 this.idleTimeout = setTimeout(() => {
111 this.idleTimeout = null;
112 if (!this.isClosed && document.visibilityState === 'hidden') {
113 log.info('Closing websocket connection due to inactivity');
114 this.close();
115 }
116 }, BACKGROUND_IDLE_TIMEOUT_MS);
117 } else {
118 log.info('Gained visibility, connection will be kept alive');
119 if (this.idleTimeout !== null) {
120 clearTimeout(this.idleTimeout);
121 this.idleTimeout = null;
122 }
123 this.ensureOpen();
104 } 124 }
105 this.idleTimeout = setTimeout(() => {
106 log.info('Closing websocket connection due to inactivity');
107 this.close();
108 }, IDLE_TIMEOUT_MS);
109 } 125 }
110 126
111 private schedulePingTimeout() { 127 private schedulePingTimeout() {
@@ -120,17 +136,17 @@ export class XtextWebSocketClient {
120 const ping = nanoid(); 136 const ping = nanoid();
121 log.trace('ping:', ping); 137 log.trace('ping:', ping);
122 this.pingTimeout = null; 138 this.pingTimeout = null;
123 this.internalSend({ 139 this.send({
124 ping, 140 ping,
125 }).catch((error) => {
126 log.error('ping error', error);
127 this.forceReconnectDueToError();
128 }).then((result) => { 141 }).then((result) => {
129 if (!isPongResult(result) || result.pong !== ping) { 142 if (!isPongResult(result) || result.pong !== ping) {
130 log.error('invalid pong'); 143 log.error('invalid pong');
131 this.forceReconnectDueToError(); 144 this.forceReconnectDueToError();
132 } 145 }
133 log.trace('pong:', ping); 146 log.trace('pong:', ping);
147 }).catch((error) => {
148 log.error('ping error', error);
149 this.forceReconnectDueToError();
134 }); 150 });
135 } 151 }
136 this.schedulePingTimeout(); 152 this.schedulePingTimeout();
@@ -179,11 +195,6 @@ export class XtextWebSocketClient {
179 if (!this.isOpen) { 195 if (!this.isOpen) {
180 throw new Error('Connection is not open'); 196 throw new Error('Connection is not open');
181 } 197 }
182 this.scheduleIdleTimeout();
183 return this.internalSend(request);
184 }
185
186 private internalSend(request: unknown): Promise<unknown> {
187 const messageId = this.nextMessageId.toString(16); 198 const messageId = this.nextMessageId.toString(16);
188 if (messageId in this.pendingRequests) { 199 if (messageId in this.pendingRequests) {
189 log.error('Message id wraparound still pending', messageId); 200 log.error('Message id wraparound still pending', messageId);