api: rewrite conflict detection in iterators
This commit is contained in:
parent
3f266269cc
commit
09b2f945d2
16
Cargo.lock
generated
16
Cargo.lock
generated
|
@ -240,6 +240,12 @@ dependencies = [
|
|||
"regex 0.2.11",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "either"
|
||||
version = "1.5.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bb1f6b1ce1c140482ea30ddd3335fc0024ac7ee112895426e0a629a6c20adfe3"
|
||||
|
||||
[[package]]
|
||||
name = "fake-simd"
|
||||
version = "0.1.2"
|
||||
|
@ -412,6 +418,15 @@ dependencies = [
|
|||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "itertools"
|
||||
version = "0.8.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f56a2d0bc861f9165be4eb3442afd3c236d8a98afd426f65d92324ae1091a484"
|
||||
dependencies = [
|
||||
"either",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "itoa"
|
||||
version = "0.4.5"
|
||||
|
@ -1079,6 +1094,7 @@ dependencies = [
|
|||
"diesel",
|
||||
"diesel_migrations",
|
||||
"dotenv",
|
||||
"itertools",
|
||||
"lazy_static",
|
||||
"regex 1.3.4",
|
||||
"rocket",
|
||||
|
|
|
@ -18,3 +18,4 @@ uuid = { version = "0.8", features = ["v4"] }
|
|||
chrono = "0.4"
|
||||
serde_json = "1.0"
|
||||
regex = "1"
|
||||
itertools = "0.8"
|
56
src/api.rs
56
src/api.rs
|
@ -2,6 +2,7 @@ use crate::DbConn;
|
|||
use crate::user;
|
||||
use crate::item;
|
||||
use crate::lock::UserLock;
|
||||
use itertools::{Itertools, Either};
|
||||
use rocket::State;
|
||||
use rocket::http::Status;
|
||||
use rocket::response::status::Custom;
|
||||
|
@ -258,42 +259,41 @@ fn items_sync(
|
|||
}
|
||||
}
|
||||
|
||||
// Then, update all items sent by client
|
||||
let mut last_id: i64 = -1;
|
||||
for mut it in inner_params.items.into_iter() {
|
||||
// Handle conflicts
|
||||
// Anything that we just retrieved but need to save immediately
|
||||
// is potentially a conflict
|
||||
// TODO: how do we handle this when the sync needs multiple requests
|
||||
// to finish?
|
||||
let mut conflicted = false;
|
||||
for y in resp.retrieved_items.iter() {
|
||||
if it.uuid == y.uuid {
|
||||
conflicted = true;
|
||||
// We assume enc_item_key identifies an "item"
|
||||
if it.enc_item_key == y.enc_item_key {
|
||||
// A sync conflict
|
||||
resp.conflicts.push(SyncConflict {
|
||||
conf_type: "sync_conflict".to_string(),
|
||||
server_item: Some(y.clone()),
|
||||
unsaved_item: None
|
||||
// Detect conflicts between client items and server items
|
||||
let (items_conflicted, items_to_save): (Vec<_>, Vec<_>) =
|
||||
inner_params.items.into_iter().partition_map(|client_item| {
|
||||
let conflict: Vec<_> = resp.retrieved_items.iter()
|
||||
.filter(|server_item| client_item.uuid == server_item.uuid)
|
||||
.collect();
|
||||
if !conflict.is_empty() {
|
||||
Either::Left((client_item, conflict[0].clone()))
|
||||
} else {
|
||||
Either::Right(client_item)
|
||||
}
|
||||
});
|
||||
|
||||
// Convert conflicts into the format our client wants
|
||||
resp.conflicts = items_conflicted.into_iter().map(|(client_item, server_item)| {
|
||||
// We assume enc_item_key "identifies" an "item"
|
||||
if client_item.enc_item_key == server_item.enc_item_key {
|
||||
SyncConflict {
|
||||
conf_type: "sync_conflict".to_string(),
|
||||
server_item: Some(server_item),
|
||||
unsaved_item: None
|
||||
}
|
||||
} else {
|
||||
// A UUID conflict (unlikely)
|
||||
resp.conflicts.push(SyncConflict {
|
||||
SyncConflict {
|
||||
conf_type: "uuid_conflict".to_string(),
|
||||
server_item: None,
|
||||
unsaved_item: Some(it.clone())
|
||||
})
|
||||
}
|
||||
unsaved_item: Some(client_item)
|
||||
}
|
||||
}
|
||||
}).collect();
|
||||
|
||||
// do not save conflicted items
|
||||
if conflicted {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Then, update all items sent by client
|
||||
let mut last_id: i64 = -1;
|
||||
for mut it in items_to_save.into_iter() {
|
||||
// Always update updated_at for all items on server
|
||||
it.updated_at =
|
||||
Some(chrono::Utc::now().to_rfc3339_opts(chrono::SecondsFormat::Millis, true));
|
||||
|
|
Loading…
Reference in a new issue