1

Work on remote API

This commit is contained in:
Alex Yatskov 2016-05-01 18:42:17 -07:00
parent 820348f7c2
commit 6e7938a93c
6 changed files with 129 additions and 42 deletions

View File

@ -29,14 +29,14 @@ class AjaxRequest:
class AjaxClient: class AjaxClient:
def __init__(self, sock, callback): def __init__(self, sock, handler):
self.sock = sock self.sock = sock
self.callback = callback self.handler = handler
self.readBuff = ''
self.readBuff = '' self.readBuff = ''
self.writeBuff = ''
def advance(self, recvSize=1): def advance(self, recvSize=1024):
if self.sock is None: if self.sock is None:
return False return False
@ -53,12 +53,12 @@ class AjaxClient:
req, length = self.parseRequest(self.readBuff) req, length = self.parseRequest(self.readBuff)
if req is not None: if req is not None:
self.readBuff = self.readBuff[length:] self.readBuff = self.readBuff[length:]
self.readBuff += self.callback(req) self.writeBuff += self.handler(req)
if wlist and self.readBuff: if wlist and self.writeBuff:
length = self.sock.send(self.readBuff) length = self.sock.send(self.writeBuff)
self.readBuff = self.readBuff[length:] self.writeBuff = self.writeBuff[length:]
if not self.readBuff: if not self.writeBuff:
self.close() self.close()
return False return False
@ -71,7 +71,7 @@ class AjaxClient:
self.sock = None self.sock = None
self.readBuff = '' self.readBuff = ''
self.readBuff = '' self.writeBuff = ''
def parseRequest(self, data): def parseRequest(self, data):
@ -96,8 +96,8 @@ class AjaxClient:
class AjaxServer: class AjaxServer:
def __init__(self, callback): def __init__(self, handler):
self.callback = callback self.handler = handler
self.clients = [] self.clients = []
self.sock = None self.sock = None
@ -116,7 +116,7 @@ class AjaxServer:
clientSock = self.sock.accept()[0] clientSock = self.sock.accept()[0]
if clientSock is not None: if clientSock is not None:
clientSock.setblocking(False) clientSock.setblocking(False)
self.clients.append(AjaxClient(clientSock, self.callbackWrapper)) self.clients.append(AjaxClient(clientSock, self.handlerWrapper))
def advanceClients(self): def advanceClients(self):
@ -133,8 +133,8 @@ class AjaxServer:
self.sock.listen(backlog) self.sock.listen(backlog)
def callbackWrapper(self, req): def handlerWrapper(self, req):
body = json.dumps(self.callback(json.loads(req.body))) body = json.dumps(self.handler(json.loads(req.body)))
resp = '' resp = ''
headers = { headers = {

View File

@ -21,7 +21,7 @@ import aqt
class Anki: class Anki:
def addNote(self, deckName, modelName, fields, tags=list()): def addNote(self, deckName, modelName, fields, tags=[]):
note = self.createNote(deckName, modelName, fields, tags) note = self.createNote(deckName, modelName, fields, tags)
if note is not None: if note is not None:
collection = self.collection() collection = self.collection()
@ -35,7 +35,7 @@ class Anki:
return bool(self.createNote(deckName, modelName, fields)) return bool(self.createNote(deckName, modelName, fields))
def createNote(self, deckName, modelName, fields, tags=list()): def createNote(self, deckName, modelName, fields, tags=[]):
model = self.models().byName(modelName) model = self.models().byName(modelName)
if model is None: if model is None:
return None return None

View File

@ -65,15 +65,15 @@ class DialogPreferences(QtGui.QDialog, gen.preferences_ui.Ui_DialogPreferences):
def dialogToData(self): def dialogToData(self):
self.preferences['checkForUpdates'] = self.checkCheckForUpdates.isChecked() self.preferences['checkForUpdates'] = self.checkCheckForUpdates.isChecked()
self.preferences['rememberTextContent'] = self.checkRememberTextContent.isChecked() self.preferences['rememberTextContent'] = self.checkRememberTextContent.isChecked()
self.preferences['allowEditing'] = self.checkAllowEditing.isChecked() self.preferences['allowEditing'] = self.checkAllowEditing.isChecked()
self.preferences['loadRecentFile'] = self.checkLoadRecentFile.isChecked() self.preferences['loadRecentFile'] = self.checkLoadRecentFile.isChecked()
self.preferences['maxResults'] = self.spinMaxResults.value() self.preferences['maxResults'] = self.spinMaxResults.value()
self.preferences['scanLength'] = self.spinScanLength.value() self.preferences['scanLength'] = self.spinScanLength.value()
self.preferences['stripReadings'] = self.checkStripReadings.isChecked() self.preferences['stripReadings'] = self.checkStripReadings.isChecked()
self.preferences['enableRemoteApi'] = self.checkEnableRemoteApi.isChecked() self.preferences['enableRemoteApi'] = self.checkEnableRemoteApi.isChecked()
self.preferences['firstRun'] = False self.preferences['firstRun'] = False
if self.anki is not None: if self.anki is not None:
self.dialogToProfile() self.dialogToProfile()

View File

@ -30,30 +30,31 @@ import updates
class MainWindowReader(QtGui.QMainWindow, gen.reader_ui.Ui_MainWindowReader): class MainWindowReader(QtGui.QMainWindow, gen.reader_ui.Ui_MainWindowReader):
class State: class State:
def __init__(self): def __init__(self):
self.filename = unicode() self.filename = unicode()
self.kanjiDefs = list() self.kanjiDefs = []
self.scanPosition = 0 self.scanPosition = 0
self.searchPosition = 0 self.searchPosition = 0
self.searchText = unicode() self.searchText = unicode()
self.vocabDefs = list() self.vocabDefs = []
def __init__(self, parent, preferences, language, filename=None, anki=None, closed=None): def __init__(self, parent, preferences, language, filename=None, anki=None, remoteApi=None, closed=None):
QtGui.QMainWindow.__init__(self, parent) QtGui.QMainWindow.__init__(self, parent)
self.setupUi(self) self.setupUi(self)
self.textContent.mouseMoveEvent = self.onContentMouseMove self.textContent.mouseMoveEvent = self.onContentMouseMove
self.textContent.mousePressEvent = self.onContentMousePress self.textContent.mousePressEvent = self.onContentMousePress
self.dockAnki.setEnabled(anki is not None) self.dockAnki.setEnabled(anki is not None)
self.facts = list() self.facts = []
self.anki = anki self.anki = anki
self.closed = closed self.remoteApi = remoteApi
self.language = language self.closed = closed
self.language = language
self.preferences = preferences self.preferences = preferences
self.state = self.State() self.state = self.State()
self.updates = updates.UpdateFinder() self.updates = updates.UpdateFinder()
self.zoom = 0 self.zoom = 0
self.applyPreferences() self.applyPreferences()
self.updateRecentFiles() self.updateRecentFiles()
@ -103,6 +104,9 @@ class MainWindowReader(QtGui.QMainWindow, gen.reader_ui.Ui_MainWindowReader):
if self.preferences['windowSize'] is not None: if self.preferences['windowSize'] is not None:
self.resize(QtCore.QSize(*self.preferences['windowSize'])) self.resize(QtCore.QSize(*self.preferences['windowSize']))
if self.remoteApi is not None:
self.remoteApi.enable(self.preferences['enableRemoteApi'])
self.comboTags.addItems(self.preferences['tags']) self.comboTags.addItems(self.preferences['tags'])
self.applyPreferencesContent() self.applyPreferencesContent()
@ -587,8 +591,8 @@ class MainWindowReader(QtGui.QMainWindow, gen.reader_ui.Ui_MainWindowReader):
def importWordList(self, words): def importWordList(self, words):
self.state.vocabDefs = list() self.state.vocabDefs = []
self.state.kanjiDefs = list() self.state.kanjiDefs = []
for word in words: for word in words:
if self.dockVocab.isVisible(): if self.dockVocab.isVisible():

80
yomi_base/remote_api.py Normal file
View File

@ -0,0 +1,80 @@
# -*- coding: utf-8 -*-
# Copyright (C) 2016 Alex Yatskov <alex@foosoft.net>
# Author: Alex Yatskov <alex@foosoft.net>
#
# 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 <http://www.gnu.org/licenses/>.
from PyQt4 import QtCore
from ajax import AjaxServer
import constants
class RemoteApi:
def __init__(self, anki, enabled, interval=50):
self.server = None
self.enable(enabled)
self.timer = QtCore.QTimer()
self.timer.timeout.connect(self.advance)
self.timer.start(interval)
self.handlers = {
'addNote': self.apiAddNote,
'apiCanAddNote': self.apiCanAddNote,
'getVersion': self.apiGetVersion,
}
def enable(self, enabled=True):
if self.server is None and enabled:
self.server = AjaxServer(self.handler)
self.server.listen()
elif self.server is not None and not enabled:
self.server.close()
self.server = None
def advance(self):
if self.server is not None:
self.server.advance()
def handler(self, request):
self.handlers.get(request.get('action'), self.apiInvalidRequest)(request.get('data'))
def apiAddNote(self, data):
deckName = data.get('deckName', unicode())
modelName = data.get('modelName', unicode())
fields = data.get('fields', {})
tags = data.get('tags', [])
return self.anki.addNote(deckName, modelName, fields, tags)
def apiCanAddNote(self, data):
deckName = data.get('deckName', unicode())
modelName = data.get('modelName', unicode())
fields = data.get('fields', {})
return self.anki.canAddNote(deckName, modelName, fields)
def apiGetVersion(self, data):
return {'version': constants.c['appVersion']}
def apiInvalidRequest(self, data):
return {}

View File

@ -17,10 +17,11 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>. # along with this program. If not, see <http://www.gnu.org/licenses/>.
from PyQt4 import QtGui, QtCore from PyQt4 import QtGui
from yomi_base import japanese from yomi_base import japanese
from yomi_base.preference_data import Preferences from yomi_base.preference_data import Preferences
from yomi_base.reader import MainWindowReader from yomi_base.reader import MainWindowReader
from yomi_base.remote_api import RemoteApi
import sys import sys
@ -39,6 +40,7 @@ class YomichanPlugin(Yomichan):
self.window = None self.window = None
self.anki = anki_bridge.Anki() self.anki = anki_bridge.Anki()
self.parent = self.anki.window() self.parent = self.anki.window()
self.remoteApi = RemoteApi(self.anki, self.preferences['enableRemoteApi'])
separator = QtGui.QAction(self.parent) separator = QtGui.QAction(self.parent)
separator.setSeparator(True) separator.setSeparator(True)
@ -62,6 +64,7 @@ class YomichanPlugin(Yomichan):
self.language, self.language,
None, None,
self.anki, self.anki,
self.remoteApi,
self.onWindowClose self.onWindowClose
) )
self.window.show() self.window.show()