Dictionary worker refactor (#1894)

* Rename dictionary worker files

* Rename classes

* Rename file

* Rename class

* Generalize the _invoke method

* Rename 'import' to 'importDictionary'

* Improve DictionaryImporterMediaLoader usage

* Refactor message handler

* Generalize onProgress event
This commit is contained in:
toasted-nutbread 2021-08-14 11:46:26 -04:00 committed by GitHub
parent cd78d56fee
commit 3e350bd563
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 129 additions and 109 deletions

View File

@ -231,8 +231,8 @@
"ext/js/general/cache-map.js",
"ext/js/language/dictionary-database.js",
"ext/js/language/dictionary-importer.js",
"ext/js/language/dictionary-importer-worker.js",
"ext/js/language/dictionary-importer-worker-media-loader.js",
"ext/js/language/dictionary-worker.js",
"ext/js/language/dictionary-worker-media-loader.js",
"ext/js/media/media-util.js"
],
"env": {

View File

@ -0,0 +1,109 @@
/*
* 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 <https://www.gnu.org/licenses/>.
*/
/* global
* DictionaryImporterMediaLoader
*/
class DictionaryDatabaseModifier {
constructor() {
this._dictionaryImporterMediaLoader = new DictionaryImporterMediaLoader();
}
importDictionary(archiveContent, details, onProgress) {
return this._invoke('importDictionary', {details, archiveContent}, [archiveContent], onProgress);
}
// Private
_invoke(action, params, transfer, onProgress) {
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
};
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} = details;
details.complete = true;
details.worker = null;
details.resolve = null;
details.reject = null;
details.onMessage = null;
worker.removeEventListener('message', onMessage);
worker.terminate();
this._onMessageComplete(params, resolve, reject);
}
break;
case 'progress':
this._onMessageProgress(params, details.onProgress);
break;
case 'getImageResolution':
this._onMessageGetImageResolution(params, details.worker);
break;
}
}
_onMessageComplete(params, resolve, reject) {
const {error} = params;
if (typeof error !== 'undefined') {
reject(deserializeError(error));
} else {
resolve(this._formatResult(params.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});
}
_formatResult(data) {
const {result, errors} = data;
const errors2 = errors.map((error) => deserializeError(error));
return {result, errors: errors2};
}
}

View File

@ -1,89 +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 <https://www.gnu.org/licenses/>.
*/
/* global
* DictionaryImporterMediaLoader
*/
class DictionaryImporterThreaded {
constructor(onProgress) {
this._onProgress = onProgress;
}
importDictionary(archiveContent, details) {
return new Promise((resolve, reject) => {
const dictionaryImporterMediaLoader = new DictionaryImporterMediaLoader();
const worker = new Worker('/js/language/dictionary-importer-worker-main.js', {});
const onMessage = (e) => {
const {action, params} = e.data;
switch (action) {
case 'complete':
worker.removeEventListener('message', onMessage);
worker.terminate();
this._onMessageComplete(params, resolve, reject);
break;
case 'progress':
this._onMessageProgress(params);
break;
case 'getImageResolution':
this._onMessageGetImageResolution(params, worker, dictionaryImporterMediaLoader);
break;
}
};
worker.addEventListener('message', onMessage);
worker.postMessage({
action: 'import',
params: {details, archiveContent}
}, [archiveContent]);
});
}
// Private
_onMessageComplete(params, resolve, reject) {
const {error} = params;
if (typeof error !== 'undefined') {
reject(deserializeError(error));
} else {
resolve(this._formatResult(params.result));
}
}
_onMessageProgress(params) {
if (typeof this._onProgress !== 'function') { return; }
const {args} = params;
this._onProgress(...args);
}
async _onMessageGetImageResolution(params, worker, dictionaryImporterMediaLoader) {
const {id, mediaType, content} = params;
let response;
try {
const result = await dictionaryImporterMediaLoader.getImageResolution(mediaType, content);
response = {id, result};
} catch (e) {
response = {id, error: serializeError(e)};
}
worker.postMessage({action: 'getImageResolution.response', params: response});
}
_formatResult(data) {
const {result, errors} = data;
const errors2 = errors.map((error) => deserializeError(error));
return {result, errors: errors2};
}
}

View File

@ -16,7 +16,7 @@
*/
/* global
* DictionaryImporterWorker
* DictionaryWorker
*/
self.importScripts(
@ -27,14 +27,14 @@ self.importScripts(
'/js/general/cache-map.js',
'/js/language/dictionary-database.js',
'/js/language/dictionary-importer.js',
'/js/language/dictionary-importer-worker.js',
'/js/language/dictionary-importer-worker-media-loader.js',
'/js/language/dictionary-worker.js',
'/js/language/dictionary-worker-media-loader.js',
'/js/media/media-util.js'
);
(() => {
try {
const dictionaryImporterWorker = new DictionaryImporterWorker();
const dictionaryImporterWorker = new DictionaryWorker();
dictionaryImporterWorker.prepare();
} catch (e) {
log.error(e);

View File

@ -19,7 +19,7 @@
* Class used for loading and validating media from a worker thread
* during the dictionary import process.
*/
class DictionaryImporterWorkerMediaLoader {
class DictionaryWorkerMediaLoader {
/**
* Creates a new instance of the media loader.
*/

View File

@ -18,12 +18,12 @@
/* global
* DictionaryDatabase
* DictionaryImporter
* DictionaryImporterWorkerMediaLoader
* DictionaryWorkerMediaLoader
*/
class DictionaryImporterWorker {
class DictionaryWorker {
constructor() {
this._mediaLoader = new DictionaryImporterWorkerMediaLoader();
this._mediaLoader = new DictionaryWorkerMediaLoader();
}
prepare() {
@ -35,8 +35,8 @@ class DictionaryImporterWorker {
_onMessage(e) {
const {action, params} = e.data;
switch (action) {
case 'import':
this._onImport(params);
case 'importDictionary':
this._onImportDictionary(params);
break;
case 'getImageResolution.response':
this._mediaLoader.handleMessage(params);
@ -44,7 +44,7 @@ class DictionaryImporterWorker {
}
}
async _onImport({details, archiveContent}) {
async _onImportDictionary({details, archiveContent}) {
const onProgress = (...args) => {
self.postMessage({
action: 'progress',

View File

@ -17,7 +17,7 @@
/* global
* DictionaryController
* DictionaryImporterThreaded
* DictionaryDatabaseModifier
*/
class DictionaryImportController {
@ -212,9 +212,9 @@ class DictionaryImportController {
}
async _importDictionary(file, importDetails, onProgress) {
const dictionaryImporter = new DictionaryImporterThreaded(onProgress);
const archiveContent = await this._readFile(file);
const {result, errors} = await dictionaryImporter.importDictionary(archiveContent, importDetails);
const dictionaryDatabaseModifier = new DictionaryDatabaseModifier();
const {result, errors} = await dictionaryDatabaseModifier.importDictionary(archiveContent, importDetails, onProgress);
yomichan.api.triggerDatabaseUpdated('dictionary', 'import');
const errors2 = await this._addDictionarySettings(result.sequenced, result.title);

View File

@ -3484,8 +3484,8 @@
<script src="/js/general/task-accumulator.js"></script>
<script src="/js/input/hotkey-util.js"></script>
<script src="/js/language/dictionary-database.js"></script>
<script src="/js/language/dictionary-database-modifier.js"></script>
<script src="/js/language/dictionary-importer-media-loader.js"></script>
<script src="/js/language/dictionary-importer-threaded.js"></script>
<script src="/js/language/sandbox/dictionary-data-util.js"></script>
<script src="/js/language/sandbox/japanese-util.js"></script>
<script src="/js/media/audio-system.js"></script>

View File

@ -406,8 +406,8 @@
<script src="/js/general/task-accumulator.js"></script>
<script src="/js/input/hotkey-util.js"></script>
<script src="/js/language/dictionary-database.js"></script>
<script src="/js/language/dictionary-database-modifier.js"></script>
<script src="/js/language/dictionary-importer-media-loader.js"></script>
<script src="/js/language/dictionary-importer-threaded.js"></script>
<script src="/js/media/media-util.js"></script>
<script src="/js/pages/settings/dictionary-controller.js"></script>
<script src="/js/pages/settings/dictionary-import-controller.js"></script>

View File

@ -96,8 +96,8 @@ function testServiceWorker() {
function testWorkers() {
testWorker(
'js/language/dictionary-importer-worker-main.js',
{DictionaryImporterWorker: StubClass}
'js/language/dictionary-worker-main.js',
{DictionaryWorker: StubClass}
);
}