From ec42a7e4d61dc30c2839a7ff7be44bec131127a5 Mon Sep 17 00:00:00 2001 From: toasted-nutbread Date: Sat, 11 Jul 2020 15:20:00 -0400 Subject: [PATCH] Message handler refactor (#660) * Refactor searchQueryUpdate action * Use standard message handler style * Use name "promiseOrResult" for consistency * Use standard message handler convention for Yomichan message handlers * Use common message handler invoker --- ext/bg/js/backend.js | 54 +++++++++++++++++++------------------- ext/bg/js/search.js | 11 +++----- ext/fg/js/frontend.js | 20 +------------- ext/mixed/js/comm.js | 25 +++--------------- ext/mixed/js/yomichan.js | 56 ++++++++++++++++++++++++++++++++-------- 5 files changed, 80 insertions(+), 86 deletions(-) diff --git a/ext/bg/js/backend.js b/ext/bg/js/backend.js index 6e594f9b..07c32fa2 100644 --- a/ext/bg/js/backend.js +++ b/ext/bg/js/backend.js @@ -294,28 +294,16 @@ class Backend { const messageHandler = this._messageHandlers.get(action); if (typeof messageHandler === 'undefined') { return false; } - const {handler, async, contentScript} = messageHandler; - - try { - if (!contentScript) { + if (!messageHandler.contentScript) { + try { this._validatePrivilegedMessageSender(sender); - } - - const promiseOrResult = handler(params, sender); - if (async) { - promiseOrResult.then( - (result) => callback({result}), - (error) => callback({error: errorToJson(error)}) - ); - return true; - } else { - callback({result: promiseOrResult}); + } catch (error) { + callback({error: errorToJson(error)}); return false; } - } catch (error) { - callback({error: errorToJson(error)}); - return false; } + + return yomichan.invokeMessageHandler(messageHandler, params, callback, sender); } _onConnect(port) { @@ -814,11 +802,7 @@ class Backend { if (tab !== null) { await this._focusTab(tab); if (queryParams.query) { - await new Promise((resolve) => chrome.tabs.sendMessage( - tab.id, - {action: 'searchQueryUpdate', params: {text: queryParams.query}}, - resolve - )); + await this._updateSearchQuery(tab.id, queryParams.query); } return true; } @@ -882,6 +866,21 @@ class Backend { // Utilities + _updateSearchQuery(tabId, text) { + new Promise((resolve, reject) => { + const callback = (response) => { + try { + resolve(yomichan.getMessageResponseResult(response)); + } catch (error) { + reject(error); + } + }; + + const message = {action: 'updateSearchQuery', params: {text}}; + chrome.tabs.sendMessage(tabId, message, callback); + }); + } + _sendMessageAllTabs(action, params={}) { const callback = () => this._checkLastError(chrome.runtime.lastError); chrome.tabs.query({}, (tabs) => { @@ -1286,11 +1285,10 @@ class Backend { return new Promise((resolve) => { chrome.tabs.sendMessage(tab.id, {action: 'getUrl'}, {frameId: 0}, (response) => { let url = null; - if (!chrome.runtime.lastError) { - url = (response !== null && typeof response === 'object' && !Array.isArray(response) ? response.url : null); - if (url !== null && typeof url !== 'string') { - url = null; - } + try { + url = yomichan.getMessageResponseResult(response); + } catch (error) { + // NOP } resolve({tab, url}); }); diff --git a/ext/bg/js/search.js b/ext/bg/js/search.js index 9bbc66f2..52fc19f8 100644 --- a/ext/bg/js/search.js +++ b/ext/bg/js/search.js @@ -61,7 +61,7 @@ class DisplaySearch extends Display { ['Shift', new Set()] ]); this._runtimeMessageHandlers = new Map([ - ['searchQueryUpdate', this._onExternalSearchUpdate.bind(this)] + ['updateSearchQuery', {async: false, handler: this._onExternalSearchUpdate.bind(this)}] ]); this.setOptionsContext({ @@ -206,12 +206,9 @@ class DisplaySearch extends Display { } _onRuntimeMessage({action, params}, sender, callback) { - const handler = this._runtimeMessageHandlers.get(action); - if (typeof handler !== 'function') { return false; } - - const result = handler(params, sender); - callback(result); - return false; + const messageHandler = this._runtimeMessageHandlers.get(action); + if (typeof messageHandler === 'undefined') { return false; } + return yomichan.invokeMessageHandler(messageHandler, params, callback, sender); } _onCopy() { diff --git a/ext/fg/js/frontend.js b/ext/fg/js/frontend.js index 1618fa12..aa03d4b5 100644 --- a/ext/fg/js/frontend.js +++ b/ext/fg/js/frontend.js @@ -211,25 +211,7 @@ class Frontend { _onRuntimeMessage({action, params}, sender, callback) { const messageHandler = this._runtimeMessageHandlers.get(action); if (typeof messageHandler === 'undefined') { return false; } - - const {handler, async} = messageHandler; - - try { - const promiseOrResult = handler(params, sender); - if (async) { - promiseOrResult.then( - (result) => callback({result}), - (error) => callback({error: errorToJson(error)}) - ); - return true; - } else { - callback({result: promiseOrResult}); - return false; - } - } catch (error) { - callback({error: errorToJson(error)}); - return false; - } + return yomichan.invokeMessageHandler(messageHandler, params, callback, sender); } _onZoomChanged({newZoomFactor}) { diff --git a/ext/mixed/js/comm.js b/ext/mixed/js/comm.js index 182400e3..1516a98f 100644 --- a/ext/mixed/js/comm.js +++ b/ext/mixed/js/comm.js @@ -166,31 +166,14 @@ class CrossFrameAPIPort extends EventDispatcher { // Invocation _onInvoke(id, {action, params}) { + const callback = (response) => this._sendResponse({type: 'result', id, data: response}); const messageHandler = this._messageHandlers.get(action); if (typeof messageHandler === 'undefined') { - this._sendError(id, new Error(`Unknown action: ${action}`)); - return; + callback({error: new Error(`Unknown action: ${action}`)}); + return false; } - - let {handler, async} = messageHandler; - this._sendAck(id); - try { - let result = handler(params); - if (async === 'dynamic') { - ({async, result} = result); - } - if (async) { - result.then( - (result2) => this._sendResult(id, result2), - (error2) => this._sendError(id, error2) - ); - } else { - this._sendResult(id, result); - } - } catch (error) { - this._sendError(id, error); - } + return yomichan.invokeMessageHandler(messageHandler, params, callback); } _sendResponse(data) { diff --git a/ext/mixed/js/yomichan.js b/ext/mixed/js/yomichan.js index d921a5a2..7fffbaa6 100644 --- a/ext/mixed/js/yomichan.js +++ b/ext/mixed/js/yomichan.js @@ -54,10 +54,10 @@ const yomichan = (() => { this._isBackendPreparedPromiseResolve = resolve; this._messageHandlers = new Map([ - ['backendPrepared', this._onMessageBackendPrepared.bind(this)], - ['getUrl', this._onMessageGetUrl.bind(this)], - ['optionsUpdated', this._onMessageOptionsUpdated.bind(this)], - ['zoomChanged', this._onMessageZoomChanged.bind(this)] + ['backendPrepared', {async: false, handler: this._onMessageBackendPrepared.bind(this)}], + ['getUrl', {async: false, handler: this._onMessageGetUrl.bind(this)}], + ['optionsUpdated', {async: false, handler: this._onMessageOptionsUpdated.bind(this)}], + ['zoomChanged', {async: false, handler: this._onMessageZoomChanged.bind(this)}] ]); } @@ -210,6 +210,43 @@ const yomichan = (() => { } } + getMessageResponseResult(response) { + let error = chrome.runtime.lastError; + if (error) { + throw new Error(error.message); + } + if (!isObject(response)) { + throw new Error('Tab did not respond'); + } + error = response.error; + if (error) { + throw jsonToError(error); + } + return response.result; + } + + invokeMessageHandler({handler, async}, params, callback, ...extraArgs) { + try { + let promiseOrResult = handler(params, ...extraArgs); + if (async === 'dynamic') { + ({async, result: promiseOrResult} = promiseOrResult); + } + if (async) { + promiseOrResult.then( + (result) => { callback({result}); }, + (error) => { callback({error: errorToJson(error)}); } + ); + return true; + } else { + callback({result: promiseOrResult}); + return false; + } + } catch (error) { + callback({error: errorToJson(error)}); + return false; + } + } + // Private _onExtensionUnloaded(error) { @@ -222,16 +259,13 @@ const yomichan = (() => { } _getLogContext() { - return {url: this._getUrl()}; + return this._getUrl(); } _onMessage({action, params}, sender, callback) { - const handler = this._messageHandlers.get(action); - if (typeof handler !== 'function') { return false; } - - const result = handler(params, sender); - callback(result); - return false; + const messageHandler = this._messageHandlers.get(action); + if (typeof messageHandler === 'undefined') { return false; } + return this.invokeMessageHandler(messageHandler, params, callback, sender); } _onMessageBackendPrepared() {