feat: user cache
This commit is contained in:
@@ -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::<Db>().await);
|
||||
if let Some(user) = User::get_by_token(&db, token).await {
|
||||
let rconn = try_outcome!(request.guard::<RdsConn>().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),
|
||||
|
||||
107
src/cache.rs
Normal file
107
src/cache.rs
Normal file
@@ -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<Post> {
|
||||
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<User> {
|
||||
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
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -14,6 +14,7 @@ mod models;
|
||||
mod random_hasher;
|
||||
mod rds_conn;
|
||||
mod rds_models;
|
||||
mod cache;
|
||||
mod schema;
|
||||
|
||||
use db_conn::Db;
|
||||
|
||||
@@ -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<i32>) -> QueryResult<Vec<Self>> {
|
||||
// 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<Self> {
|
||||
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<Self> {
|
||||
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)]
|
||||
|
||||
@@ -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<Post> {
|
||||
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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user