Cleanup yomichan api (#1394)
* Move invokeMessageHandler to core.js * Move getMessageResponseResult to backghend.js * Replace getTemporaryListenerResult
This commit is contained in:
parent
9279ced686
commit
48b59375eb
@ -111,6 +111,7 @@
|
|||||||
"deepEqual": "readonly",
|
"deepEqual": "readonly",
|
||||||
"generateId": "readonly",
|
"generateId": "readonly",
|
||||||
"promiseAnimationFrame": "readonly",
|
"promiseAnimationFrame": "readonly",
|
||||||
|
"invokeMessageHandler": "readonly",
|
||||||
"log": "readonly",
|
"log": "readonly",
|
||||||
"DynamicProperty": "readonly",
|
"DynamicProperty": "readonly",
|
||||||
"EventDispatcher": "readonly",
|
"EventDispatcher": "readonly",
|
||||||
|
@ -238,7 +238,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);
|
return invokeMessageHandler(messageHandler, params, callback, sender);
|
||||||
}
|
}
|
||||||
|
|
||||||
_onZoomChanged({newZoomFactor}) {
|
_onZoomChanged({newZoomFactor}) {
|
||||||
@ -455,7 +455,7 @@ class Frontend {
|
|||||||
async _getIframeProxyPopup() {
|
async _getIframeProxyPopup() {
|
||||||
const targetFrameId = 0; // Root frameId
|
const targetFrameId = 0; // Root frameId
|
||||||
try {
|
try {
|
||||||
await this._waitForFrontendReady(targetFrameId);
|
await this._waitForFrontendReady(targetFrameId, 10000);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
// Root frame not available
|
// Root frame not available
|
||||||
return await this._getDefaultPopup();
|
return await this._getDefaultPopup();
|
||||||
@ -613,21 +613,40 @@ class Frontend {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async _waitForFrontendReady(frameId) {
|
async _waitForFrontendReady(frameId, timeout) {
|
||||||
const promise = yomichan.getTemporaryListenerResult(
|
return new Promise((resolve, reject) => {
|
||||||
chrome.runtime.onMessage,
|
let timeoutId = null;
|
||||||
({action, params}, {resolve}) => {
|
|
||||||
if (
|
const cleanup = () => {
|
||||||
action === 'frontendReady' &&
|
if (timeoutId !== null) {
|
||||||
params.frameId === frameId
|
clearTimeout(timeoutId);
|
||||||
) {
|
timeoutId = null;
|
||||||
resolve();
|
|
||||||
}
|
}
|
||||||
},
|
chrome.runtime.onMessage.removeListener(onMessage);
|
||||||
10000
|
};
|
||||||
);
|
const onMessage = (message, sender, sendResponse) => {
|
||||||
yomichan.api.broadcastTab('requestFrontendReadyBroadcast', {frameId: this._frameId});
|
try {
|
||||||
await promise;
|
const {action, params} = message;
|
||||||
|
if (action === 'frontendReady' && params.frameId === frameId) {
|
||||||
|
cleanup();
|
||||||
|
resolve();
|
||||||
|
sendResponse();
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
// NOP
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if (timeout !== null) {
|
||||||
|
timeoutId = setTimeout(() => {
|
||||||
|
timeoutId = null;
|
||||||
|
cleanup();
|
||||||
|
reject(new Error(`Wait for frontend ready timed out after ${timeout}ms`));
|
||||||
|
}, timeout);
|
||||||
|
}
|
||||||
|
|
||||||
|
chrome.runtime.onMessage.addListener(onMessage);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
_getPreventMiddleMouseValueForPageType(preventMiddleMouseOptions) {
|
_getPreventMiddleMouseValueForPageType(preventMiddleMouseOptions) {
|
||||||
|
@ -307,7 +307,7 @@ class Backend {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return yomichan.invokeMessageHandler(messageHandler, params, callback, sender);
|
return invokeMessageHandler(messageHandler, params, callback, sender);
|
||||||
}
|
}
|
||||||
|
|
||||||
_onConnect(port) {
|
_onConnect(port) {
|
||||||
@ -1563,7 +1563,7 @@ class Backend {
|
|||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
const callback = (response) => {
|
const callback = (response) => {
|
||||||
try {
|
try {
|
||||||
resolve(yomichan.getMessageResponseResult(response));
|
resolve(this._getMessageResponseResult(response));
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
reject(error);
|
reject(error);
|
||||||
}
|
}
|
||||||
@ -1573,6 +1573,21 @@ class Backend {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_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 deserializeError(error);
|
||||||
|
}
|
||||||
|
return response.result;
|
||||||
|
}
|
||||||
|
|
||||||
async _checkTabUrl(tabId, urlPredicate) {
|
async _checkTabUrl(tabId, urlPredicate) {
|
||||||
let tab;
|
let tab;
|
||||||
try {
|
try {
|
||||||
|
@ -191,7 +191,7 @@ class CrossFrameAPIPort extends EventDispatcher {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const callback = (data) => this._sendResult(id, data);
|
const callback = (data) => this._sendResult(id, data);
|
||||||
return yomichan.invokeMessageHandler(messageHandler, params, callback);
|
return invokeMessageHandler(messageHandler, params, callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
_sendResponse(data) {
|
_sendResponse(data) {
|
||||||
|
@ -341,6 +341,42 @@ function promiseAnimationFrame(timeout=null) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Invokes a standard message handler. This function is used to react and respond
|
||||||
|
* to communication messages within the extension.
|
||||||
|
* @param handler A handler function which is passed `params` and `...extraArgs` as arguments.
|
||||||
|
* @param async Whether or not the handler is async or not. Values include `false`, `true`, or `'dynamic'`.
|
||||||
|
* When the value is `'dynamic'`, the handler should return an object of the format `{async: boolean, result: any}`.
|
||||||
|
* @param params Information which was passed with the original message.
|
||||||
|
* @param callback A callback function which is invoked after the handler has completed. The value passed
|
||||||
|
* to the function is in the format:
|
||||||
|
* * `{result: any}` if the handler invoked successfully.
|
||||||
|
* * `{error: object}` if the handler thew an error. The error is serialized.
|
||||||
|
* @param extraArgs Additional arguments which are passed to the `handler` function.
|
||||||
|
* @returns `true` if the function is invoked asynchronously, `false` otherwise.
|
||||||
|
*/
|
||||||
|
function 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: serializeError(error)}); }
|
||||||
|
);
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
callback({result: promiseOrResult});
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
callback({error: serializeError(error)});
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Base class controls basic event dispatching.
|
* Base class controls basic event dispatching.
|
||||||
*/
|
*/
|
||||||
|
@ -463,7 +463,7 @@ class Display extends EventDispatcher {
|
|||||||
if (typeof messageHandler === 'undefined') { return; }
|
if (typeof messageHandler === 'undefined') { return; }
|
||||||
|
|
||||||
const callback = () => {}; // NOP
|
const callback = () => {}; // NOP
|
||||||
yomichan.invokeMessageHandler(messageHandler, params, callback);
|
invokeMessageHandler(messageHandler, params, callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
_onMessageSetOptionsContext({optionsContext}) {
|
_onMessageSetOptionsContext({optionsContext}) {
|
||||||
|
@ -104,7 +104,7 @@ class SearchDisplayController {
|
|||||||
_onMessage({action, params}, sender, callback) {
|
_onMessage({action, params}, sender, callback) {
|
||||||
const messageHandler = this._messageHandlers.get(action);
|
const messageHandler = this._messageHandlers.get(action);
|
||||||
if (typeof messageHandler === 'undefined') { return false; }
|
if (typeof messageHandler === 'undefined') { return false; }
|
||||||
return yomichan.invokeMessageHandler(messageHandler, params, callback, sender);
|
return invokeMessageHandler(messageHandler, params, callback, sender);
|
||||||
}
|
}
|
||||||
|
|
||||||
_onKeyDown(e) {
|
_onKeyDown(e) {
|
||||||
|
@ -120,42 +120,6 @@ class Yomichan extends EventDispatcher {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
getTemporaryListenerResult(eventHandler, userCallback, timeout=null) {
|
|
||||||
if (!(
|
|
||||||
typeof eventHandler.addListener === 'function' &&
|
|
||||||
typeof eventHandler.removeListener === 'function'
|
|
||||||
)) {
|
|
||||||
throw new Error('Event handler type not supported');
|
|
||||||
}
|
|
||||||
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
const runtimeMessageCallback = ({action, params}, sender, sendResponse) => {
|
|
||||||
let timeoutId = null;
|
|
||||||
if (timeout !== null) {
|
|
||||||
timeoutId = setTimeout(() => {
|
|
||||||
timeoutId = null;
|
|
||||||
eventHandler.removeListener(runtimeMessageCallback);
|
|
||||||
reject(new Error(`Listener timed out in ${timeout} ms`));
|
|
||||||
}, timeout);
|
|
||||||
}
|
|
||||||
|
|
||||||
const cleanupResolve = (value) => {
|
|
||||||
if (timeoutId !== null) {
|
|
||||||
clearTimeout(timeoutId);
|
|
||||||
timeoutId = null;
|
|
||||||
}
|
|
||||||
eventHandler.removeListener(runtimeMessageCallback);
|
|
||||||
sendResponse();
|
|
||||||
resolve(value);
|
|
||||||
};
|
|
||||||
|
|
||||||
userCallback({action, params}, {resolve: cleanupResolve, sender});
|
|
||||||
};
|
|
||||||
|
|
||||||
eventHandler.addListener(runtimeMessageCallback);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
sendMessage(...args) {
|
sendMessage(...args) {
|
||||||
try {
|
try {
|
||||||
return chrome.runtime.sendMessage(...args);
|
return chrome.runtime.sendMessage(...args);
|
||||||
@ -174,43 +138,6 @@ class Yomichan extends EventDispatcher {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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 deserializeError(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: serializeError(error)}); }
|
|
||||||
);
|
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
callback({result: promiseOrResult});
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
callback({error: serializeError(error)});
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
triggerExtensionUnloaded() {
|
triggerExtensionUnloaded() {
|
||||||
this._isExtensionUnloaded = true;
|
this._isExtensionUnloaded = true;
|
||||||
if (this._isTriggeringExtensionUnloaded) { return; }
|
if (this._isTriggeringExtensionUnloaded) { return; }
|
||||||
@ -235,7 +162,7 @@ class Yomichan extends EventDispatcher {
|
|||||||
_onMessage({action, params}, sender, callback) {
|
_onMessage({action, params}, sender, callback) {
|
||||||
const messageHandler = this._messageHandlers.get(action);
|
const messageHandler = this._messageHandlers.get(action);
|
||||||
if (typeof messageHandler === 'undefined') { return false; }
|
if (typeof messageHandler === 'undefined') { return false; }
|
||||||
return this.invokeMessageHandler(messageHandler, params, callback, sender);
|
return invokeMessageHandler(messageHandler, params, callback, sender);
|
||||||
}
|
}
|
||||||
|
|
||||||
_onMessageIsReady() {
|
_onMessageIsReady() {
|
||||||
|
Loading…
Reference in New Issue
Block a user