mirror of
https://github.com/ankitects/anki.git
synced 2025-09-18 22:12:21 -04:00
simplify errors
- use a flat enum instead of oneof messages, most of which were empty - tidy up the Python side
This commit is contained in:
parent
fe6888f9a4
commit
41c5a25dc8
9 changed files with 169 additions and 187 deletions
|
@ -9,7 +9,8 @@ ignored-classes=
|
||||||
AnswerCardIn,
|
AnswerCardIn,
|
||||||
UnburyCardsInCurrentDeckIn,
|
UnburyCardsInCurrentDeckIn,
|
||||||
BuryOrSuspendCardsIn,
|
BuryOrSuspendCardsIn,
|
||||||
NoteIsDuplicateOrEmptyOut
|
NoteIsDuplicateOrEmptyOut,
|
||||||
|
BackendError
|
||||||
|
|
||||||
[REPORTS]
|
[REPORTS]
|
||||||
output-format=colorized
|
output-format=colorized
|
||||||
|
|
|
@ -3,24 +3,39 @@
|
||||||
|
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
import os
|
|
||||||
import sys
|
import sys
|
||||||
import traceback
|
import traceback
|
||||||
from typing import Any, Dict, List, Optional, Sequence, Tuple, Union
|
from typing import Any, Dict, List, Optional, Sequence, Tuple, Union
|
||||||
from weakref import ref
|
from weakref import ref
|
||||||
|
|
||||||
|
from markdown import markdown
|
||||||
|
|
||||||
import anki.buildinfo
|
import anki.buildinfo
|
||||||
from anki._backend.generated import RustBackendGenerated
|
from anki._backend.generated import RustBackendGenerated
|
||||||
from anki.dbproxy import Row as DBRow
|
from anki.dbproxy import Row as DBRow
|
||||||
from anki.dbproxy import ValueForDB
|
from anki.dbproxy import ValueForDB
|
||||||
from anki.errors import backend_exception_to_pylib
|
|
||||||
from anki.utils import from_json_bytes, to_json_bytes
|
from anki.utils import from_json_bytes, to_json_bytes
|
||||||
|
|
||||||
|
from ..errors import (
|
||||||
|
BackendIOError,
|
||||||
|
DBError,
|
||||||
|
ExistsError,
|
||||||
|
FilteredDeckError,
|
||||||
|
Interrupted,
|
||||||
|
InvalidInput,
|
||||||
|
LocalizedError,
|
||||||
|
NetworkError,
|
||||||
|
NotFoundError,
|
||||||
|
SearchError,
|
||||||
|
SyncError,
|
||||||
|
SyncErrorKind,
|
||||||
|
TemplateError,
|
||||||
|
UndoEmpty,
|
||||||
|
)
|
||||||
from . import backend_pb2 as pb
|
from . import backend_pb2 as pb
|
||||||
from . import rsbridge
|
from . import rsbridge
|
||||||
from .fluent import GeneratedTranslations, LegacyTranslationEnum
|
from .fluent import GeneratedTranslations, LegacyTranslationEnum
|
||||||
|
|
||||||
# pylint: disable=c-extension-no-member
|
|
||||||
assert rsbridge.buildhash() == anki.buildinfo.buildhash
|
assert rsbridge.buildhash() == anki.buildinfo.buildhash
|
||||||
|
|
||||||
|
|
||||||
|
@ -147,3 +162,57 @@ class Translations(GeneratedTranslations):
|
||||||
return self.backend().translate(
|
return self.backend().translate(
|
||||||
module_index=module, message_index=message, **args
|
module_index=module, message_index=message, **args
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def backend_exception_to_pylib(err: pb.BackendError) -> Exception:
|
||||||
|
kind = pb.BackendError
|
||||||
|
val = err.kind
|
||||||
|
if val == kind.INTERRUPTED:
|
||||||
|
return Interrupted()
|
||||||
|
|
||||||
|
elif val == kind.NETWORK_ERROR:
|
||||||
|
return NetworkError(err.localized)
|
||||||
|
|
||||||
|
elif val == kind.SYNC_AUTH_ERROR:
|
||||||
|
return SyncError(err.localized, SyncErrorKind.AUTH)
|
||||||
|
|
||||||
|
elif val == kind.SYNC_OTHER_ERROR:
|
||||||
|
return SyncError(err.localized, SyncErrorKind.OTHER)
|
||||||
|
|
||||||
|
elif val == kind.IO_ERROR:
|
||||||
|
return BackendIOError(err.localized)
|
||||||
|
|
||||||
|
elif val == kind.DB_ERROR:
|
||||||
|
return DBError(err.localized)
|
||||||
|
|
||||||
|
elif val == kind.TEMPLATE_PARSE:
|
||||||
|
return TemplateError(err.localized)
|
||||||
|
|
||||||
|
elif val == kind.INVALID_INPUT:
|
||||||
|
return InvalidInput(err.localized)
|
||||||
|
|
||||||
|
elif val == kind.JSON_ERROR:
|
||||||
|
return LocalizedError(err.localized)
|
||||||
|
|
||||||
|
elif val == kind.NOT_FOUND_ERROR:
|
||||||
|
return NotFoundError()
|
||||||
|
|
||||||
|
elif val == kind.EXISTS:
|
||||||
|
return ExistsError()
|
||||||
|
|
||||||
|
elif val == kind.FILTERED_DECK_ERROR:
|
||||||
|
return FilteredDeckError(err.localized)
|
||||||
|
|
||||||
|
elif val == kind.PROTO_ERROR:
|
||||||
|
return LocalizedError(err.localized)
|
||||||
|
|
||||||
|
elif val == kind.SEARCH_ERROR:
|
||||||
|
return SearchError(markdown(err.localized))
|
||||||
|
|
||||||
|
elif val == kind.UNDO_EMPTY:
|
||||||
|
return UndoEmpty()
|
||||||
|
|
||||||
|
else:
|
||||||
|
# sadly we can't do exhaustiveness checking on protobuf enums
|
||||||
|
# assert_exhaustive(val)
|
||||||
|
return LocalizedError(err.localized)
|
||||||
|
|
|
@ -40,7 +40,7 @@ from anki.config import Config, ConfigManager
|
||||||
from anki.consts import *
|
from anki.consts import *
|
||||||
from anki.dbproxy import DBProxy
|
from anki.dbproxy import DBProxy
|
||||||
from anki.decks import DeckId, DeckManager
|
from anki.decks import DeckId, DeckManager
|
||||||
from anki.errors import AnkiError, DBError
|
from anki.errors import AbortSchemaModification, DBError
|
||||||
from anki.lang import FormatTimeSpan
|
from anki.lang import FormatTimeSpan
|
||||||
from anki.media import MediaManager, media_paths_from_col_path
|
from anki.media import MediaManager, media_paths_from_col_path
|
||||||
from anki.models import ModelManager, NotetypeDict, NotetypeId
|
from anki.models import ModelManager, NotetypeDict, NotetypeId
|
||||||
|
@ -290,7 +290,7 @@ class Collection:
|
||||||
"Mark schema modified. Call this first so user can abort if necessary."
|
"Mark schema modified. Call this first so user can abort if necessary."
|
||||||
if not self.schemaChanged():
|
if not self.schemaChanged():
|
||||||
if check and not hooks.schema_will_change(proceed=True):
|
if check and not hooks.schema_will_change(proceed=True):
|
||||||
raise AnkiError("abortSchemaMod")
|
raise AbortSchemaModification()
|
||||||
self.db.execute("update col set scm=?", intTime(1000))
|
self.db.execute("update col set scm=?", intTime(1000))
|
||||||
self.save()
|
self.save()
|
||||||
|
|
||||||
|
|
|
@ -3,41 +3,48 @@
|
||||||
|
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
from markdown import markdown
|
from enum import Enum
|
||||||
|
|
||||||
import anki._backend.backend_pb2 as _pb
|
|
||||||
|
|
||||||
from anki.types import assert_exhaustive
|
|
||||||
|
|
||||||
|
|
||||||
class StringError(Exception):
|
class LocalizedError(Exception):
|
||||||
|
"An error with a localized description."
|
||||||
|
|
||||||
|
def __init__(self, localized: str) -> None:
|
||||||
|
self._localized = localized
|
||||||
|
super().__init__()
|
||||||
|
|
||||||
def __str__(self) -> str:
|
def __str__(self) -> str:
|
||||||
return self.args[0] # pylint: disable=unsubscriptable-object
|
return self._localized
|
||||||
|
|
||||||
|
|
||||||
class Interrupted(Exception):
|
class Interrupted(Exception):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
class NetworkError(StringError):
|
class NetworkError(LocalizedError):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
class SyncError(StringError):
|
class SyncErrorKind(Enum):
|
||||||
# pylint: disable=no-member
|
AUTH = 1
|
||||||
def is_auth_error(self) -> bool:
|
OTHER = 2
|
||||||
return self.args[1] == _pb.SyncError.SyncErrorKind.AUTH_FAILED
|
|
||||||
|
|
||||||
|
|
||||||
class IOError(StringError):
|
class SyncError(LocalizedError):
|
||||||
|
def __init__(self, localized: str, kind: SyncErrorKind):
|
||||||
|
self.kind = kind
|
||||||
|
super().__init__(localized)
|
||||||
|
|
||||||
|
|
||||||
|
class BackendIOError(LocalizedError):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
class DBError(StringError):
|
class DBError(LocalizedError):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
class TemplateError(StringError):
|
class TemplateError(LocalizedError):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
@ -53,67 +60,22 @@ class UndoEmpty(Exception):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
class DeckRenameError(Exception):
|
class FilteredDeckError(LocalizedError):
|
||||||
"""Legacy error, use FilteredDeckError instead."""
|
|
||||||
|
|
||||||
def __init__(self, description: str, *args: object) -> None:
|
|
||||||
super().__init__(description, *args)
|
|
||||||
self.description = description
|
|
||||||
|
|
||||||
|
|
||||||
class FilteredDeckError(StringError, DeckRenameError):
|
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
class InvalidInput(StringError):
|
class InvalidInput(LocalizedError):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
class SearchError(StringError):
|
class SearchError(LocalizedError):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
def backend_exception_to_pylib(err: _pb.BackendError) -> Exception:
|
class AbortSchemaModification(Exception):
|
||||||
val = err.WhichOneof("value")
|
pass
|
||||||
if val == "interrupted":
|
|
||||||
return Interrupted()
|
|
||||||
elif val == "network_error":
|
|
||||||
return NetworkError(err.localized, err.network_error.kind)
|
|
||||||
elif val == "sync_error":
|
|
||||||
return SyncError(err.localized, err.sync_error.kind)
|
|
||||||
elif val == "io_error":
|
|
||||||
return IOError(err.localized)
|
|
||||||
elif val == "db_error":
|
|
||||||
return DBError(err.localized)
|
|
||||||
elif val == "template_parse":
|
|
||||||
return TemplateError(err.localized)
|
|
||||||
elif val == "invalid_input":
|
|
||||||
return InvalidInput(err.localized)
|
|
||||||
elif val == "json_error":
|
|
||||||
return StringError(err.localized)
|
|
||||||
elif val == "not_found_error":
|
|
||||||
return NotFoundError()
|
|
||||||
elif val == "exists":
|
|
||||||
return ExistsError()
|
|
||||||
elif val == "filtered_deck_error":
|
|
||||||
return FilteredDeckError(err.localized)
|
|
||||||
elif val == "proto_error":
|
|
||||||
return StringError(err.localized)
|
|
||||||
elif val == "search_error":
|
|
||||||
return SearchError(markdown(err.localized))
|
|
||||||
elif val == "undo_empty":
|
|
||||||
return UndoEmpty()
|
|
||||||
else:
|
|
||||||
assert_exhaustive(val)
|
|
||||||
return StringError(err.localized)
|
|
||||||
|
|
||||||
|
|
||||||
# FIXME: this is only used with "abortSchemaMod", but currently some
|
# legacy
|
||||||
# add-ons depend on it
|
DeckRenameError = FilteredDeckError
|
||||||
class AnkiError(Exception):
|
AnkiError = AbortSchemaModification
|
||||||
def __init__(self, type: str) -> None:
|
|
||||||
super().__init__()
|
|
||||||
self.type = type
|
|
||||||
|
|
||||||
def __str__(self) -> str:
|
|
||||||
return self.type
|
|
||||||
|
|
|
@ -71,7 +71,7 @@ class ErrorHandler(QObject):
|
||||||
error = html.escape(self.pool)
|
error = html.escape(self.pool)
|
||||||
self.pool = ""
|
self.pool = ""
|
||||||
self.mw.progress.clear()
|
self.mw.progress.clear()
|
||||||
if "abortSchemaMod" in error:
|
if "AbortSchemaModification" in error:
|
||||||
return
|
return
|
||||||
if "DeprecationWarning" in error:
|
if "DeprecationWarning" in error:
|
||||||
return
|
return
|
||||||
|
|
|
@ -9,7 +9,7 @@ from concurrent.futures import Future
|
||||||
from typing import Callable, Tuple
|
from typing import Callable, Tuple
|
||||||
|
|
||||||
import aqt
|
import aqt
|
||||||
from anki.errors import Interrupted, SyncError
|
from anki.errors import Interrupted, SyncError, SyncErrorKind
|
||||||
from anki.lang import without_unicode_isolation
|
from anki.lang import without_unicode_isolation
|
||||||
from anki.sync import SyncOutput, SyncStatus
|
from anki.sync import SyncOutput, SyncStatus
|
||||||
from anki.utils import platDesc
|
from anki.utils import platDesc
|
||||||
|
@ -62,7 +62,7 @@ def get_sync_status(
|
||||||
|
|
||||||
def handle_sync_error(mw: aqt.main.AnkiQt, err: Exception) -> None:
|
def handle_sync_error(mw: aqt.main.AnkiQt, err: Exception) -> None:
|
||||||
if isinstance(err, SyncError):
|
if isinstance(err, SyncError):
|
||||||
if err.is_auth_error():
|
if err.kind is SyncErrorKind.AUTH:
|
||||||
mw.pm.clear_sync_auth()
|
mw.pm.clear_sync_auth()
|
||||||
elif isinstance(err, Interrupted):
|
elif isinstance(err, Interrupted):
|
||||||
# no message to show
|
# no message to show
|
||||||
|
@ -247,7 +247,7 @@ def sync_login(
|
||||||
try:
|
try:
|
||||||
auth = fut.result()
|
auth = fut.result()
|
||||||
except SyncError as e:
|
except SyncError as e:
|
||||||
if e.is_auth_error():
|
if e.kind is SyncErrorKind.AUTH:
|
||||||
showWarning(str(e))
|
showWarning(str(e))
|
||||||
sync_login(mw, on_success, username, password)
|
sync_login(mw, on_success, username, password)
|
||||||
else:
|
else:
|
||||||
|
|
|
@ -553,53 +553,28 @@ message I18nBackendInit {
|
||||||
///////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////
|
||||||
|
|
||||||
message BackendError {
|
message BackendError {
|
||||||
|
enum Kind {
|
||||||
|
INVALID_INPUT = 0;
|
||||||
|
UNDO_EMPTY = 1;
|
||||||
|
INTERRUPTED = 2;
|
||||||
|
TEMPLATE_PARSE = 3;
|
||||||
|
IO_ERROR = 4;
|
||||||
|
DB_ERROR = 5;
|
||||||
|
NETWORK_ERROR = 6;
|
||||||
|
SYNC_AUTH_ERROR = 7;
|
||||||
|
SYNC_OTHER_ERROR = 8;
|
||||||
|
JSON_ERROR = 9;
|
||||||
|
PROTO_ERROR = 10;
|
||||||
|
NOT_FOUND_ERROR = 11;
|
||||||
|
EXISTS = 12;
|
||||||
|
FILTERED_DECK_ERROR = 13;
|
||||||
|
SEARCH_ERROR = 14;
|
||||||
|
}
|
||||||
|
|
||||||
// localized error description suitable for displaying to the user
|
// localized error description suitable for displaying to the user
|
||||||
string localized = 1;
|
string localized = 1;
|
||||||
// error specifics
|
// the error subtype
|
||||||
oneof value {
|
Kind kind = 2;
|
||||||
Empty invalid_input = 2;
|
|
||||||
Empty template_parse = 3;
|
|
||||||
Empty io_error = 4;
|
|
||||||
Empty db_error = 5;
|
|
||||||
NetworkError network_error = 6;
|
|
||||||
SyncError sync_error = 7;
|
|
||||||
// user interrupted operation
|
|
||||||
Empty interrupted = 8;
|
|
||||||
string json_error = 9;
|
|
||||||
string proto_error = 10;
|
|
||||||
Empty not_found_error = 11;
|
|
||||||
Empty exists = 12;
|
|
||||||
Empty filtered_deck_error = 13;
|
|
||||||
Empty search_error = 14;
|
|
||||||
Empty undo_empty = 15;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
message NetworkError {
|
|
||||||
enum NetworkErrorKind {
|
|
||||||
OTHER = 0;
|
|
||||||
OFFLINE = 1;
|
|
||||||
TIMEOUT = 2;
|
|
||||||
PROXY_AUTH = 3;
|
|
||||||
}
|
|
||||||
NetworkErrorKind kind = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
message SyncError {
|
|
||||||
enum SyncErrorKind {
|
|
||||||
OTHER = 0;
|
|
||||||
CONFLICT = 1;
|
|
||||||
SERVER_ERROR = 2;
|
|
||||||
CLIENT_TOO_OLD = 3;
|
|
||||||
AUTH_FAILED = 4;
|
|
||||||
SERVER_MESSAGE = 5;
|
|
||||||
MEDIA_CHECK_REQUIRED = 6;
|
|
||||||
RESYNC_REQUIRED = 7;
|
|
||||||
CLOCK_INCORRECT = 8;
|
|
||||||
DATABASE_CHECK_REQUIRED = 9;
|
|
||||||
SYNC_NOT_STARTED = 10;
|
|
||||||
}
|
|
||||||
SyncErrorKind kind = 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Progress
|
// Progress
|
||||||
|
|
|
@ -3,72 +3,49 @@
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
backend_proto as pb,
|
backend_proto as pb,
|
||||||
error::{AnkiError, NetworkErrorKind, SyncErrorKind},
|
error::{AnkiError, SyncErrorKind},
|
||||||
prelude::*,
|
prelude::*,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Convert an Anki error to a protobuf error.
|
use pb::backend_error::Kind;
|
||||||
pub(super) fn anki_error_to_proto_error(err: AnkiError, tr: &I18n) -> pb::BackendError {
|
|
||||||
use pb::backend_error::Value as V;
|
impl AnkiError {
|
||||||
let localized = err.localized_description(tr);
|
pub(super) fn into_protobuf(self, tr: &I18n) -> pb::BackendError {
|
||||||
let value = match err {
|
let localized = self.localized_description(tr);
|
||||||
AnkiError::InvalidInput { .. } => V::InvalidInput(pb::Empty {}),
|
let kind = match self {
|
||||||
AnkiError::TemplateError { .. } => V::TemplateParse(pb::Empty {}),
|
AnkiError::InvalidInput(_) => Kind::InvalidInput,
|
||||||
AnkiError::IoError { .. } => V::IoError(pb::Empty {}),
|
AnkiError::TemplateError(_) => Kind::TemplateParse,
|
||||||
AnkiError::DbError { .. } => V::DbError(pb::Empty {}),
|
AnkiError::IoError(_) => Kind::IoError,
|
||||||
AnkiError::NetworkError(err) => V::NetworkError(pb::NetworkError {
|
AnkiError::DbError(_) => Kind::DbError,
|
||||||
kind: err.kind.into(),
|
AnkiError::NetworkError(_) => Kind::NetworkError,
|
||||||
}),
|
AnkiError::SyncError(err) => err.kind.into(),
|
||||||
AnkiError::SyncError(err) => V::SyncError(pb::SyncError {
|
AnkiError::Interrupted => Kind::Interrupted,
|
||||||
kind: err.kind.into(),
|
AnkiError::CollectionNotOpen => Kind::InvalidInput,
|
||||||
}),
|
AnkiError::CollectionAlreadyOpen => Kind::InvalidInput,
|
||||||
AnkiError::Interrupted => V::Interrupted(pb::Empty {}),
|
AnkiError::JsonError(_) => Kind::JsonError,
|
||||||
AnkiError::CollectionNotOpen => V::InvalidInput(pb::Empty {}),
|
AnkiError::ProtoError(_) => Kind::ProtoError,
|
||||||
AnkiError::CollectionAlreadyOpen => V::InvalidInput(pb::Empty {}),
|
AnkiError::NotFound => Kind::NotFoundError,
|
||||||
AnkiError::JsonError(info) => V::JsonError(info),
|
AnkiError::Existing => Kind::Exists,
|
||||||
AnkiError::ProtoError(info) => V::ProtoError(info),
|
AnkiError::FilteredDeckError(_) => Kind::FilteredDeckError,
|
||||||
AnkiError::NotFound => V::NotFoundError(pb::Empty {}),
|
AnkiError::SearchError(_) => Kind::SearchError,
|
||||||
AnkiError::Existing => V::Exists(pb::Empty {}),
|
AnkiError::TemplateSaveError(_) => Kind::TemplateParse,
|
||||||
AnkiError::FilteredDeckError(_) => V::FilteredDeckError(pb::Empty {}),
|
AnkiError::ParseNumError => Kind::InvalidInput,
|
||||||
AnkiError::SearchError(_) => V::SearchError(pb::Empty {}),
|
AnkiError::InvalidRegex(_) => Kind::InvalidInput,
|
||||||
AnkiError::TemplateSaveError { .. } => V::TemplateParse(pb::Empty {}),
|
AnkiError::UndoEmpty => Kind::UndoEmpty,
|
||||||
AnkiError::ParseNumError => V::InvalidInput(pb::Empty {}),
|
|
||||||
AnkiError::InvalidRegex(_) => V::InvalidInput(pb::Empty {}),
|
|
||||||
AnkiError::UndoEmpty => V::UndoEmpty(pb::Empty {}),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
pb::BackendError {
|
pb::BackendError {
|
||||||
value: Some(value),
|
kind: kind as i32,
|
||||||
localized,
|
localized,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl std::convert::From<NetworkErrorKind> for i32 {
|
|
||||||
fn from(e: NetworkErrorKind) -> Self {
|
|
||||||
use pb::network_error::NetworkErrorKind as V;
|
|
||||||
(match e {
|
|
||||||
NetworkErrorKind::Offline => V::Offline,
|
|
||||||
NetworkErrorKind::Timeout => V::Timeout,
|
|
||||||
NetworkErrorKind::ProxyAuth => V::ProxyAuth,
|
|
||||||
NetworkErrorKind::Other => V::Other,
|
|
||||||
}) as i32
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl std::convert::From<SyncErrorKind> for i32 {
|
impl From<SyncErrorKind> for Kind {
|
||||||
fn from(e: SyncErrorKind) -> Self {
|
fn from(err: SyncErrorKind) -> Self {
|
||||||
use pb::sync_error::SyncErrorKind as V;
|
match err {
|
||||||
(match e {
|
SyncErrorKind::AuthFailed => Kind::SyncAuthError,
|
||||||
SyncErrorKind::Conflict => V::Conflict,
|
_ => Kind::SyncOtherError,
|
||||||
SyncErrorKind::ServerError => V::ServerError,
|
}
|
||||||
SyncErrorKind::ClientTooOld => V::ClientTooOld,
|
|
||||||
SyncErrorKind::AuthFailed => V::AuthFailed,
|
|
||||||
SyncErrorKind::ServerMessage => V::ServerMessage,
|
|
||||||
SyncErrorKind::ResyncRequired => V::ResyncRequired,
|
|
||||||
SyncErrorKind::DatabaseCheckRequired => V::DatabaseCheckRequired,
|
|
||||||
SyncErrorKind::Other => V::Other,
|
|
||||||
SyncErrorKind::ClockIncorrect => V::ClockIncorrect,
|
|
||||||
SyncErrorKind::SyncNotStarted => V::SyncNotStarted,
|
|
||||||
}) as i32
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -61,8 +61,6 @@ use std::{
|
||||||
};
|
};
|
||||||
use tokio::runtime::{self, Runtime};
|
use tokio::runtime::{self, Runtime};
|
||||||
|
|
||||||
use self::error::anki_error_to_proto_error;
|
|
||||||
|
|
||||||
pub struct Backend {
|
pub struct Backend {
|
||||||
col: Arc<Mutex<Option<Collection>>>,
|
col: Arc<Mutex<Option<Collection>>>,
|
||||||
tr: I18n,
|
tr: I18n,
|
||||||
|
@ -137,7 +135,7 @@ impl Backend {
|
||||||
pb::ServiceIndex::Cards => CardsService::run_method(self, method, input),
|
pb::ServiceIndex::Cards => CardsService::run_method(self, method, input),
|
||||||
})
|
})
|
||||||
.map_err(|err| {
|
.map_err(|err| {
|
||||||
let backend_err = anki_error_to_proto_error(err, &self.tr);
|
let backend_err = err.into_protobuf(&self.tr);
|
||||||
let mut bytes = Vec::new();
|
let mut bytes = Vec::new();
|
||||||
backend_err.encode(&mut bytes).unwrap();
|
backend_err.encode(&mut bytes).unwrap();
|
||||||
bytes
|
bytes
|
||||||
|
@ -146,7 +144,7 @@ impl Backend {
|
||||||
|
|
||||||
pub fn run_db_command_bytes(&self, input: &[u8]) -> std::result::Result<Vec<u8>, Vec<u8>> {
|
pub fn run_db_command_bytes(&self, input: &[u8]) -> std::result::Result<Vec<u8>, Vec<u8>> {
|
||||||
self.db_command(input).map_err(|err| {
|
self.db_command(input).map_err(|err| {
|
||||||
let backend_err = anki_error_to_proto_error(err, &self.tr);
|
let backend_err = err.into_protobuf(&self.tr);
|
||||||
let mut bytes = Vec::new();
|
let mut bytes = Vec::new();
|
||||||
backend_err.encode(&mut bytes).unwrap();
|
backend_err.encode(&mut bytes).unwrap();
|
||||||
bytes
|
bytes
|
||||||
|
|
Loading…
Reference in a new issue