Extract binary merging logic
This commit is contained in:
parent
7a8cca8fe7
commit
10bc8c7099
9 changed files with 55 additions and 57 deletions
|
|
@ -1,16 +1,29 @@
|
|||
use std::str::Utf8Error;
|
||||
|
||||
use base64::DecodeError;
|
||||
use thiserror::Error;
|
||||
use wasm_bindgen::JsValue;
|
||||
|
||||
#[derive(Error, Debug)]
|
||||
pub enum SyncLibError {
|
||||
#[error("Base64 decoding error: {}", .reason)]
|
||||
DecodingError { reason: String },
|
||||
#[error("Base64 decoding error because of {}", .reason)]
|
||||
Base64DecodingError { reason: String },
|
||||
|
||||
#[error("Bytes cannot be decoded as UTF-8 string because of {}", .reason)]
|
||||
StringDecodingError { reason: String },
|
||||
}
|
||||
|
||||
impl From<DecodeError> for SyncLibError {
|
||||
fn from(e: DecodeError) -> Self {
|
||||
SyncLibError::DecodingError {
|
||||
SyncLibError::Base64DecodingError {
|
||||
reason: e.to_string(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Utf8Error> for SyncLibError {
|
||||
fn from(e: Utf8Error) -> Self {
|
||||
SyncLibError::StringDecodingError {
|
||||
reason: e.to_string(),
|
||||
}
|
||||
}
|
||||
|
|
@ -18,7 +31,7 @@ impl From<DecodeError> for SyncLibError {
|
|||
|
||||
impl From<std::string::FromUtf8Error> for SyncLibError {
|
||||
fn from(e: std::string::FromUtf8Error) -> Self {
|
||||
SyncLibError::DecodingError {
|
||||
SyncLibError::Base64DecodingError {
|
||||
reason: e.to_string(),
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
use core::str;
|
||||
|
||||
use base64::{engine::general_purpose::STANDARD_NO_PAD, Engine as _};
|
||||
use errors::SyncLibError;
|
||||
use wasm_bindgen::prelude::*;
|
||||
|
|
@ -27,6 +29,20 @@ pub fn base64_to_string(input: &str) -> Result<String, SyncLibError> {
|
|||
String::from_utf8(bytes).map_err(SyncLibError::from)
|
||||
}
|
||||
|
||||
#[wasm_bindgen]
|
||||
pub fn merge(parent: &[u8], left: &[u8], right: &[u8]) -> Result<Vec<u8>, SyncLibError> {
|
||||
Ok(if is_binary(right) {
|
||||
right.to_vec()
|
||||
} else {
|
||||
reconcile::reconcile(
|
||||
str::from_utf8(parent).map_err(SyncLibError::from)?,
|
||||
str::from_utf8(left).map_err(SyncLibError::from)?,
|
||||
str::from_utf8(right).map_err(SyncLibError::from)?,
|
||||
)
|
||||
.into_bytes()
|
||||
})
|
||||
}
|
||||
|
||||
#[wasm_bindgen]
|
||||
pub fn is_binary(data: &[u8]) -> bool { data.iter().any(|&b| b == 0) }
|
||||
|
||||
|
|
|
|||
|
|
@ -70,7 +70,6 @@ impl Database {
|
|||
created_date as "created_date: chrono::DateTime<Utc>",
|
||||
updated_date as "updated_date: chrono::DateTime<Utc>",
|
||||
relative_path,
|
||||
is_binary,
|
||||
is_deleted
|
||||
from latest_documents
|
||||
where is_deleted = false and vault_id = ?
|
||||
|
|
@ -103,7 +102,6 @@ impl Database {
|
|||
updated_date as "updated_date: chrono::DateTime<Utc>",
|
||||
relative_path,
|
||||
content,
|
||||
is_binary,
|
||||
is_deleted
|
||||
from latest_documents
|
||||
where vault_id = ? and document_id = ?
|
||||
|
|
@ -137,7 +135,6 @@ impl Database {
|
|||
updated_date as "updated_date: chrono::DateTime<Utc>",
|
||||
relative_path,
|
||||
content,
|
||||
is_binary,
|
||||
is_deleted
|
||||
from latest_documents
|
||||
where vault_id = ? and relative_path = ? and is_deleted = false
|
||||
|
|
@ -172,7 +169,6 @@ impl Database {
|
|||
updated_date as "updated_date: chrono::DateTime<Utc>",
|
||||
relative_path,
|
||||
content,
|
||||
is_binary,
|
||||
is_deleted
|
||||
from documents
|
||||
where vault_id = ? and document_id = ? and version_id = ?"#,
|
||||
|
|
@ -204,10 +200,9 @@ impl Database {
|
|||
updated_date,
|
||||
relative_path,
|
||||
content,
|
||||
is_binary,
|
||||
is_deleted
|
||||
)
|
||||
values (?, ?, ?, ?, ?, ?, ?, ?, ?)
|
||||
values (?, ?, ?, ?, ?, ?, ?, ?)
|
||||
"#,
|
||||
version.vault_id,
|
||||
version.document_id,
|
||||
|
|
@ -216,7 +211,6 @@ impl Database {
|
|||
version.updated_date,
|
||||
version.relative_path,
|
||||
version.content,
|
||||
version.is_binary,
|
||||
version.is_deleted
|
||||
);
|
||||
|
||||
|
|
|
|||
|
|
@ -16,14 +16,9 @@ pub struct StoredDocumentVersion {
|
|||
pub updated_date: DateTime<Utc>,
|
||||
pub relative_path: String,
|
||||
pub content: Vec<u8>,
|
||||
pub is_binary: bool,
|
||||
pub is_deleted: bool,
|
||||
}
|
||||
|
||||
impl StoredDocumentVersion {
|
||||
pub fn content_as_string(&self) -> String { String::from_utf8_lossy(&self.content).to_string() }
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, JsonSchema)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct DocumentVersionWithoutContent {
|
||||
|
|
@ -33,7 +28,6 @@ pub struct DocumentVersionWithoutContent {
|
|||
pub created_date: DateTime<Utc>,
|
||||
pub updated_date: DateTime<Utc>,
|
||||
pub relative_path: String,
|
||||
pub is_binary: bool,
|
||||
pub is_deleted: bool,
|
||||
}
|
||||
|
||||
|
|
@ -46,7 +40,6 @@ impl From<StoredDocumentVersion> for DocumentVersionWithoutContent {
|
|||
created_date: value.created_date,
|
||||
updated_date: value.updated_date,
|
||||
relative_path: value.relative_path,
|
||||
is_binary: value.is_binary,
|
||||
is_deleted: value.is_deleted,
|
||||
}
|
||||
}
|
||||
|
|
@ -69,7 +62,6 @@ pub struct DocumentVersion {
|
|||
pub updated_date: DateTime<Utc>,
|
||||
pub relative_path: String,
|
||||
pub content_base64: String,
|
||||
pub is_binary: bool,
|
||||
pub is_deleted: bool,
|
||||
}
|
||||
|
||||
|
|
@ -83,7 +75,6 @@ impl From<StoredDocumentVersion> for DocumentVersion {
|
|||
updated_date: value.updated_date,
|
||||
relative_path: value.relative_path,
|
||||
content_base64: bytes_to_base64(&value.content),
|
||||
is_binary: value.is_binary,
|
||||
is_deleted: value.is_deleted,
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ use axum_extra::{
|
|||
};
|
||||
use schemars::JsonSchema;
|
||||
use serde::Deserialize;
|
||||
use sync_lib::{base64_to_bytes, base64_to_string};
|
||||
use sync_lib::{base64_to_bytes, merge};
|
||||
|
||||
use super::{auth::auth, requests::CreateDocumentVersion};
|
||||
use crate::{
|
||||
|
|
@ -53,20 +53,17 @@ pub async fn create_document(
|
|||
.map_err(server_error)?;
|
||||
|
||||
let new_version = if let Some(existing_version) = maybe_existing_version {
|
||||
let merged_content = if request.is_binary {
|
||||
base64_to_bytes(&request.content_base64)
|
||||
.context("Failed to decode base64 content in request")
|
||||
.map_err(client_error)?
|
||||
} else {
|
||||
reconcile::reconcile(
|
||||
"", // the empty string is the first common parent of the two documents
|
||||
&existing_version.content_as_string(),
|
||||
&base64_to_string(&request.content_base64)
|
||||
.context("Failed to decode base64 content in request")
|
||||
.map_err(client_error)?,
|
||||
)
|
||||
.into_bytes()
|
||||
};
|
||||
let content_bytes = base64_to_bytes(&request.content_base64)
|
||||
.context("Failed to decode base64 content in request")
|
||||
.map_err(client_error)?;
|
||||
|
||||
let merged_content = merge(
|
||||
&[], // the empty string is the first common parent of the two documents,
|
||||
&existing_version.content,
|
||||
&content_bytes,
|
||||
)
|
||||
.context("Failed to decode bytes as UTF-8")
|
||||
.map_err(client_error)?;
|
||||
|
||||
StoredDocumentVersion {
|
||||
vault_id,
|
||||
|
|
@ -76,7 +73,6 @@ pub async fn create_document(
|
|||
created_date: request.created_date,
|
||||
relative_path: request.relative_path,
|
||||
updated_date: chrono::Utc::now(),
|
||||
is_binary: request.is_binary,
|
||||
is_deleted: false,
|
||||
}
|
||||
} else {
|
||||
|
|
@ -90,7 +86,6 @@ pub async fn create_document(
|
|||
created_date: request.created_date,
|
||||
relative_path: request.relative_path,
|
||||
updated_date: chrono::Utc::now(),
|
||||
is_binary: request.is_binary,
|
||||
is_deleted: false,
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -63,7 +63,6 @@ pub async fn delete_document(
|
|||
created_date: request.created_date,
|
||||
updated_date: chrono::Utc::now(),
|
||||
relative_path: latest_version.relative_path,
|
||||
is_binary: latest_version.is_binary,
|
||||
is_deleted: true,
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ use axum_extra::{
|
|||
TypedHeader,
|
||||
};
|
||||
|
||||
use super::auth::{self, auth};
|
||||
use super::auth::auth;
|
||||
use crate::{app_state::AppState, database::models::PingResponse, errors::SyncServerError};
|
||||
|
||||
#[axum::debug_handler]
|
||||
|
|
|
|||
|
|
@ -10,7 +10,6 @@ pub struct CreateDocumentVersion {
|
|||
pub created_date: DateTime<Utc>,
|
||||
pub relative_path: String,
|
||||
pub content_base64: String,
|
||||
pub is_binary: bool,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize, JsonSchema)]
|
||||
|
|
@ -20,7 +19,6 @@ pub struct UpdateDocumentVersion {
|
|||
pub created_date: DateTime<Utc>,
|
||||
pub relative_path: String,
|
||||
pub content_base64: String,
|
||||
pub is_binary: bool,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize, JsonSchema)]
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ use axum_extra::{
|
|||
};
|
||||
use schemars::JsonSchema;
|
||||
use serde::Deserialize;
|
||||
use sync_lib::{base64_to_bytes, base64_to_string};
|
||||
use sync_lib::{base64_to_bytes, merge};
|
||||
|
||||
use super::{auth::auth, requests::UpdateDocumentVersion};
|
||||
use crate::{
|
||||
|
|
@ -76,20 +76,13 @@ pub async fn update_document(
|
|||
)));
|
||||
}
|
||||
|
||||
let merged_content = if request.is_binary {
|
||||
base64_to_bytes(&request.content_base64)
|
||||
.context("Failed to decode base64 content in request")
|
||||
.map_err(client_error)?
|
||||
} else {
|
||||
reconcile::reconcile(
|
||||
&parent.content_as_string(),
|
||||
&latest_version.content_as_string(),
|
||||
&base64_to_string(&request.content_base64)
|
||||
.context("Failed to decode base64 content in request")
|
||||
.map_err(client_error)?,
|
||||
)
|
||||
.into_bytes()
|
||||
};
|
||||
let content_bytes = base64_to_bytes(&request.content_base64)
|
||||
.context("Failed to decode base64 content in request")
|
||||
.map_err(client_error)?;
|
||||
|
||||
let merged_content = merge(&parent.content, &latest_version.content, &content_bytes)
|
||||
.context("Failed to decode bytes as UTF-8")
|
||||
.map_err(client_error)?;
|
||||
|
||||
let new_version = StoredDocumentVersion {
|
||||
vault_id,
|
||||
|
|
@ -99,7 +92,6 @@ pub async fn update_document(
|
|||
created_date: request.created_date,
|
||||
relative_path: request.relative_path,
|
||||
updated_date: chrono::Utc::now(),
|
||||
is_binary: request.is_binary,
|
||||
is_deleted: false,
|
||||
};
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue