From 8388d7350554d082d0457aec99b3eaf84b880c57 Mon Sep 17 00:00:00 2001 From: Peter Cai Date: Sat, 22 Feb 2020 10:45:06 +0800 Subject: [PATCH] only allow one sync per user every time --- src/api.rs | 11 ++++++++++- src/lock.rs | 23 +++++++++++++++++++++++ src/main.rs | 2 ++ 3 files changed, 35 insertions(+), 1 deletion(-) create mode 100644 src/lock.rs diff --git a/src/api.rs b/src/api.rs index b603fa1..a83efaa 100644 --- a/src/api.rs +++ b/src/api.rs @@ -1,6 +1,8 @@ use crate::DbConn; use crate::user; use crate::item; +use crate::lock::UserLock; +use rocket::State; use rocket::http::Status; use rocket::response::status::Custom; use rocket_contrib::json::Json; @@ -180,7 +182,14 @@ struct SyncResp { } #[post("/items/sync", format = "json", data = "")] -fn items_sync(db: DbConn, u: user::User, params: Json) -> Custom> { +fn items_sync( + db: DbConn, lock: State, + u: user::User, params: Json +) -> Custom> { + // Only allow one sync per user at the same time + let mutex = lock.get_mutex(u.id); + let _lock = mutex.lock().unwrap(); + let mut resp = SyncResp { retrieved_items: vec![], saved_items: vec![], diff --git a/src/lock.rs b/src/lock.rs new file mode 100644 index 0000000..0b92969 --- /dev/null +++ b/src/lock.rs @@ -0,0 +1,23 @@ +use std::collections::HashMap; +use std::sync::{Arc, RwLock, Mutex}; + +// A per-user lock used for sync requests +pub struct UserLock { + lock_map: RwLock>>> +} + +impl UserLock { + pub fn new() -> UserLock { + UserLock { + lock_map: RwLock::new(HashMap::new()) + } + } + + pub fn get_mutex(&self, uid: i32) -> Arc> { + if !self.lock_map.read().unwrap().contains_key(&uid) { + self.lock_map.write().unwrap().insert(uid, Arc::new(Mutex::new(()))); + } + + self.lock_map.read().unwrap().get(&uid).unwrap().clone() + } +} \ No newline at end of file diff --git a/src/main.rs b/src/main.rs index b80ff7e..2eca156 100644 --- a/src/main.rs +++ b/src/main.rs @@ -23,6 +23,7 @@ mod api; mod tokens; mod user; mod item; +mod lock; #[cfg(test)] mod tests; @@ -126,6 +127,7 @@ pub fn build_rocket() -> Rocket { let r = rocket::custom(build_config()) .attach(cors) .attach(DbConn::fairing()) + .manage(lock::UserLock::new()) .mount("/", api::routes()); run_db_migrations(r) }