mirror of
https://github.com/ankitects/anki.git
synced 2025-11-30 16:37:12 -05:00
* Add crate snafu * Replace all inline structs in AnkiError * Derive Snafu on AnkiError * Use snafu for card type errors * Use snafu whatever error for InvalidInput * Use snafu for NotFoundError and improve message * Use snafu for FileIoError to attach context Remove IoError. Add some context-attaching helpers to replace code returning bare io::Errors. * Add more context-attaching io helpers * Add message, context and backtrace to new snafus * Utilize error context and backtrace on frontend * Rename LocalizedError -> BackendError. * Remove DocumentedError. * Have all backend exceptions inherit BackendError. * Rename localized(_description) -> message * Remove accidentally committed experimental trait * invalid_input_context -> ok_or_invalid * ensure_valid_input! -> require! * Always return `Err` from `invalid_input!` Instead of a Result to unwrap, the macro accepts a source error now. * new_tempfile_in_parent -> new_tempfile_in_parent_of * ok_or_not_found -> or_not_found * ok_or_invalid -> or_invalid * Add crate convert_case * Use unqualified lowercase type name * Remove uses of snafu::ensure * Allow public construction of InvalidInputErrors (dae) Needed to port the AnkiDroid changes. * Make into_protobuf() public (dae) Also required for AnkiDroid. Not sure why it worked previously - possible bug in older Rust version?
124 lines
4.2 KiB
Rust
124 lines
4.2 KiB
Rust
// Copyright: Ankitects Pty Ltd and contributors
|
|
// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
|
|
|
use std::path::PathBuf;
|
|
|
|
use serde::{Deserialize, Serialize};
|
|
|
|
use super::{Chunk, Graves, SanityCheckCounts, UnchunkedChanges};
|
|
use crate::{io::read_file, pb::sync_server_method_request::Method, prelude::*};
|
|
#[derive(Serialize, Deserialize, Debug)]
|
|
#[serde(rename_all = "camelCase")]
|
|
pub enum SyncRequest {
|
|
HostKey(HostKeyRequest),
|
|
Meta(MetaRequest),
|
|
Start(StartRequest),
|
|
ApplyGraves(ApplyGravesRequest),
|
|
ApplyChanges(ApplyChangesRequest),
|
|
Chunk,
|
|
ApplyChunk(ApplyChunkRequest),
|
|
#[serde(rename = "sanityCheck2")]
|
|
SanityCheck(SanityCheckRequest),
|
|
Finish,
|
|
Abort,
|
|
#[serde(rename = "upload")]
|
|
FullUpload(PathBuf),
|
|
#[serde(rename = "download")]
|
|
FullDownload,
|
|
}
|
|
|
|
impl SyncRequest {
|
|
/// Return method name and payload bytes.
|
|
pub(crate) fn into_method_and_data(self) -> Result<(&'static str, Vec<u8>)> {
|
|
use serde_json::to_vec;
|
|
Ok(match self {
|
|
SyncRequest::HostKey(v) => ("hostKey", to_vec(&v)?),
|
|
SyncRequest::Meta(v) => ("meta", to_vec(&v)?),
|
|
SyncRequest::Start(v) => ("start", to_vec(&v)?),
|
|
SyncRequest::ApplyGraves(v) => ("applyGraves", to_vec(&v)?),
|
|
SyncRequest::ApplyChanges(v) => ("applyChanges", to_vec(&v)?),
|
|
SyncRequest::Chunk => ("chunk", b"{}".to_vec()),
|
|
SyncRequest::ApplyChunk(v) => ("applyChunk", to_vec(&v)?),
|
|
SyncRequest::SanityCheck(v) => ("sanityCheck2", to_vec(&v)?),
|
|
SyncRequest::Finish => ("finish", b"{}".to_vec()),
|
|
SyncRequest::Abort => ("abort", b"{}".to_vec()),
|
|
SyncRequest::FullUpload(v) => {
|
|
// fixme: stream in the data instead, in a different call
|
|
("upload", read_file(&v)?)
|
|
}
|
|
SyncRequest::FullDownload => ("download", b"{}".to_vec()),
|
|
})
|
|
}
|
|
|
|
pub(crate) fn from_method_and_data(method: Method, data: Vec<u8>) -> Result<Self> {
|
|
use serde_json::from_slice;
|
|
Ok(match method {
|
|
Method::HostKey => SyncRequest::HostKey(from_slice(&data)?),
|
|
Method::Meta => SyncRequest::Meta(from_slice(&data)?),
|
|
Method::Start => SyncRequest::Start(from_slice(&data)?),
|
|
Method::ApplyGraves => SyncRequest::ApplyGraves(from_slice(&data)?),
|
|
Method::ApplyChanges => SyncRequest::ApplyChanges(from_slice(&data)?),
|
|
Method::Chunk => SyncRequest::Chunk,
|
|
Method::ApplyChunk => SyncRequest::ApplyChunk(from_slice(&data)?),
|
|
Method::SanityCheck => SyncRequest::SanityCheck(from_slice(&data)?),
|
|
Method::Finish => SyncRequest::Finish,
|
|
Method::Abort => SyncRequest::Abort,
|
|
Method::FullUpload => {
|
|
let path = PathBuf::from(String::from_utf8(data).expect("path was not in utf8"));
|
|
SyncRequest::FullUpload(path)
|
|
}
|
|
Method::FullDownload => SyncRequest::FullDownload,
|
|
})
|
|
}
|
|
}
|
|
|
|
#[derive(Serialize, Deserialize, Debug)]
|
|
pub struct HostKeyRequest {
|
|
#[serde(rename = "u")]
|
|
pub username: String,
|
|
#[serde(rename = "p")]
|
|
pub password: String,
|
|
}
|
|
#[derive(Serialize, Deserialize, Debug)]
|
|
pub struct HostKeyResponse {
|
|
pub key: String,
|
|
}
|
|
|
|
#[derive(Serialize, Deserialize, Debug)]
|
|
pub struct MetaRequest {
|
|
#[serde(rename = "v")]
|
|
pub sync_version: u8,
|
|
#[serde(rename = "cv")]
|
|
pub client_version: String,
|
|
}
|
|
|
|
#[derive(Serialize, Deserialize, Debug)]
|
|
pub struct StartRequest {
|
|
#[serde(rename = "minUsn")]
|
|
pub client_usn: Usn,
|
|
#[serde(rename = "lnewer")]
|
|
pub local_is_newer: bool,
|
|
/// Unfortunately AnkiDroid is still using this
|
|
#[serde(rename = "graves", default)]
|
|
pub deprecated_client_graves: Option<Graves>,
|
|
}
|
|
|
|
#[derive(Serialize, Deserialize, Debug)]
|
|
pub struct ApplyGravesRequest {
|
|
pub chunk: Graves,
|
|
}
|
|
|
|
#[derive(Serialize, Deserialize, Debug)]
|
|
pub struct ApplyChangesRequest {
|
|
pub changes: UnchunkedChanges,
|
|
}
|
|
|
|
#[derive(Serialize, Deserialize, Debug)]
|
|
pub struct ApplyChunkRequest {
|
|
pub chunk: Chunk,
|
|
}
|
|
|
|
#[derive(Serialize, Deserialize, Debug)]
|
|
pub struct SanityCheckRequest {
|
|
pub client: SanityCheckCounts,
|
|
}
|