feat: user cache
This commit is contained in:
@@ -1,6 +1,7 @@
|
|||||||
use crate::db_conn::Db;
|
use crate::db_conn::Db;
|
||||||
use crate::models::*;
|
use crate::models::*;
|
||||||
use crate::random_hasher::RandomHasher;
|
use crate::random_hasher::RandomHasher;
|
||||||
|
use crate::rds_conn::RdsConn;
|
||||||
use rocket::http::Status;
|
use rocket::http::Status;
|
||||||
use rocket::outcome::try_outcome;
|
use rocket::outcome::try_outcome;
|
||||||
use rocket::request::{FromRequest, Outcome, Request};
|
use rocket::request::{FromRequest, Outcome, Request};
|
||||||
@@ -38,7 +39,8 @@ impl<'r> FromRequest<'r> for CurrentUser {
|
|||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
let db = try_outcome!(request.guard::<Db>().await);
|
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);
|
let namehash = rh.hash_with_salt(&user.name);
|
||||||
cu = Some(CurrentUser {
|
cu = Some(CurrentUser {
|
||||||
id: Some(user.id),
|
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 random_hasher;
|
||||||
mod rds_conn;
|
mod rds_conn;
|
||||||
mod rds_models;
|
mod rds_models;
|
||||||
|
mod cache;
|
||||||
mod schema;
|
mod schema;
|
||||||
|
|
||||||
use db_conn::Db;
|
use db_conn::Db;
|
||||||
|
|||||||
@@ -3,13 +3,14 @@
|
|||||||
use crate::db_conn::Db;
|
use crate::db_conn::Db;
|
||||||
use crate::libs::diesel_logger::LoggingConnection;
|
use crate::libs::diesel_logger::LoggingConnection;
|
||||||
use crate::rds_conn::RdsConn;
|
use crate::rds_conn::RdsConn;
|
||||||
use crate::rds_models::PostCache;
|
use crate::cache::{PostCache, UserCache};
|
||||||
use crate::schema::*;
|
use crate::schema::*;
|
||||||
use chrono::{offset::Utc, DateTime};
|
use chrono::{offset::Utc, DateTime};
|
||||||
use diesel::{
|
use diesel::{
|
||||||
insert_into, BoolExpressionMethods, ExpressionMethods, QueryDsl, QueryResult, RunQueryDsl,
|
insert_into, BoolExpressionMethods, ExpressionMethods, QueryDsl, QueryResult, RunQueryDsl,
|
||||||
TextExpressionMethods,
|
TextExpressionMethods,
|
||||||
};
|
};
|
||||||
|
use diesel::dsl::any;
|
||||||
use rocket::serde::{Deserialize, Serialize};
|
use rocket::serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
no_arg_sql_function!(RANDOM, (), "Represents the sql RANDOM() function");
|
no_arg_sql_function!(RANDOM, (), "Represents the sql RANDOM() function");
|
||||||
@@ -27,10 +28,10 @@ macro_rules! get {
|
|||||||
macro_rules! get_multi {
|
macro_rules! get_multi {
|
||||||
($table:ident) => {
|
($table:ident) => {
|
||||||
pub async fn get_multi(db: &Db, ids: Vec<i32>) -> QueryResult<Vec<Self>> {
|
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| {
|
db.run(move |c| {
|
||||||
$table::table
|
$table::table
|
||||||
.filter($table::id.eq_any(ids))
|
.filter($table::id.eq(any(ids)))
|
||||||
.filter($table::is_deleted.eq(false))
|
.filter($table::is_deleted.eq(false))
|
||||||
.order($table::id.desc())
|
.order($table::id.desc())
|
||||||
.load(with_log!(c))
|
.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 struct Comment {
|
||||||
pub id: i32,
|
pub id: i32,
|
||||||
pub author_hash: String,
|
pub author_hash: String,
|
||||||
@@ -100,7 +102,8 @@ pub struct Post {
|
|||||||
pub allow_search: bool,
|
pub allow_search: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Queryable, Insertable)]
|
#[derive(Queryable, Insertable, Serialize, Deserialize)]
|
||||||
|
#[serde(crate = "rocket::serde")]
|
||||||
pub struct User {
|
pub struct User {
|
||||||
pub id: i32,
|
pub id: i32,
|
||||||
pub name: String,
|
pub name: String,
|
||||||
@@ -131,7 +134,6 @@ impl Post {
|
|||||||
pub async fn get_with_cache(db: &Db, rconn: &RdsConn, id: i32) -> QueryResult<Self> {
|
pub async fn get_with_cache(db: &Db, rconn: &RdsConn, id: i32) -> QueryResult<Self> {
|
||||||
let mut cacher = PostCache::init(&id, &rconn);
|
let mut cacher = PostCache::init(&id, &rconn);
|
||||||
if let Some(p) = cacher.get().await {
|
if let Some(p) = cacher.get().await {
|
||||||
dbg!("hint and use post cache");
|
|
||||||
Ok(p)
|
Ok(p)
|
||||||
} else {
|
} else {
|
||||||
let p = Self::get(db, id).await?;
|
let p = Self::get(db, id).await?;
|
||||||
@@ -278,6 +280,17 @@ impl User {
|
|||||||
.await
|
.await
|
||||||
.ok()
|
.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)]
|
#[derive(Insertable)]
|
||||||
|
|||||||
@@ -1,10 +1,5 @@
|
|||||||
use crate::models::{Comment, Post};
|
|
||||||
use crate::rds_conn::RdsConn;
|
use crate::rds_conn::RdsConn;
|
||||||
use redis::{AsyncCommands, RedisResult};
|
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 {
|
pub struct Attention {
|
||||||
key: String,
|
key: String,
|
||||||
@@ -35,53 +30,3 @@ impl Attention {
|
|||||||
self.rconn.smembers(&self.key).await
|
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