Browse Source

feat: user cache

master
hole-thu 3 years ago
parent
commit
f67912e857
  1. 4
      src/api/mod.rs
  2. 107
      src/cache.rs
  3. 1
      src/main.rs
  4. 25
      src/models.rs
  5. 55
      src/rds_models.rs

4
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::<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

@ -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
}
}
}

1
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;

25
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<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)]

55
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<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
}
}
}

Loading…
Cancel
Save