Immediate backend event handlers (#555)

* Add function to await until prepare is completed

* Create BackendEventHandler to synchronously set up event handling
This commit is contained in:
toasted-nutbread 2020-06-07 21:50:14 -04:00 committed by GitHub
parent 9767b76553
commit 839e306cac
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 106 additions and 18 deletions

View File

@ -75,9 +75,15 @@ class Backend {
this.popupWindow = null; this.popupWindow = null;
this._defaultBrowserActionTitle = null;
this._isPrepared = false; this._isPrepared = false;
this._prepareError = false; this._prepareError = false;
this._preparePromise = null;
this._prepareCompletePromise = new Promise((resolve, reject) => {
this._prepareCompleteResolve = resolve;
this._prepareCompleteReject = reject;
});
this._defaultBrowserActionTitle = null;
this._badgePrepareDelayTimer = null; this._badgePrepareDelayTimer = null;
this._logErrorLevel = null; this._logErrorLevel = null;
@ -134,7 +140,26 @@ class Backend {
]); ]);
} }
async prepare() { prepare() {
if (this._preparePromise === null) {
const promise = this._prepareInternal();
promise.then(
(value) => {
this._isPrepared = true;
this._prepareCompleteResolve(value);
},
(error) => {
this._prepareError = true;
this._prepareCompleteReject(error);
}
);
promise.finally(() => this._updateBadge());
this._preparePromise = promise;
}
return this._prepareCompletePromise;
}
async _prepareInternal() {
try { try {
this._defaultBrowserActionTitle = await this._getBrowserIconTitle(); this._defaultBrowserActionTitle = await this._getBrowserIconTitle();
this._badgePrepareDelayTimer = setTimeout(() => { this._badgePrepareDelayTimer = setTimeout(() => {
@ -156,15 +181,6 @@ class Backend {
this.onOptionsUpdated('background'); this.onOptionsUpdated('background');
if (isObject(chrome.commands) && isObject(chrome.commands.onCommand)) {
chrome.commands.onCommand.addListener(this._runCommand.bind(this));
}
if (isObject(chrome.tabs) && isObject(chrome.tabs.onZoomChange)) {
chrome.tabs.onZoomChange.addListener(this._onZoomChange.bind(this));
}
chrome.runtime.onMessage.addListener(this.onMessage.bind(this));
chrome.runtime.onConnect.addListener(this._onConnect.bind(this));
const options = this.getOptions(this.optionsContext); const options = this.getOptions(this.optionsContext);
if (options.general.showGuide) { if (options.general.showGuide) {
chrome.tabs.create({url: chrome.runtime.getURL('/bg/guide.html')}); chrome.tabs.create({url: chrome.runtime.getURL('/bg/guide.html')});
@ -175,10 +191,7 @@ class Backend {
this._sendMessageAllTabs('backendPrepared'); this._sendMessageAllTabs('backendPrepared');
const callback = () => this.checkLastError(chrome.runtime.lastError); const callback = () => this.checkLastError(chrome.runtime.lastError);
chrome.runtime.sendMessage({action: 'backendPrepared'}, callback); chrome.runtime.sendMessage({action: 'backendPrepared'}, callback);
this._isPrepared = true;
} catch (e) { } catch (e) {
this._prepareError = true;
yomichan.logError(e); yomichan.logError(e);
throw e; throw e;
} finally { } finally {
@ -186,15 +199,33 @@ class Backend {
clearTimeout(this._badgePrepareDelayTimer); clearTimeout(this._badgePrepareDelayTimer);
this._badgePrepareDelayTimer = null; this._badgePrepareDelayTimer = null;
} }
this._updateBadge();
} }
} }
prepareComplete() {
return this._prepareCompletePromise;
}
isPrepared() { isPrepared() {
return this._isPrepared; return this._isPrepared;
} }
handleCommand(...args) {
return this._runCommand(...args);
}
handleZoomChange(...args) {
return this._onZoomChange(...args);
}
handleConnect(...args) {
return this._onConnect(...args);
}
handleMessage(...args) {
return this.onMessage(...args);
}
_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) => {
@ -1293,3 +1324,57 @@ class Backend {
} }
} }
} }
class BackendEventHandler {
constructor(backend) {
this._backend = backend;
}
prepare() {
if (isObject(chrome.commands) && isObject(chrome.commands.onCommand)) {
const onCommand = this._createGenericEventHandler((...args) => this._backend.handleCommand(...args));
chrome.commands.onCommand.addListener(onCommand);
}
if (isObject(chrome.tabs) && isObject(chrome.tabs.onZoomChange)) {
const onZoomChange = this._createGenericEventHandler((...args) => this._backend.handleZoomChange(...args));
chrome.tabs.onZoomChange.addListener(onZoomChange);
}
const onConnect = this._createGenericEventHandler((...args) => this._backend.handleConnect(...args));
chrome.runtime.onConnect.addListener(onConnect);
const onMessage = this._onMessage.bind(this);
chrome.runtime.onMessage.addListener(onMessage);
}
// Event handlers
_createGenericEventHandler(handler) {
return this._onGenericEvent.bind(this, handler);
}
_onGenericEvent(handler, ...args) {
if (this._backend.isPrepared()) {
handler(...args);
return;
}
this._backend.prepareComplete().then(
() => { handler(...args); },
() => {} // NOP
);
}
_onMessage(message, sender, sendResponse) {
if (this._backend.isPrepared()) {
return this._backend.handleMessage(message, sender, sendResponse);
}
this._backend.prepareComplete().then(
() => { this._backend.handleMessage(message, sender, sendResponse); },
() => { sendResponse(); } // NOP
);
return true;
}
}

View File

@ -17,12 +17,15 @@
/* global /* global
* Backend * Backend
* BackendEventHandler
*/ */
(async () => { (() => {
const backend = new Backend(); const backend = new Backend();
const backendEventHandler = new BackendEventHandler(backend);
backendEventHandler.prepare();
if (typeof window === 'object' && window !== null) { if (typeof window === 'object' && window !== null) {
window.yomichanBackend = backend; window.yomichanBackend = backend;
} }
await backend.prepare(); backend.prepare();
})(); })();