api: item/sync: fix cursor_token and sync_token logic

This commit is contained in:
Peter Cai 2020-02-21 17:27:05 +08:00
parent fd9b1310b0
commit 5d5e88fcef
No known key found for this signature in database
GPG Key ID: 71F5FB4E4F3FD54F
2 changed files with 33 additions and 16 deletions

View File

@ -165,8 +165,8 @@ fn items_sync(db: DbConn, u: user::User, params: Json<SyncParams>) -> Custom<Jso
retrieved_items: vec![],
saved_items: vec![],
unsaved: vec![],
sync_token: params.sync_token.clone(),
cursor_token: params.cursor_token.clone()
sync_token: None,
cursor_token: None
};
let inner_params = params.into_inner();
@ -189,16 +189,15 @@ fn items_sync(db: DbConn, u: user::User, params: Json<SyncParams>) -> Custom<Jso
}
let mut from_id: Option<i64> = None;
let mut max_id: Option<i64> = None;
let mut had_cursor = false;
if let Some(cursor_token) = inner_params.cursor_token {
// If the client provides cursor_token,
// then, we return all records
// until sync_token (the head of the last sync)
from_id = cursor_token.parse().ok();
max_id = inner_params.sync_token.clone()
.and_then(|i| i.parse().ok());
} else if let Some(sync_token) = inner_params.sync_token {
had_cursor = true;
} else if let Some(sync_token) = inner_params.sync_token.clone() {
// If there is no cursor_token, then we are doing
// a normal sync, so just return all records from sync_token
from_id = sync_token.parse().ok();
@ -206,7 +205,7 @@ fn items_sync(db: DbConn, u: user::User, params: Json<SyncParams>) -> Custom<Jso
// Then, retrieve what the client needs
let result = item::SyncItem::items_of_user(&db, &u,
from_id, max_id, inner_params.limit);
from_id, None, inner_params.limit);
match result {
Err(item::ItemOpError(e)) => {
@ -214,15 +213,33 @@ fn items_sync(db: DbConn, u: user::User, params: Json<SyncParams>) -> Custom<Jso
},
Ok(items) => {
if !items.is_empty() {
// max_id = the last sync token
// if we still haven't reached the last sync token yet,
// return a new cursor token and keep the sync token
if let Some(max_id) = max_id {
resp.cursor_token = Some(items[0].id.to_string());
resp.sync_token = Some(max_id.to_string());
// If we fetched something
// we should record the current last id to *some* token
// this may be `cursor_token` or `sync_token`
// if we have more to fetch, we set `cursor_token` to this id
// so that the client knows to continue
// and we set `sync_token` to this id regardless, for the
// client to remember where we were even if
// it doesn't need to continue
let next_from = items.last().unwrap().id;
if let Some(limit) = inner_params.limit {
if items.len() as i64 == limit {
// We may still have something to fetch
resp.cursor_token = Some(next_from.to_string());
}
}
// Always set sync_token to equal cursor_token in this case
resp.sync_token = Some(next_from.to_string());
} else {
if had_cursor {
// If we already have no item to give, but the client still holds a cursor
// Revoke that cursor, and make it the sync_token
resp.sync_token = resp.cursor_token.clone();
resp.cursor_token = None;
} else {
// Else, use the current max id as the sync_token
resp.sync_token = Some(items[0].id.to_string());
// Pass the same sync_token back
resp.sync_token = inner_params.sync_token.clone();
}
}
resp.retrieved_items = items.into_iter().map(|x| x.into()).collect();

View File

@ -95,7 +95,7 @@ impl SyncItem {
stmt = stmt.filter(id.le(max_id));
}
stmt.order(id.desc())
stmt.order(id.asc())
.load::<Item>(db)
.map_err(|_| "Database error".into())
})