From f67912e857b39dfda75e4d4c950548797772555c Mon Sep 17 00:00:00 2001 From: hole-thu Date: Thu, 24 Mar 2022 00:21:25 +0800 Subject: [PATCH] feat: user cache --- src/api/mod.rs | 4 +- src/cache.rs | 107 ++++++++++++++++++++++++++++++++++++++++++++++ src/main.rs | 1 + src/models.rs | 25 ++++++++--- src/rds_models.rs | 55 ------------------------ 5 files changed, 130 insertions(+), 62 deletions(-) create mode 100644 src/cache.rs diff --git a/src/api/mod.rs b/src/api/mod.rs index 52abeac..e90bef2 100644 --- a/src/api/mod.rs +++ b/src/api/mod.rs @@ -1,6 +1,7 @@ use crate::db_conn::Db; use crate::models::*; use crate::random_hasher::RandomHasher; +use crate::rds_conn::RdsConn; use rocket::http::Status; use rocket::outcome::try_outcome; use rocket::request::{FromRequest, Outcome, Request}; @@ -38,7 +39,8 @@ impl<'r> FromRequest<'r> for CurrentUser { }); } else { let db = try_outcome!(request.guard::().await); - if let Some(user) = User::get_by_token(&db, token).await { + let rconn = try_outcome!(request.guard::().await); + if let Some(user) = User::get_by_token_with_cache(&db, &rconn, token).await { let namehash = rh.hash_with_salt(&user.name); cu = Some(CurrentUser { id: Some(user.id), diff --git a/src/cache.rs b/src/cache.rs new file mode 100644 index 0000000..2290dfb --- /dev/null +++ b/src/cache.rs @@ -0,0 +1,107 @@ +use crate::models::{Comment, Post, User}; +use crate::rds_conn::RdsConn; +use redis::AsyncCommands; +use rocket::serde::json::serde_json; +// can use rocket::serde::json::to_string in master version + +const INSTANCE_EXPIRE_TIME: usize = 60 * 60; + +pub struct PostCache { + key: String, + rconn: RdsConn, +} + +impl PostCache { + pub fn init(pid: &i32, rconn: &RdsConn) -> Self { + PostCache { + key: format!("hole_v2:cache:post:{}", pid), + rconn: rconn.clone(), + } + } + + pub async fn set(&mut self, p: &Post) { + self.rconn + .set_ex( + &self.key, + serde_json::to_string(p).unwrap(), + INSTANCE_EXPIRE_TIME, + ) + .await + .unwrap_or_else(|e| { + warn!("set post cache failed: {}, {}", e, p.id); + }) + } + + pub async fn get(&mut self) -> Option { + let rds_result = self.rconn.get::<&String, String>(&self.key).await; + if let Ok(s) = rds_result { + debug!("hint user cache"); + self.rconn + .expire::<&String, bool>(&self.key, INSTANCE_EXPIRE_TIME) + .await + .unwrap_or_else(|e| { + warn!( + "get post cache, set new expire failed: {}, {}, {} ", + e, &self.key, &s + ); + false + }); + serde_json::from_str(&s).unwrap_or_else(|e| { + warn!("get post cache, decode failed {}, {}", e, s); + None + }) + } else { + None + } + } +} + +pub struct UserCache { + key: String, + rconn: RdsConn, +} + +impl UserCache { + pub fn init(token: &str, rconn: &RdsConn) -> Self { + UserCache { + key: format!("hole_v2:cache:user:{}", token), + rconn: rconn.clone(), + } + } + + pub async fn set(&mut self, u: &User) { + self.rconn + .set_ex( + &self.key, + serde_json::to_string(u).unwrap(), + INSTANCE_EXPIRE_TIME, + ) + .await + .unwrap_or_else(|e| { + warn!("set user cache failed: {}, {}, {}", e, u.id, u.name); + }) + } + + pub async fn get(&mut self) -> Option { + let rds_result = self.rconn.get::<&String, String>(&self.key).await; + if let Ok(s) = rds_result { + debug!("hint post cache"); + self.rconn + .expire::<&String, bool>(&self.key, INSTANCE_EXPIRE_TIME) + .await + .unwrap_or_else(|e| { + warn!( + "get post cache, set new expire failed: {}, {}, {} ", + e, &self.key, &s + ); + false + }); + serde_json::from_str(&s).unwrap_or_else(|e| { + warn!("get post cache, decode failed {}, {}", e, s); + None + }) + } else { + None + } + } +} diff --git a/src/main.rs b/src/main.rs index d69423b..c85043d 100644 --- a/src/main.rs +++ b/src/main.rs @@ -14,6 +14,7 @@ mod models; mod random_hasher; mod rds_conn; mod rds_models; +mod cache; mod schema; use db_conn::Db; diff --git a/src/models.rs b/src/models.rs index 015bcd7..89fac30 100644 --- a/src/models.rs +++ b/src/models.rs @@ -3,13 +3,14 @@ use crate::db_conn::Db; use crate::libs::diesel_logger::LoggingConnection; use crate::rds_conn::RdsConn; -use crate::rds_models::PostCache; +use crate::cache::{PostCache, UserCache}; use crate::schema::*; use chrono::{offset::Utc, DateTime}; use diesel::{ insert_into, BoolExpressionMethods, ExpressionMethods, QueryDsl, QueryResult, RunQueryDsl, TextExpressionMethods, }; +use diesel::dsl::any; use rocket::serde::{Deserialize, Serialize}; no_arg_sql_function!(RANDOM, (), "Represents the sql RANDOM() function"); @@ -27,10 +28,10 @@ macro_rules! get { macro_rules! get_multi { ($table:ident) => { pub async fn get_multi(db: &Db, ids: Vec) -> QueryResult> { - // can use eq(any()) for postgres + // eq(any()) is only for postgres db.run(move |c| { $table::table - .filter($table::id.eq_any(ids)) + .filter($table::id.eq(any(ids))) .filter($table::is_deleted.eq(false)) .order($table::id.desc()) .load(with_log!(c)) @@ -68,7 +69,8 @@ macro_rules! with_log { }; } -#[derive(Queryable, Insertable)] +#[derive(Queryable, Insertable, Serialize, Deserialize)] +#[serde(crate = "rocket::serde")] pub struct Comment { pub id: i32, pub author_hash: String, @@ -100,7 +102,8 @@ pub struct Post { pub allow_search: bool, } -#[derive(Queryable, Insertable)] +#[derive(Queryable, Insertable, Serialize, Deserialize)] +#[serde(crate = "rocket::serde")] pub struct User { pub id: i32, pub name: String, @@ -131,7 +134,6 @@ impl Post { pub async fn get_with_cache(db: &Db, rconn: &RdsConn, id: i32) -> QueryResult { let mut cacher = PostCache::init(&id, &rconn); if let Some(p) = cacher.get().await { - dbg!("hint and use post cache"); Ok(p) } else { let p = Self::get(db, id).await?; @@ -278,6 +280,17 @@ impl User { .await .ok() } + + pub async fn get_by_token_with_cache(db: &Db, rconn: &RdsConn, token: &str) -> Option { + let mut cacher = UserCache::init(token, &rconn); + if let Some(u) = cacher.get().await { + Some(u) + } else { + let u = Self::get_by_token(db, token).await?; + cacher.set(&u).await; + Some(u) + } + } } #[derive(Insertable)] diff --git a/src/rds_models.rs b/src/rds_models.rs index e8615c0..93161bb 100644 --- a/src/rds_models.rs +++ b/src/rds_models.rs @@ -1,10 +1,5 @@ -use crate::models::{Comment, Post}; use crate::rds_conn::RdsConn; use redis::{AsyncCommands, RedisResult}; -use rocket::serde::json::serde_json; -// can use rocket::serde::json::to_string in master version - -const INSTANCE_EXPIRE_TIME: usize = 60 * 60; pub struct Attention { key: String, @@ -35,53 +30,3 @@ impl Attention { self.rconn.smembers(&self.key).await } } - -pub struct PostCache { - key: String, - rconn: RdsConn, -} - -impl PostCache { - pub fn init(pid: &i32, rconn: &RdsConn) -> Self { - PostCache { - key: format!("hole_v2:cache:post:{}", pid), - rconn: rconn.clone(), - } - } - - pub async fn set(&mut self, p: &Post) { - self.rconn - .set_ex( - &self.key, - serde_json::to_string(p).unwrap(), - INSTANCE_EXPIRE_TIME, - ) - .await - .unwrap_or_else(|e| { - warn!("set post cache failed: {}, {}", e, p.id); - }) - } - - pub async fn get(&mut self) -> Option { - let rds_result = self.rconn.get::<&String, String>(&self.key).await; - if let Ok(s) = rds_result { - debug!("hint post cache"); - self.rconn - .expire::<&String, bool>(&self.key, INSTANCE_EXPIRE_TIME) - .await - .unwrap_or_else(|e| { - warn!( - "get post cache, set new expire failed: {}, {}, {} ", - e, &self.key, &s - ); - false - }); - serde_json::from_str(&s).unwrap_or_else(|e| { - warn!("get post cache, decode failed {}, {}", e, s); - None - }) - } else { - None - } - } -}