aboutsummaryrefslogtreecommitdiffstats
path: root/language-web/src/main/js/xtext/XtextWebSocketClient.ts
diff options
context:
space:
mode:
authorLibravatar Kristóf Marussy <kristof@marussy.com>2021-11-16 03:00:45 +0100
committerLibravatar Kristóf Marussy <kristof@marussy.com>2021-11-16 03:11:00 +0100
commit5810a7eb3b19ef9868db170c9214686bfc613eee (patch)
treeda122997d4ad58f4104d0f84b06a00fe14e7ad02 /language-web/src/main/js/xtext/XtextWebSocketClient.ts
parentfeat(lang): basic formatting (diff)
downloadrefinery-5810a7eb3b19ef9868db170c9214686bfc613eee.tar.gz
refinery-5810a7eb3b19ef9868db170c9214686bfc613eee.tar.zst
refinery-5810a7eb3b19ef9868db170c9214686bfc613eee.zip
chore(web): json validation with zod
Use the zod library instead of manually written type assertions for validating json messages from the server. This makes it easier to add and handle new messages.
Diffstat (limited to 'language-web/src/main/js/xtext/XtextWebSocketClient.ts')
-rw-r--r--language-web/src/main/js/xtext/XtextWebSocketClient.ts67
1 files changed, 44 insertions, 23 deletions
diff --git a/language-web/src/main/js/xtext/XtextWebSocketClient.ts b/language-web/src/main/js/xtext/XtextWebSocketClient.ts
index 488e4b3b..2ce20a54 100644
--- a/language-web/src/main/js/xtext/XtextWebSocketClient.ts
+++ b/language-web/src/main/js/xtext/XtextWebSocketClient.ts
@@ -4,12 +4,13 @@ import { getLogger } from '../utils/logger';
4import { PendingTask } from '../utils/PendingTask'; 4import { PendingTask } from '../utils/PendingTask';
5import { Timer } from '../utils/Timer'; 5import { Timer } from '../utils/Timer';
6import { 6import {
7 isErrorResponse, 7 xtextWebErrorResponse,
8 isOkResponse, 8 XtextWebRequest,
9 isPushMessage, 9 xtextWebOkResponse,
10 IXtextWebRequest, 10 xtextWebPushMessage,
11 XtextWebPushService,
11} from './xtextMessages'; 12} from './xtextMessages';
12import { isPongResult } from './xtextServiceResults'; 13import { pongResult } from './xtextServiceResults';
13 14
14const XTEXT_SUBPROTOCOL_V1 = 'tools.refinery.language.web.xtext.v1'; 15const XTEXT_SUBPROTOCOL_V1 = 'tools.refinery.language.web.xtext.v1';
15 16
@@ -32,7 +33,7 @@ export type ReconnectHandler = () => void;
32export type PushHandler = ( 33export type PushHandler = (
33 resourceId: string, 34 resourceId: string,
34 stateId: string, 35 stateId: string,
35 service: string, 36 service: XtextWebPushService,
36 data: unknown, 37 data: unknown,
37) => void; 38) => void;
38 39
@@ -192,11 +193,12 @@ export class XtextWebSocketClient {
192 const ping = nanoid(); 193 const ping = nanoid();
193 log.trace('Ping', ping); 194 log.trace('Ping', ping);
194 this.send({ ping }).then((result) => { 195 this.send({ ping }).then((result) => {
195 if (isPongResult(result) && result.pong === ping) { 196 const parsedPongResult = pongResult.safeParse(result);
197 if (parsedPongResult.success && parsedPongResult.data.pong === ping) {
196 log.trace('Pong', ping); 198 log.trace('Pong', ping);
197 this.pingTimer.schedule(); 199 this.pingTimer.schedule();
198 } else { 200 } else {
199 log.error('Invalid pong'); 201 log.error('Invalid pong:', parsedPongResult, 'expected:', ping);
200 this.forceReconnectOnError(); 202 this.forceReconnectOnError();
201 } 203 }
202 }).catch((error) => { 204 }).catch((error) => {
@@ -222,7 +224,7 @@ export class XtextWebSocketClient {
222 const message = JSON.stringify({ 224 const message = JSON.stringify({
223 id: messageId, 225 id: messageId,
224 request, 226 request,
225 } as IXtextWebRequest); 227 } as XtextWebRequest);
226 log.trace('Sending message', message); 228 log.trace('Sending message', message);
227 return new Promise((resolve, reject) => { 229 return new Promise((resolve, reject) => {
228 const task = new PendingTask(resolve, reject, REQUEST_TIMEOUT_MS, () => { 230 const task = new PendingTask(resolve, reject, REQUEST_TIMEOUT_MS, () => {
@@ -248,23 +250,42 @@ export class XtextWebSocketClient {
248 this.forceReconnectOnError(); 250 this.forceReconnectOnError();
249 return; 251 return;
250 } 252 }
251 if (isOkResponse(message)) { 253 const okResponse = xtextWebOkResponse.safeParse(message);
252 this.resolveRequest(message.id, message.response); 254 if (okResponse.success) {
253 } else if (isErrorResponse(message)) { 255 const { id, response } = okResponse.data;
254 this.rejectRequest(message.id, new Error(`${message.error} error: ${message.message}`)); 256 this.resolveRequest(id, response);
255 if (message.error === 'server') { 257 return;
256 log.error('Reconnecting due to server error: ', message.message); 258 }
259 const errorResponse = xtextWebErrorResponse.safeParse(message);
260 if (errorResponse.success) {
261 const { id, error, message: errorMessage } = errorResponse.data;
262 this.rejectRequest(id, new Error(`${error} error: ${errorMessage}`));
263 if (error === 'server') {
264 log.error('Reconnecting due to server error: ', errorMessage);
257 this.forceReconnectOnError(); 265 this.forceReconnectOnError();
258 } 266 }
259 } else if (isPushMessage(message)) { 267 return;
260 this.onPush( 268 }
261 message.resource, 269 const pushMessage = xtextWebPushMessage.safeParse(message);
262 message.stateId, 270 if (pushMessage.success) {
263 message.service, 271 const {
264 message.push, 272 resource,
265 ); 273 stateId,
274 service,
275 push,
276 } = pushMessage.data;
277 this.onPush(resource, stateId, service, push);
266 } else { 278 } else {
267 log.error('Unexpected websocket message', message); 279 log.error(
280 'Unexpected websocket message:',
281 message,
282 'not ok response because:',
283 okResponse.error,
284 'not error response because:',
285 errorResponse.error,
286 'not push message because:',
287 pushMessage.error,
288 );
268 this.forceReconnectOnError(); 289 this.forceReconnectOnError();
269 } 290 }
270 } 291 }