Mecab test (#1361)

* Update Mecab API

* Add testMecab API function

* Add a test button for the Mecab component
This commit is contained in:
toasted-nutbread 2021-02-08 19:40:49 -05:00 committed by GitHub
parent 0ed24347ee
commit 0f5fb804d0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 163 additions and 2 deletions

View File

@ -122,7 +122,8 @@ class Backend {
['setAllSettings', {async: true, contentScript: false, handler: this._onApiSetAllSettings.bind(this)}],
['getOrCreateSearchPopup', {async: true, contentScript: true, handler: this._onApiGetOrCreateSearchPopup.bind(this)}],
['isTabSearchPopup', {async: true, contentScript: true, handler: this._onApiIsTabSearchPopup.bind(this)}],
['triggerDatabaseUpdated', {async: false, contentScript: true, handler: this._onApiTriggerDatabaseUpdated.bind(this)}]
['triggerDatabaseUpdated', {async: false, contentScript: true, handler: this._onApiTriggerDatabaseUpdated.bind(this)}],
['testMecab', {async: true, contentScript: true, handler: this._onApiTestMecab.bind(this)}]
]);
this._messageHandlersWithProgress = new Map([
]);
@ -676,6 +677,42 @@ class Backend {
this._triggerDatabaseUpdated(type, cause);
}
async _onApiTestMecab() {
if (!this._mecab.isEnabled()) {
throw new Error('MeCab not enabled');
}
let permissionsOkay = false;
try {
permissionsOkay = await this._hasPermissions({permissions: ['nativeMessaging']});
} catch (e) {
// NOP
}
if (!permissionsOkay) {
throw new Error('Insufficient permissions');
}
const disconnect = !this._mecab.isConnected();
try {
const version = await this._mecab.getVersion();
if (version === null) {
throw new Error('Could not connect to native MeCab component');
}
const localVersion = this._mecab.getLocalVersion();
if (version !== localVersion) {
throw new Error(`MeCab component version not supported: ${version}`);
}
} finally {
// Disconnect if the connection was previously disconnected
if (disconnect && this._mecab.isEnabled() && this._mecab.isActive()) {
this._mecab.disconnect();
}
}
return true;
}
// Command handlers
async _onCommandOpenSearchPage(params) {
@ -1904,4 +1941,15 @@ class Backend {
});
});
}
_hasPermissions(permissions) {
return new Promise((resolve, reject) => chrome.permissions.contains(permissions, (result) => {
const e = chrome.runtime.lastError;
if (e) {
reject(new Error(e.message));
} else {
resolve(result);
}
}));
}
}

View File

@ -53,6 +53,39 @@ class Mecab {
}
}
/**
* Disconnects the current port, but does not disable future connections.
*/
disconnect() {
if (this._port !== null) {
this._clearPort();
}
}
/**
* Returns whether or not the connection to the native application is active.
* @returns `true` if the connection is active, `false` otherwise.
*/
isConnected() {
return (this._port !== null);
}
/**
* Returns whether or not any invocation is currently active.
* @returns `true` if an invocation is active, `false` otherwise.
*/
isActive() {
return (this._invocations.size > 0);
}
/**
* Gets the local API version being used.
* @returns An integer representing the API version that Yomichan uses.
*/
getLocalVersion() {
return this._version;
}
/**
* Gets the version of the MeCab component.
* @returns The version of the MeCab component, or `null` if the component was not found.

View File

@ -0,0 +1,67 @@
/*
* 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
* api
*/
class MecabController {
constructor(settingsController) {
this._settingsController = settingsController;
this._testButton = null;
this._resultsContainer = null;
this._testActive = false;
}
prepare() {
this._testButton = document.querySelector('#test-mecab-button');
this._resultsContainer = document.querySelector('#test-mecab-results');
this._testButton.addEventListener('click', this._onTestButtonClick.bind(this), false);
}
// Private
_onTestButtonClick(e) {
e.preventDefault();
this._testMecab();
}
async _testMecab() {
if (this._testActive) { return; }
try {
this._testActive = true;
this._testButton.disabled = true;
this._resultsContainer.textContent = '';
this._resultsContainer.hidden = true;
await api.testMecab();
this._setStatus('Connection was successful', false);
} catch (e) {
this._setStatus(e.message, true);
} finally {
this._testActive = false;
this._testButton.disabled = false;
}
}
_setStatus(message, isError) {
this._resultsContainer.textContent = message;
this._resultsContainer.hidden = false;
this._resultsContainer.classList.toggle('danger-text', isError);
}
}

View File

@ -26,6 +26,7 @@
* ExtensionKeyboardShortcutController
* GenericSettingController
* KeyboardShortcutController
* MecabController
* ModalController
* NestedPopupsController
* PermissionsToggleController
@ -140,6 +141,9 @@ async function setupGenericSettingsController(genericSettingController) {
const popupWindowController = new PopupWindowController();
popupWindowController.prepare();
const mecabController = new MecabController();
mecabController.prepare();
await Promise.all(preparePromises);
document.documentElement.dataset.loaded = 'true';

View File

@ -1166,7 +1166,11 @@
In order for Yomichan to use it, both MeCab and a native messaging component must be installed.
A setup guide can be found <a href="https://github.com/siikamiika/yomichan-mecab-installer/blob/master/README.md" target="_blank" rel="noopener noreferrer">here</a>.
</p>
<p>
<div class="margin-above flex-row-nowrap">
<button id="test-mecab-button">Test</button>
<div id="test-mecab-results" class="flex-margin-left" hidden></div>
</div>
<p class="margin-above">
<a class="more-toggle" data-parent-distance="3">Less&hellip;</a>
</p>
</div>
@ -3241,6 +3245,7 @@
<script src="/bg/js/settings2/extension-keyboard-shortcuts-controller.js"></script>
<script src="/bg/js/settings2/keyboard-shortcuts-controller.js"></script>
<script src="/bg/js/settings2/mecab-controller.js"></script>
<script src="/bg/js/settings2/nested-popups-controller.js"></script>
<script src="/bg/js/settings2/popup-window-controller.js"></script>
<script src="/bg/js/settings2/secondary-search-dictionary-controller.js"></script>

View File

@ -193,6 +193,10 @@ const api = (() => {
return this._invoke('triggerDatabaseUpdated', {type, cause});
}
testMecab() {
return this._invoke('testMecab', {});
}
// Utilities
_createActionPort(timeout=5000) {