From 74709296e557dfeab2e465f8bd53681934fe8040 Mon Sep 17 00:00:00 2001 From: toasted-nutbread Date: Sat, 28 Aug 2021 14:22:16 -0400 Subject: [PATCH] Dictionary database worker refactoring (#1913) * Rename DictionaryWorker => DictionaryWorkerHandler * Rename var * Rename file * Simplify * Rename DictionaryDatabaseModifier => DictionaryWorker * Rename dictionary-database-modifier.js => dictionary-worker.js --- .eslintrc.json | 2 +- .../language/dictionary-database-modifier.js | 130 ----------------- ext/js/language/dictionary-worker-handler.js | 95 ++++++++++++ ext/js/language/dictionary-worker-main.js | 8 +- ext/js/language/dictionary-worker.js | 137 +++++++++++------- .../pages/settings/dictionary-controller.js | 5 +- .../settings/dictionary-import-controller.js | 5 +- ext/settings.html | 2 +- ext/welcome.html | 2 +- test/test-workers.js | 2 +- 10 files changed, 193 insertions(+), 195 deletions(-) delete mode 100644 ext/js/language/dictionary-database-modifier.js create mode 100644 ext/js/language/dictionary-worker-handler.js diff --git a/.eslintrc.json b/.eslintrc.json index edd254bf..1608bc9f 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -231,7 +231,7 @@ "ext/js/general/cache-map.js", "ext/js/language/dictionary-database.js", "ext/js/language/dictionary-importer.js", - "ext/js/language/dictionary-worker.js", + "ext/js/language/dictionary-worker-handler.js", "ext/js/language/dictionary-worker-media-loader.js", "ext/js/media/media-util.js" ], diff --git a/ext/js/language/dictionary-database-modifier.js b/ext/js/language/dictionary-database-modifier.js deleted file mode 100644 index 055c4769..00000000 --- a/ext/js/language/dictionary-database-modifier.js +++ /dev/null @@ -1,130 +0,0 @@ -/* - * Copyright (C) 2021 Yomichan Authors - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -/* global - * DictionaryImporterMediaLoader - */ - -class DictionaryDatabaseModifier { - constructor() { - this._dictionaryImporterMediaLoader = new DictionaryImporterMediaLoader(); - } - - importDictionary(archiveContent, details, onProgress) { - return this._invoke( - 'importDictionary', - {details, archiveContent}, - [archiveContent], - onProgress, - this._formatimportDictionaryResult.bind(this) - ); - } - - deleteDictionary(dictionaryTitle, onProgress) { - return this._invoke('deleteDictionary', {dictionaryTitle}, [], onProgress); - } - - // Private - - _invoke(action, params, transfer, onProgress, formatResult) { - return new Promise((resolve, reject) => { - const worker = new Worker('/js/language/dictionary-worker-main.js', {}); - const details = { - complete: false, - worker, - resolve, - reject, - onMessage: null, - onProgress, - formatResult - }; - const onMessage = this._onMessage.bind(this, details); - details.onMessage = onMessage; - worker.addEventListener('message', onMessage); - worker.postMessage({action, params}, transfer); - }); - } - - _onMessage(details, e) { - if (details.complete) { return; } - const {action, params} = e.data; - switch (action) { - case 'complete': - { - const {worker, resolve, reject, onMessage, formatResult} = details; - details.complete = true; - details.worker = null; - details.resolve = null; - details.reject = null; - details.onMessage = null; - details.onProgress = null; - details.formatResult = null; - worker.removeEventListener('message', onMessage); - worker.terminate(); - this._onMessageComplete(params, resolve, reject, formatResult); - } - break; - case 'progress': - this._onMessageProgress(params, details.onProgress); - break; - case 'getImageResolution': - this._onMessageGetImageResolution(params, details.worker); - break; - } - } - - _onMessageComplete(params, resolve, reject, formatResult) { - const {error} = params; - if (typeof error !== 'undefined') { - reject(deserializeError(error)); - } else { - let {result} = params; - try { - if (typeof formatResult === 'function') { - result = formatResult(result); - } - } catch (e) { - reject(e); - return; - } - resolve(result); - } - } - - _onMessageProgress(params, onProgress) { - if (typeof onProgress !== 'function') { return; } - const {args} = params; - onProgress(...args); - } - - async _onMessageGetImageResolution(params, worker) { - const {id, mediaType, content} = params; - let response; - try { - const result = await this._dictionaryImporterMediaLoader.getImageResolution(mediaType, content); - response = {id, result}; - } catch (e) { - response = {id, error: serializeError(e)}; - } - worker.postMessage({action: 'getImageResolution.response', params: response}); - } - - _formatimportDictionaryResult(result) { - result.errors = result.errors.map((error) => deserializeError(error)); - return result; - } -} diff --git a/ext/js/language/dictionary-worker-handler.js b/ext/js/language/dictionary-worker-handler.js new file mode 100644 index 00000000..88150f50 --- /dev/null +++ b/ext/js/language/dictionary-worker-handler.js @@ -0,0 +1,95 @@ +/* + * Copyright (C) 2021 Yomichan Authors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/* global + * DictionaryDatabase + * DictionaryImporter + * DictionaryWorkerMediaLoader + */ + +class DictionaryWorkerHandler { + constructor() { + this._mediaLoader = new DictionaryWorkerMediaLoader(); + } + + prepare() { + self.addEventListener('message', this._onMessage.bind(this), false); + } + + // Private + + _onMessage(e) { + const {action, params} = e.data; + switch (action) { + case 'importDictionary': + this._onMessageWithProgress(params, this._importDictionary.bind(this)); + break; + case 'deleteDictionary': + this._onMessageWithProgress(params, this._deleteDictionary.bind(this)); + break; + case 'getImageResolution.response': + this._mediaLoader.handleMessage(params); + break; + } + } + + async _onMessageWithProgress(params, handler) { + const onProgress = (...args) => { + self.postMessage({ + action: 'progress', + params: {args} + }); + }; + let response; + try { + const result = await handler(params, onProgress); + response = {result}; + } catch (e) { + response = {error: serializeError(e)}; + } + self.postMessage({action: 'complete', params: response}); + } + + async _importDictionary({details, archiveContent}, onProgress) { + const dictionaryDatabase = await this._getPreparedDictionaryDatabase(); + try { + const dictionaryImporter = new DictionaryImporter(this._mediaLoader, onProgress); + const {result, errors} = await dictionaryImporter.importDictionary(dictionaryDatabase, archiveContent, details); + return { + result, + errors: errors.map((error) => serializeError(error)) + }; + } finally { + dictionaryDatabase.close(); + } + } + + async _deleteDictionary({dictionaryTitle}, onProgress) { + const dictionaryDatabase = await this._getPreparedDictionaryDatabase(); + try { + return await dictionaryDatabase.deleteDictionary(dictionaryTitle, {rate: 1000}, onProgress); + } finally { + dictionaryDatabase.close(); + } + } + + async _getPreparedDictionaryDatabase() { + const dictionaryDatabase = new DictionaryDatabase(); + await dictionaryDatabase.prepare(); + return dictionaryDatabase; + } +} diff --git a/ext/js/language/dictionary-worker-main.js b/ext/js/language/dictionary-worker-main.js index e113b568..fbeaea1e 100644 --- a/ext/js/language/dictionary-worker-main.js +++ b/ext/js/language/dictionary-worker-main.js @@ -16,7 +16,7 @@ */ /* global - * DictionaryWorker + * DictionaryWorkerHandler */ self.importScripts( @@ -27,15 +27,15 @@ self.importScripts( '/js/general/cache-map.js', '/js/language/dictionary-database.js', '/js/language/dictionary-importer.js', - '/js/language/dictionary-worker.js', + '/js/language/dictionary-worker-handler.js', '/js/language/dictionary-worker-media-loader.js', '/js/media/media-util.js' ); (() => { try { - const dictionaryImporterWorker = new DictionaryWorker(); - dictionaryImporterWorker.prepare(); + const dictionaryWorkerHandler = new DictionaryWorkerHandler(); + dictionaryWorkerHandler.prepare(); } catch (e) { log.error(e); } diff --git a/ext/js/language/dictionary-worker.js b/ext/js/language/dictionary-worker.js index dc546657..4adfdaec 100644 --- a/ext/js/language/dictionary-worker.js +++ b/ext/js/language/dictionary-worker.js @@ -16,80 +16,115 @@ */ /* global - * DictionaryDatabase - * DictionaryImporter - * DictionaryWorkerMediaLoader + * DictionaryImporterMediaLoader */ class DictionaryWorker { constructor() { - this._mediaLoader = new DictionaryWorkerMediaLoader(); + this._dictionaryImporterMediaLoader = new DictionaryImporterMediaLoader(); } - prepare() { - self.addEventListener('message', this._onMessage.bind(this), false); + importDictionary(archiveContent, details, onProgress) { + return this._invoke( + 'importDictionary', + {details, archiveContent}, + [archiveContent], + onProgress, + this._formatimportDictionaryResult.bind(this) + ); + } + + deleteDictionary(dictionaryTitle, onProgress) { + return this._invoke('deleteDictionary', {dictionaryTitle}, [], onProgress); } // Private - _onMessage(e) { + _invoke(action, params, transfer, onProgress, formatResult) { + return new Promise((resolve, reject) => { + const worker = new Worker('/js/language/dictionary-worker-main.js', {}); + const details = { + complete: false, + worker, + resolve, + reject, + onMessage: null, + onProgress, + formatResult + }; + const onMessage = this._onMessage.bind(this, details); + details.onMessage = onMessage; + worker.addEventListener('message', onMessage); + worker.postMessage({action, params}, transfer); + }); + } + + _onMessage(details, e) { + if (details.complete) { return; } const {action, params} = e.data; switch (action) { - case 'importDictionary': - this._onMessageWithProgress(params, this._importDictionary.bind(this)); + case 'complete': + { + const {worker, resolve, reject, onMessage, formatResult} = details; + details.complete = true; + details.worker = null; + details.resolve = null; + details.reject = null; + details.onMessage = null; + details.onProgress = null; + details.formatResult = null; + worker.removeEventListener('message', onMessage); + worker.terminate(); + this._onMessageComplete(params, resolve, reject, formatResult); + } break; - case 'deleteDictionary': - this._onMessageWithProgress(params, this._deleteDictionary.bind(this)); + case 'progress': + this._onMessageProgress(params, details.onProgress); break; - case 'getImageResolution.response': - this._mediaLoader.handleMessage(params); + case 'getImageResolution': + this._onMessageGetImageResolution(params, details.worker); break; } } - async _onMessageWithProgress(params, handler) { - const onProgress = (...args) => { - self.postMessage({ - action: 'progress', - params: {args} - }); - }; + _onMessageComplete(params, resolve, reject, formatResult) { + const {error} = params; + if (typeof error !== 'undefined') { + reject(deserializeError(error)); + } else { + let {result} = params; + try { + if (typeof formatResult === 'function') { + result = formatResult(result); + } + } catch (e) { + reject(e); + return; + } + resolve(result); + } + } + + _onMessageProgress(params, onProgress) { + if (typeof onProgress !== 'function') { return; } + const {args} = params; + onProgress(...args); + } + + async _onMessageGetImageResolution(params, worker) { + const {id, mediaType, content} = params; let response; try { - const result = await handler(params, onProgress); - response = {result}; + const result = await this._dictionaryImporterMediaLoader.getImageResolution(mediaType, content); + response = {id, result}; } catch (e) { - response = {error: serializeError(e)}; + response = {id, error: serializeError(e)}; } - self.postMessage({action: 'complete', params: response}); + worker.postMessage({action: 'getImageResolution.response', params: response}); } - async _importDictionary({details, archiveContent}, onProgress) { - const dictionaryDatabase = await this._getPreparedDictionaryDatabase(); - try { - const dictionaryImporter = new DictionaryImporter(this._mediaLoader, onProgress); - const {result, errors} = await dictionaryImporter.importDictionary(dictionaryDatabase, archiveContent, details); - return { - result, - errors: errors.map((error) => serializeError(error)) - }; - } finally { - dictionaryDatabase.close(); - } - } - - async _deleteDictionary({dictionaryTitle}, onProgress) { - const dictionaryDatabase = await this._getPreparedDictionaryDatabase(); - try { - return await dictionaryDatabase.deleteDictionary(dictionaryTitle, {rate: 1000}, onProgress); - } finally { - dictionaryDatabase.close(); - } - } - - async _getPreparedDictionaryDatabase() { - const dictionaryDatabase = new DictionaryDatabase(); - await dictionaryDatabase.prepare(); - return dictionaryDatabase; + _formatimportDictionaryResult(result) { + result.errors = result.errors.map((error) => deserializeError(error)); + return result; } } diff --git a/ext/js/pages/settings/dictionary-controller.js b/ext/js/pages/settings/dictionary-controller.js index a041e791..2a44f9ad 100644 --- a/ext/js/pages/settings/dictionary-controller.js +++ b/ext/js/pages/settings/dictionary-controller.js @@ -16,7 +16,7 @@ */ /* global - * DictionaryDatabaseModifier + * DictionaryWorker */ class DictionaryEntry { @@ -679,8 +679,7 @@ class DictionaryController { } async _deleteDictionaryInternal(dictionaryTitle, onProgress) { - const dictionaryDatabaseModifier = new DictionaryDatabaseModifier(); - await dictionaryDatabaseModifier.deleteDictionary(dictionaryTitle, onProgress); + await new DictionaryWorker().deleteDictionary(dictionaryTitle, onProgress); yomichan.api.triggerDatabaseUpdated('dictionary', 'delete'); } diff --git a/ext/js/pages/settings/dictionary-import-controller.js b/ext/js/pages/settings/dictionary-import-controller.js index 2716756d..b6700c78 100644 --- a/ext/js/pages/settings/dictionary-import-controller.js +++ b/ext/js/pages/settings/dictionary-import-controller.js @@ -17,7 +17,7 @@ /* global * DictionaryController - * DictionaryDatabaseModifier + * DictionaryWorker */ class DictionaryImportController { @@ -213,8 +213,7 @@ class DictionaryImportController { async _importDictionary(file, importDetails, onProgress) { const archiveContent = await this._readFile(file); - const dictionaryDatabaseModifier = new DictionaryDatabaseModifier(); - const {result, errors} = await dictionaryDatabaseModifier.importDictionary(archiveContent, importDetails, onProgress); + const {result, errors} = await new DictionaryWorker().importDictionary(archiveContent, importDetails, onProgress); yomichan.api.triggerDatabaseUpdated('dictionary', 'import'); const errors2 = await this._addDictionarySettings(result.sequenced, result.title); diff --git a/ext/settings.html b/ext/settings.html index d4ea9ce6..f3ed6577 100644 --- a/ext/settings.html +++ b/ext/settings.html @@ -3483,8 +3483,8 @@ - + diff --git a/ext/welcome.html b/ext/welcome.html index e03ae5ec..26ae513c 100644 --- a/ext/welcome.html +++ b/ext/welcome.html @@ -405,8 +405,8 @@ - + diff --git a/test/test-workers.js b/test/test-workers.js index 892f1526..ec5ba002 100644 --- a/test/test-workers.js +++ b/test/test-workers.js @@ -97,7 +97,7 @@ function testServiceWorker() { function testWorkers() { testWorker( 'js/language/dictionary-worker-main.js', - {DictionaryWorker: StubClass} + {DictionaryWorkerHandler: StubClass} ); }