bridge->backend
This commit is contained in:
parent
5a8d088531
commit
3e1b474dca
|
@ -10,10 +10,10 @@
|
|||
.pytype
|
||||
__pycache__
|
||||
anki/buildhash.py
|
||||
anki/bridge_pb2.*
|
||||
anki/backend_pb2.*
|
||||
aqt/forms
|
||||
locale
|
||||
rs/ankirs/src/proto.rs
|
||||
rs/ankirs/src/backend_proto.rs
|
||||
rs/target
|
||||
tools/runanki.system
|
||||
ts/node_modules
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
[settings]
|
||||
skip=aqt/forms,anki/bridge_pb2.py,bridge_pb2.pyi
|
||||
skip=aqt/forms,anki/backend_pb2.py,backend_pb2.pyi
|
||||
multi_line_output=3
|
||||
include_trailing_comma=True
|
||||
force_grid_wrap=0
|
||||
|
|
4
Makefile
4
Makefile
|
@ -126,11 +126,11 @@ BUILDDEPS := .build/ui .build/js .build/rs .build/py-proto
|
|||
@touch $@
|
||||
|
||||
.build/rs: .build/rust-deps $(RUNREQS) $(RSDEPS) $(PROTODEPS)
|
||||
(cd rs/pybridge && maturin develop $(RUSTARGS))
|
||||
(cd rs/pymod && maturin develop $(RUSTARGS))
|
||||
@touch $@
|
||||
|
||||
.build/py-proto: $(RUNREQS) $(PROTODEPS)
|
||||
protoc --proto_path=proto --python_out=anki --mypy_out=anki proto/bridge.proto
|
||||
protoc --proto_path=proto --python_out=anki --mypy_out=anki proto/backend.proto
|
||||
@touch $@
|
||||
|
||||
.PHONY: build clean
|
||||
|
|
|
@ -6,9 +6,6 @@ import sys
|
|||
|
||||
from anki.storage import Collection
|
||||
|
||||
# temporary
|
||||
from . import rsbridge
|
||||
|
||||
if sys.version_info[0] < 3 or sys.version_info[1] < 5:
|
||||
raise Exception("Anki requires Python 3.5+")
|
||||
|
||||
|
|
|
@ -4,14 +4,14 @@ from typing import Dict, List
|
|||
|
||||
import _ankirs # pytype: disable=import-error
|
||||
|
||||
import anki.bridge_pb2 as pb
|
||||
import anki.backend_pb2 as pb
|
||||
|
||||
from .types import AllTemplateReqs
|
||||
|
||||
|
||||
class BridgeException(Exception):
|
||||
class BackendException(Exception):
|
||||
def __str__(self) -> str:
|
||||
err: pb.BridgeError = self.args[0] # pylint: disable=unsubscriptable-object
|
||||
err: pb.BackendError = self.args[0] # pylint: disable=unsubscriptable-object
|
||||
kind = err.WhichOneof("value")
|
||||
if kind == "invalid_input":
|
||||
return f"invalid input: {err.invalid_input.info}"
|
||||
|
@ -39,30 +39,30 @@ def proto_template_reqs_to_legacy(
|
|||
return legacy_reqs
|
||||
|
||||
|
||||
class RSBridge:
|
||||
class Backend:
|
||||
def __init__(self):
|
||||
self._bridge = _ankirs.Bridge()
|
||||
self._backend = _ankirs.Backend()
|
||||
|
||||
def _run_command(self, input: pb.BridgeInput) -> pb.BridgeOutput:
|
||||
def _run_command(self, input: pb.BackendInput) -> pb.BackendOutput:
|
||||
input_bytes = input.SerializeToString()
|
||||
output_bytes = self._bridge.command(input_bytes)
|
||||
output = pb.BridgeOutput()
|
||||
output_bytes = self._backend.command(input_bytes)
|
||||
output = pb.BackendOutput()
|
||||
output.ParseFromString(output_bytes)
|
||||
kind = output.WhichOneof("value")
|
||||
if kind == "error":
|
||||
raise BridgeException(output.error)
|
||||
raise BackendException(output.error)
|
||||
else:
|
||||
return output
|
||||
|
||||
def plus_one(self, num: int) -> int:
|
||||
input = pb.BridgeInput(plus_one=pb.PlusOneIn(num=num))
|
||||
input = pb.BackendInput(plus_one=pb.PlusOneIn(num=num))
|
||||
output = self._run_command(input)
|
||||
return output.plus_one.num
|
||||
|
||||
def template_requirements(
|
||||
self, template_fronts: List[str], field_map: Dict[str, int]
|
||||
) -> AllTemplateReqs:
|
||||
input = pb.BridgeInput(
|
||||
input = pb.BackendInput(
|
||||
template_requirements=pb.TemplateRequirementsIn(
|
||||
template_front=template_fronts, field_names_to_ordinals=field_map
|
||||
)
|
|
@ -19,6 +19,7 @@ import anki.find
|
|||
import anki.latex # sets up hook
|
||||
import anki.notes
|
||||
import anki.template
|
||||
from anki.backend import Backend
|
||||
from anki.cards import Card
|
||||
from anki.consts import *
|
||||
from anki.db import DB
|
||||
|
@ -29,7 +30,6 @@ from anki.lang import _, ngettext
|
|||
from anki.media import MediaManager
|
||||
from anki.models import ModelManager
|
||||
from anki.notes import Note
|
||||
from anki.rsbridge import RSBridge
|
||||
from anki.sched import Scheduler as V1Scheduler
|
||||
from anki.schedv2 import Scheduler as V2Scheduler
|
||||
from anki.sound import stripSounds
|
||||
|
@ -85,12 +85,12 @@ class _Collection:
|
|||
ls: int
|
||||
conf: Dict[str, Any]
|
||||
_undo: List[Any]
|
||||
rust: RSBridge
|
||||
backend: Backend
|
||||
|
||||
def __init__(
|
||||
self, db: DB, server: bool = False, log: bool = False, rust: RSBridge = None
|
||||
self, db: DB, backend: Backend, server: bool = False, log: bool = False
|
||||
) -> None:
|
||||
self.rust = rust
|
||||
self.backend = backend
|
||||
self._debugLog = log
|
||||
self.db = db
|
||||
self.path = db._path
|
||||
|
|
|
@ -574,7 +574,7 @@ select id from notes where mid = ?)"""
|
|||
field_map = {}
|
||||
for (idx, fld) in enumerate(m["flds"]):
|
||||
field_map[fld["name"]] = idx
|
||||
reqs = self.col.rust.template_requirements(fronts, field_map)
|
||||
reqs = self.col.backend.template_requirements(fronts, field_map)
|
||||
m["req"] = [list(l) for l in reqs]
|
||||
|
||||
def _reqForTemplate(
|
||||
|
|
|
@ -8,11 +8,11 @@ import os
|
|||
import re
|
||||
from typing import Any, Dict, Tuple
|
||||
|
||||
from anki.backend import Backend
|
||||
from anki.collection import _Collection
|
||||
from anki.consts import *
|
||||
from anki.db import DB
|
||||
from anki.lang import _
|
||||
from anki.rsbridge import RSBridge
|
||||
from anki.stdmodels import (
|
||||
addBasicModel,
|
||||
addBasicTypingModel,
|
||||
|
@ -27,8 +27,10 @@ def Collection(
|
|||
path: str, lock: bool = True, server: bool = False, log: bool = False
|
||||
) -> _Collection:
|
||||
"Open a new or existing collection. Path must be unicode."
|
||||
bridge = RSBridge()
|
||||
assert bridge.plus_one(5) == 6
|
||||
backend = Backend()
|
||||
# fixme: this call is temporarily here to ensure the brige is working
|
||||
# on all platforms, and should be removed in a future beta
|
||||
assert backend.plus_one(5) == 6
|
||||
assert path.endswith(".anki2")
|
||||
path = os.path.abspath(path)
|
||||
create = not os.path.exists(path)
|
||||
|
@ -49,7 +51,7 @@ def Collection(
|
|||
db.execute("pragma journal_mode = wal")
|
||||
db.setAutocommit(False)
|
||||
# add db to col and do any remaining upgrades
|
||||
col = _Collection(db, server, log, rust=bridge)
|
||||
col = _Collection(db, backend=backend, server=server, log=log)
|
||||
if ver < SCHEMA_VERSION:
|
||||
_upgrade(col, ver)
|
||||
elif ver > SCHEMA_VERSION:
|
||||
|
|
|
@ -1,25 +1,25 @@
|
|||
syntax = "proto3";
|
||||
|
||||
package proto;
|
||||
package backend_proto;
|
||||
|
||||
message Empty {}
|
||||
|
||||
message BridgeInput {
|
||||
message BackendInput {
|
||||
oneof value {
|
||||
PlusOneIn plus_one = 2;
|
||||
TemplateRequirementsIn template_requirements = 3;
|
||||
}
|
||||
}
|
||||
|
||||
message BridgeOutput {
|
||||
message BackendOutput {
|
||||
oneof value {
|
||||
BridgeError error = 1;
|
||||
BackendError error = 1;
|
||||
PlusOneOut plus_one = 2;
|
||||
TemplateRequirementsOut template_requirements = 3;
|
||||
}
|
||||
}
|
||||
|
||||
message BridgeError {
|
||||
message BackendError {
|
||||
oneof value {
|
||||
InvalidInputError invalid_input = 1;
|
||||
TemplateParseError template_parse = 2;
|
|
@ -429,7 +429,7 @@ dependencies = [
|
|||
]
|
||||
|
||||
[[package]]
|
||||
name = "pybridge"
|
||||
name = "pymod"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"ankirs",
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
[workspace]
|
||||
members = ["ankirs", "pybridge"]
|
||||
members = ["ankirs", "pymod"]
|
||||
|
||||
[profile.release]
|
||||
lto = true
|
||||
|
|
|
@ -3,5 +3,5 @@ use prost_build;
|
|||
fn main() {
|
||||
// avoid default OUT_DIR for now, for code completion
|
||||
std::env::set_var("OUT_DIR", "src");
|
||||
prost_build::compile_protos(&["../../proto/bridge.proto"], &["../../proto/"]).unwrap();
|
||||
prost_build::compile_protos(&["../../proto/backend.proto"], &["../../proto/"]).unwrap();
|
||||
}
|
||||
|
|
|
@ -1,22 +1,22 @@
|
|||
use crate::backend_proto as pt;
|
||||
use crate::backend_proto::backend_input::Value;
|
||||
use crate::err::{AnkiError, Result};
|
||||
use crate::proto as pt;
|
||||
use crate::proto::bridge_input::Value;
|
||||
use crate::template::{FieldMap, FieldRequirements, ParsedTemplate};
|
||||
use prost::Message;
|
||||
use std::collections::HashSet;
|
||||
|
||||
pub struct Bridge {}
|
||||
pub struct Backend {}
|
||||
|
||||
impl Default for Bridge {
|
||||
impl Default for Backend {
|
||||
fn default() -> Self {
|
||||
Bridge {}
|
||||
Backend {}
|
||||
}
|
||||
}
|
||||
|
||||
/// Convert an Anki error to a protobuf error.
|
||||
impl std::convert::From<AnkiError> for pt::BridgeError {
|
||||
impl std::convert::From<AnkiError> for pt::BackendError {
|
||||
fn from(err: AnkiError) -> Self {
|
||||
use pt::bridge_error::Value as V;
|
||||
use pt::backend_error::Value as V;
|
||||
let value = match err {
|
||||
AnkiError::InvalidInput { info } => V::InvalidInput(pt::InvalidInputError { info }),
|
||||
AnkiError::TemplateParseError { info } => {
|
||||
|
@ -24,32 +24,32 @@ impl std::convert::From<AnkiError> for pt::BridgeError {
|
|||
}
|
||||
};
|
||||
|
||||
pt::BridgeError { value: Some(value) }
|
||||
pt::BackendError { value: Some(value) }
|
||||
}
|
||||
}
|
||||
|
||||
// Convert an Anki error to a protobuf output.
|
||||
impl std::convert::From<AnkiError> for pt::bridge_output::Value {
|
||||
impl std::convert::From<AnkiError> for pt::backend_output::Value {
|
||||
fn from(err: AnkiError) -> Self {
|
||||
pt::bridge_output::Value::Error(err.into())
|
||||
pt::backend_output::Value::Error(err.into())
|
||||
}
|
||||
}
|
||||
|
||||
impl Bridge {
|
||||
pub fn new() -> Bridge {
|
||||
Bridge::default()
|
||||
impl Backend {
|
||||
pub fn new() -> Backend {
|
||||
Backend::default()
|
||||
}
|
||||
|
||||
/// Decode a request, process it, and return the encoded result.
|
||||
pub fn run_command_bytes(&mut self, req: &[u8]) -> Vec<u8> {
|
||||
let mut buf = vec![];
|
||||
|
||||
let req = match pt::BridgeInput::decode(req) {
|
||||
let req = match pt::BackendInput::decode(req) {
|
||||
Ok(req) => req,
|
||||
Err(_e) => {
|
||||
// unable to decode
|
||||
let err = AnkiError::invalid_input("couldn't decode bridge request");
|
||||
let output = pt::BridgeOutput {
|
||||
let err = AnkiError::invalid_input("couldn't decode backend request");
|
||||
let output = pt::BackendOutput {
|
||||
value: Some(err.into()),
|
||||
};
|
||||
output.encode(&mut buf).expect("encode failed");
|
||||
|
@ -62,21 +62,24 @@ impl Bridge {
|
|||
buf
|
||||
}
|
||||
|
||||
fn run_command(&self, input: pt::BridgeInput) -> pt::BridgeOutput {
|
||||
fn run_command(&self, input: pt::BackendInput) -> pt::BackendOutput {
|
||||
let oval = if let Some(ival) = input.value {
|
||||
match self.run_command_inner(ival) {
|
||||
Ok(output) => output,
|
||||
Err(err) => err.into(),
|
||||
}
|
||||
} else {
|
||||
AnkiError::invalid_input("unrecognized bridge input value").into()
|
||||
AnkiError::invalid_input("unrecognized backend input value").into()
|
||||
};
|
||||
|
||||
pt::BridgeOutput { value: Some(oval) }
|
||||
pt::BackendOutput { value: Some(oval) }
|
||||
}
|
||||
|
||||
fn run_command_inner(&self, ival: pt::bridge_input::Value) -> Result<pt::bridge_output::Value> {
|
||||
use pt::bridge_output::Value as OValue;
|
||||
fn run_command_inner(
|
||||
&self,
|
||||
ival: pt::backend_input::Value,
|
||||
) -> Result<pt::backend_output::Value> {
|
||||
use pt::backend_output::Value as OValue;
|
||||
Ok(match ival {
|
||||
Value::TemplateRequirements(input) => {
|
||||
OValue::TemplateRequirements(self.template_requirements(input)?)
|
||||
|
@ -100,7 +103,7 @@ impl Bridge {
|
|||
.map(|(name, ord)| (name.as_str(), *ord as u16))
|
||||
.collect();
|
||||
// map each provided template into a requirements list
|
||||
use crate::proto::template_requirement::Value;
|
||||
use crate::backend_proto::template_requirement::Value;
|
||||
let all_reqs = input
|
||||
.template_front
|
||||
.into_iter()
|
|
@ -1,5 +1,5 @@
|
|||
mod proto;
|
||||
mod backend_proto;
|
||||
|
||||
pub mod bridge;
|
||||
pub mod backend;
|
||||
pub mod err;
|
||||
pub mod template;
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
[package]
|
||||
name = "pybridge"
|
||||
name = "pymod"
|
||||
version = "0.1.0"
|
||||
edition = "2018"
|
||||
authors = ["Ankitects Pty Ltd and contributors"]
|
|
@ -1,25 +1,25 @@
|
|||
use ankirs::bridge::Bridge as RustBridge;
|
||||
use ankirs::backend::Backend as RustBackend;
|
||||
use pyo3::prelude::*;
|
||||
use pyo3::types::PyBytes;
|
||||
|
||||
#[pyclass]
|
||||
struct Bridge {
|
||||
bridge: RustBridge,
|
||||
struct Backend {
|
||||
backend: RustBackend,
|
||||
}
|
||||
|
||||
#[pymethods]
|
||||
impl Bridge {
|
||||
impl Backend {
|
||||
#[new]
|
||||
fn init(obj: &PyRawObject) {
|
||||
obj.init({
|
||||
Bridge {
|
||||
bridge: Default::default(),
|
||||
Backend {
|
||||
backend: Default::default(),
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
fn command(&mut self, py: Python, input: &PyBytes) -> PyResult<PyObject> {
|
||||
let out_bytes = self.bridge.run_command_bytes(input.as_bytes());
|
||||
let out_bytes = self.backend.run_command_bytes(input.as_bytes());
|
||||
let out_obj = PyBytes::new(py, &out_bytes);
|
||||
Ok(out_obj.into())
|
||||
}
|
||||
|
@ -27,7 +27,7 @@ impl Bridge {
|
|||
|
||||
#[pymodule]
|
||||
fn _ankirs(_py: Python, m: &PyModule) -> PyResult<()> {
|
||||
m.add_class::<Bridge>()?;
|
||||
m.add_class::<Backend>()?;
|
||||
|
||||
Ok(())
|
||||
}
|
|
@ -1 +1 @@
|
|||
ignore = ["proto.rs"]
|
||||
ignore = ["backend_proto.rs"]
|
||||
|
|
Loading…
Reference in New Issue