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
This commit is contained in:
toasted-nutbread 2020-07-11 15:20:00 -04:00 committed by GitHub
parent 8389cd8ba2
commit ec42a7e4d6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 80 additions and 86 deletions

View File

@ -294,28 +294,16 @@ class Backend {
const messageHandler = this._messageHandlers.get(action); const messageHandler = this._messageHandlers.get(action);
if (typeof messageHandler === 'undefined') { return false; } if (typeof messageHandler === 'undefined') { return false; }
const {handler, async, contentScript} = messageHandler; if (!messageHandler.contentScript) {
try {
try {
if (!contentScript) {
this._validatePrivilegedMessageSender(sender); this._validatePrivilegedMessageSender(sender);
} } catch (error) {
callback({error: errorToJson(error)});
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; return false;
} }
} catch (error) {
callback({error: errorToJson(error)});
return false;
} }
return yomichan.invokeMessageHandler(messageHandler, params, callback, sender);
} }
_onConnect(port) { _onConnect(port) {
@ -814,11 +802,7 @@ class Backend {
if (tab !== null) { if (tab !== null) {
await this._focusTab(tab); await this._focusTab(tab);
if (queryParams.query) { if (queryParams.query) {
await new Promise((resolve) => chrome.tabs.sendMessage( await this._updateSearchQuery(tab.id, queryParams.query);
tab.id,
{action: 'searchQueryUpdate', params: {text: queryParams.query}},
resolve
));
} }
return true; return true;
} }
@ -882,6 +866,21 @@ class Backend {
// Utilities // 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={}) { _sendMessageAllTabs(action, params={}) {
const callback = () => this._checkLastError(chrome.runtime.lastError); const callback = () => this._checkLastError(chrome.runtime.lastError);
chrome.tabs.query({}, (tabs) => { chrome.tabs.query({}, (tabs) => {
@ -1286,11 +1285,10 @@ class Backend {
return new Promise((resolve) => { return new Promise((resolve) => {
chrome.tabs.sendMessage(tab.id, {action: 'getUrl'}, {frameId: 0}, (response) => { chrome.tabs.sendMessage(tab.id, {action: 'getUrl'}, {frameId: 0}, (response) => {
let url = null; let url = null;
if (!chrome.runtime.lastError) { try {
url = (response !== null && typeof response === 'object' && !Array.isArray(response) ? response.url : null); url = yomichan.getMessageResponseResult(response);
if (url !== null && typeof url !== 'string') { } catch (error) {
url = null; // NOP
}
} }
resolve({tab, url}); resolve({tab, url});
}); });

View File

@ -61,7 +61,7 @@ class DisplaySearch extends Display {
['Shift', new Set()] ['Shift', new Set()]
]); ]);
this._runtimeMessageHandlers = new Map([ this._runtimeMessageHandlers = new Map([
['searchQueryUpdate', this._onExternalSearchUpdate.bind(this)] ['updateSearchQuery', {async: false, handler: this._onExternalSearchUpdate.bind(this)}]
]); ]);
this.setOptionsContext({ this.setOptionsContext({
@ -206,12 +206,9 @@ class DisplaySearch extends Display {
} }
_onRuntimeMessage({action, params}, sender, callback) { _onRuntimeMessage({action, params}, sender, callback) {
const handler = this._runtimeMessageHandlers.get(action); const messageHandler = this._runtimeMessageHandlers.get(action);
if (typeof handler !== 'function') { return false; } if (typeof messageHandler === 'undefined') { return false; }
return yomichan.invokeMessageHandler(messageHandler, params, callback, sender);
const result = handler(params, sender);
callback(result);
return false;
} }
_onCopy() { _onCopy() {

View File

@ -211,25 +211,7 @@ class Frontend {
_onRuntimeMessage({action, params}, sender, callback) { _onRuntimeMessage({action, params}, sender, callback) {
const messageHandler = this._runtimeMessageHandlers.get(action); const messageHandler = this._runtimeMessageHandlers.get(action);
if (typeof messageHandler === 'undefined') { return false; } if (typeof messageHandler === 'undefined') { return false; }
return yomichan.invokeMessageHandler(messageHandler, params, callback, sender);
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;
}
} }
_onZoomChanged({newZoomFactor}) { _onZoomChanged({newZoomFactor}) {

View File

@ -166,31 +166,14 @@ class CrossFrameAPIPort extends EventDispatcher {
// Invocation // Invocation
_onInvoke(id, {action, params}) { _onInvoke(id, {action, params}) {
const callback = (response) => this._sendResponse({type: 'result', id, data: response});
const messageHandler = this._messageHandlers.get(action); const messageHandler = this._messageHandlers.get(action);
if (typeof messageHandler === 'undefined') { if (typeof messageHandler === 'undefined') {
this._sendError(id, new Error(`Unknown action: ${action}`)); callback({error: new Error(`Unknown action: ${action}`)});
return; return false;
} }
let {handler, async} = messageHandler;
this._sendAck(id); this._sendAck(id);
try { return yomichan.invokeMessageHandler(messageHandler, params, callback);
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);
}
} }
_sendResponse(data) { _sendResponse(data) {

View File

@ -54,10 +54,10 @@ const yomichan = (() => {
this._isBackendPreparedPromiseResolve = resolve; this._isBackendPreparedPromiseResolve = resolve;
this._messageHandlers = new Map([ this._messageHandlers = new Map([
['backendPrepared', this._onMessageBackendPrepared.bind(this)], ['backendPrepared', {async: false, handler: this._onMessageBackendPrepared.bind(this)}],
['getUrl', this._onMessageGetUrl.bind(this)], ['getUrl', {async: false, handler: this._onMessageGetUrl.bind(this)}],
['optionsUpdated', this._onMessageOptionsUpdated.bind(this)], ['optionsUpdated', {async: false, handler: this._onMessageOptionsUpdated.bind(this)}],
['zoomChanged', this._onMessageZoomChanged.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 // Private
_onExtensionUnloaded(error) { _onExtensionUnloaded(error) {
@ -222,16 +259,13 @@ const yomichan = (() => {
} }
_getLogContext() { _getLogContext() {
return {url: this._getUrl()}; return this._getUrl();
} }
_onMessage({action, params}, sender, callback) { _onMessage({action, params}, sender, callback) {
const handler = this._messageHandlers.get(action); const messageHandler = this._messageHandlers.get(action);
if (typeof handler !== 'function') { return false; } if (typeof messageHandler === 'undefined') { return false; }
return this.invokeMessageHandler(messageHandler, params, callback, sender);
const result = handler(params, sender);
callback(result);
return false;
} }
_onMessageBackendPrepared() { _onMessageBackendPrepared() {