From 5e9575185c7f778e9e0dce5aa69663e99713d335 Mon Sep 17 00:00:00 2001 From: Stefan Dej Date: Mon, 9 Sep 2024 23:22:28 +0200 Subject: [PATCH 1/2] chore(websocket): add function to send and wait for response Signed-off-by: Stefan Dej --- src/plugins/webSocketClient.ts | 53 +++++++++++++++++++++++++++++----- src/store/server/actions.ts | 40 ++++++++++++------------- 2 files changed, 64 insertions(+), 29 deletions(-) diff --git a/src/plugins/webSocketClient.ts b/src/plugins/webSocketClient.ts index 6e4820240..fd015816f 100644 --- a/src/plugins/webSocketClient.ts +++ b/src/plugins/webSocketClient.ts @@ -29,6 +29,13 @@ export class WebSocketClient { handleMessage(data: any) { const wait = this.getWaitById(data.id) + // reject promise if it exists + if ('error' in data && wait?.reject) { + wait.reject(data.error) + this.removeWaitById(wait.id) + return + } + // report error messages if (data.error?.message) { // only report errors, if not disconnected and no init component @@ -36,12 +43,7 @@ export class WebSocketClient { window.console.error(`Response Error: ${data.error.message} (${wait?.action ?? 'no action'})`) } - if (data.error.message === 'Unauthorized' && wait?.action === 'server/setConnectionId') { - this.close() - this.store?.dispatch('socket/setConnectionFailed', data.error.message) - } - - if (wait?.id) { + if (wait) { const modulename = wait.action?.split('/')[1] ?? null if ( @@ -68,8 +70,13 @@ export class WebSocketClient { return } + // resolve promise if it exists + if (wait?.resolve && 'result' in data) { + wait.resolve(data.result) + } + // pass result to action - if (wait?.action) { + if (wait.action) { let result = data.result if (result === 'ok') result = { result: result } if (typeof result === 'string') result = { result: result } @@ -158,7 +165,7 @@ export class WebSocketClient { if (options.loading) this.store?.dispatch('socket/addLoading', { name: options.loading }) - this.instance.send( + this.instance?.send( JSON.stringify({ jsonrpc: '2.0', method, @@ -168,6 +175,34 @@ export class WebSocketClient { ) } + async emitAndWait(method: string, params: Params, options: emitOptions = {}): Promise { + return new Promise((resolve, reject) => { + if (this.instance?.readyState !== WebSocket.OPEN) reject() + + const id = this.messageId++ + this.waits.push({ + id: id, + params: params, + action: options.action ?? null, + actionPayload: options.actionPayload ?? {}, + loading: options.loading ?? null, + resolve, + reject, + }) + + if (options.loading) this.store?.dispatch('socket/addLoading', { name: options.loading }) + + this.instance?.send( + JSON.stringify({ + jsonrpc: '2.0', + method, + params, + id, + }) + ) + }) + } + emitBatch(messages: BatchMessage[]): void { if (messages.length === 0) return if (this.instance?.readyState !== WebSocket.OPEN) return @@ -228,6 +263,8 @@ export interface Wait { action?: string | null actionPayload?: any loading?: string | null + resolve?: (value: any) => void + reject?: (reason: any) => void } interface Params { diff --git a/src/store/server/actions.ts b/src/store/server/actions.ts index 270b3e7e7..a32a32a2b 100644 --- a/src/store/server/actions.ts +++ b/src/store/server/actions.ts @@ -16,16 +16,33 @@ export const actions: ActionTree = { dispatch('updateManager/reset') }, - async init({ dispatch }) { + async init({ commit, dispatch, rootState }) { window.console.debug('init Server') + // identify client + try { + const connection = await Vue.$socket.emitAndWait('server.connection.identify', { + client_name: 'mainsail', + version: rootState.packageVersion, + type: 'web', + url: 'https://github.com/mainsail-crew/mainsail', + }) + commit('setConnectionId', connection.connection_id) + } catch (e: any) { + if (e.message === 'Unauthorized') { + this.dispatch('socket/setConnectionFailed', e.message) + } + + window.console.error('Error while identifying client: ' + e.message) + return + } + dispatch('socket/addInitModule', 'server/info', { root: true }) dispatch('socket/addInitModule', 'server/config', { root: true }) dispatch('socket/addInitModule', 'server/systemInfo', { root: true }) dispatch('socket/addInitModule', 'server/procStats', { root: true }) dispatch('socket/addInitModule', 'server/databaseList', { root: true }) - dispatch('identify') Vue.$socket.emit('server.info', {}, { action: 'server/initServerInfo' }) Vue.$socket.emit('server.config', {}, { action: 'server/initServerConfig' }) Vue.$socket.emit('machine.system_info', {}, { action: 'server/initSystemInfo' }) @@ -35,25 +52,6 @@ export const actions: ActionTree = { await dispatch('socket/removeInitModule', 'server', { root: true }) }, - identify({ dispatch, rootState }): void { - dispatch('socket/addInitModule', 'server/identify', { root: true }) - Vue.$socket.emit( - 'server.connection.identify', - { - client_name: 'mainsail', - version: rootState.packageVersion, - type: 'web', - url: 'https://github.com/mainsail-crew/mainsail', - }, - { action: 'server/setConnectionId' } - ) - }, - - setConnectionId({ commit, dispatch }, payload) { - commit('setConnectionId', payload.connection_id) - dispatch('socket/removeInitModule', 'server/identify', { root: true }) - }, - checkDatabases({ dispatch, commit }, payload) { if (payload.namespaces?.includes('mainsail')) { dispatch('socket/addInitModule', 'gui/init', { root: true }) From 15b71061f4f06341af334dc5c9da435dd6961b27 Mon Sep 17 00:00:00 2001 From: Stefan Dej Date: Sun, 15 Sep 2024 21:07:53 +0200 Subject: [PATCH 2/2] fix: execute resolve also without a data result Signed-off-by: Stefan Dej --- src/plugins/webSocketClient.ts | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/plugins/webSocketClient.ts b/src/plugins/webSocketClient.ts index fd015816f..1b12adfa7 100644 --- a/src/plugins/webSocketClient.ts +++ b/src/plugins/webSocketClient.ts @@ -71,9 +71,7 @@ export class WebSocketClient { } // resolve promise if it exists - if (wait?.resolve && 'result' in data) { - wait.resolve(data.result) - } + if (wait?.resolve) wait.resolve(data.result ?? {}) // pass result to action if (wait.action) {