diff --git a/Cargo.toml b/Cargo.toml index 329403b..eeaa64a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,7 +9,7 @@ license = "AGPL-3.0" [dependencies] rocket = { version = "0.5.0-rc.1", features = ["json"] } diesel = { version = "1.4.8", features = ["postgres", "chrono"] } -redis = { version="0.21.5", features = ["aio", "async-std-comp"] } +redis = { version="0.21.5", features = ["aio", "tokio-comp"] } chrono = { version="0.*", features =["serde"] } rand = "0.*" dotenv = "0.*" diff --git a/src/api/attention.rs b/src/api/attention.rs index 911eb9f..4c648f5 100644 --- a/src/api/attention.rs +++ b/src/api/attention.rs @@ -1,5 +1,5 @@ use crate::api::post::ps2outputs; -use crate::api::{APIError, CurrentUser, MapToAPIError, PolicyError::*, API, UGC}; +use crate::api::{APIError, CurrentUser, PolicyError::*, API, UGC}; use crate::db_conn::Db; use crate::models::*; use crate::rds_conn::RdsConn; @@ -22,20 +22,22 @@ pub async fn attention_post( rconn: RdsConn, ) -> API { user.id.ok_or_else(|| APIError::PcError(NotAllowed))?; - let p = Post::get(&db, ai.pid).await.m()?; + let mut p = Post::get(&db, ai.pid).await?; p.check_permission(&user, "r")?; - let mut att = Attention::init(&user.namehash, rconn); + let mut att = Attention::init(&user.namehash, &rconn); let switch_to = ai.switch == 1; let mut delta: i32 = 0; - if att.has(ai.pid).await.m()? != switch_to { + if att.has(ai.pid).await? != switch_to { if switch_to { - att.add(ai.pid).await.m()?; + att.add(ai.pid).await?; delta = 1; } else { - att.remove(ai.pid).await.m()?; + att.remove(ai.pid).await?; delta = -1; } - p.change_n_attentions(&db, delta).await.m()?; + p = p.change_n_attentions(&db, delta).await?; + p = p.change_hot_score(&db, delta * 2).await?; + p.refresh_cache(&rconn, false).await; } Ok(json!({ @@ -49,12 +51,9 @@ pub async fn attention_post( #[get("/getattention")] pub async fn get_attention(user: CurrentUser, db: Db, rconn: RdsConn) -> API { - let ids = Attention::init(&user.namehash, rconn.clone()) - .all() - .await - .m()?; - let ps = Post::get_multi(&db, ids).await.m()?; - let ps_data = ps2outputs(&ps, &user, &db, rconn.clone()).await; + let ids = Attention::init(&user.namehash, &rconn).all().await?; + let ps = Post::get_multi(&db, ids).await?; + let ps_data = ps2outputs(&ps, &user, &db, &rconn, &vec![]).await; Ok(json!({ "code": 0, diff --git a/src/api/comment.rs b/src/api/comment.rs index da7f9ed..b803ec5 100644 --- a/src/api/comment.rs +++ b/src/api/comment.rs @@ -1,10 +1,11 @@ -use crate::api::{APIError, CurrentUser, MapToAPIError, PolicyError::*, API}; +use crate::api::{APIError, CurrentUser, PolicyError::*, API, UGC}; use crate::db_conn::Db; use crate::models::*; use crate::rds_conn::RdsConn; use crate::rds_models::*; use chrono::{offset::Utc, DateTime}; use rocket::form::Form; +use rocket::futures::{future::TryFutureExt, try_join}; use rocket::serde::{ json::{json, Value}, Serialize, @@ -24,6 +25,7 @@ pub struct CommentInput { pub struct CommentOutput { cid: i32, text: String, + author_title: String, can_del: bool, name_id: i32, is_tmp: bool, @@ -32,7 +34,12 @@ pub struct CommentOutput { timestamp: i64, } -pub fn c2output<'r>(p: &'r Post, cs: &Vec, user: &CurrentUser) -> Vec { +pub fn c2output<'r>( + p: &'r Post, + cs: &Vec, + user: &CurrentUser, + kws: &Vec<&str>, +) -> Vec { let mut hash2id = HashMap::<&String, i32>::from([(&p.author_hash, 0)]); cs.iter() .filter_map(|c| { @@ -48,10 +55,15 @@ pub fn c2output<'r>(p: &'r Post, cs: &Vec, user: &CurrentUser) -> Vec(p: &'r Post, cs: &Vec, user: &CurrentUser) -> Vec")] pub async fn get_comment(pid: i32, user: CurrentUser, db: Db, rconn: RdsConn) -> API { - let p = Post::get(&db, pid).await.m()?; + let p = Post::get(&db, pid).await?; if p.is_deleted { return Err(APIError::PcError(IsDeleted)); } let pid = p.id; - let cs = Comment::gets_by_post_id(&db, pid).await.m()?; - let data = c2output(&p, &cs, &user); + let cs = Comment::gets_by_post_id(&db, pid).await?; + let data = c2output(&p, &cs, &user, &vec![]); Ok(json!({ "code": 0, @@ -78,7 +90,7 @@ pub async fn get_comment(pid: i32, user: CurrentUser, db: Db, rconn: RdsConn) -> "n_attentions": p.n_attentions, // for old version frontend "likenum": p.n_attentions, - "attention": Attention::init(&user.namehash, rconn.clone()).has(p.id).await.m()? , + "attention": Attention::init(&user.namehash, &rconn).has(p.id).await? , })) } @@ -89,7 +101,7 @@ pub async fn add_comment( db: Db, rconn: RdsConn, ) -> API { - let p = Post::get(&db, ci.pid).await.m()?; + let mut p = Post::get(&db, ci.pid).await?; Comment::create( &db, NewComment { @@ -100,15 +112,28 @@ pub async fn add_comment( post_id: ci.pid, }, ) - .await - .m()?; - p.change_n_comments(&db, 1).await.m()?; + .await?; + p = p.change_n_comments(&db, 1).await?; // auto attention after comment - let mut att = Attention::init(&user.namehash, rconn); - if !att.has(p.id).await.m()? { - att.add(p.id).await.m()?; - p.change_n_attentions(&db, 1).await.m()?; + let mut att = Attention::init(&user.namehash, &rconn); + + let mut hs_delta = 1; + + if !att.has(p.id).await? { + hs_delta += 2; + try_join!( + att.add(p.id).err_into::(), + async { + p = p.change_n_attentions(&db, 1).await?; + Ok::<(), APIError>(()) + } + .err_into::(), + )?; } + + p = p.change_hot_score(&db, hs_delta).await?; + p.refresh_cache(&rconn, false).await; + Ok(json!({ "code": 0 })) diff --git a/src/api/mod.rs b/src/api/mod.rs index 30b6faf..52abeac 100644 --- a/src/api/mod.rs +++ b/src/api/mod.rs @@ -70,16 +70,6 @@ pub enum APIError { PcError(PolicyError), } -impl APIError { - fn from_db(err: diesel::result::Error) -> APIError { - APIError::DbError(err) - } - - fn from_rds(err: redis::RedisError) -> APIError { - APIError::RdsError(err) - } -} - impl<'r> Responder<'r, 'static> for APIError { fn respond_to(self, req: &'r Request<'_>) -> response::Result<'static> { dbg!(&self); @@ -107,28 +97,21 @@ impl<'r> Responder<'r, 'static> for APIError { } } -pub type API = Result; -pub type JsonAPI = API; - -pub trait MapToAPIError { - type Data; - fn m(self) -> API; -} - -impl MapToAPIError for redis::RedisResult { - type Data = T; - fn m(self) -> API { - Ok(self.map_err(APIError::from_rds)?) +impl From for APIError { + fn from(err: diesel::result::Error) -> APIError { + APIError::DbError(err) } } -impl MapToAPIError for diesel::QueryResult { - type Data = T; - fn m(self) -> API { - Ok(self.map_err(APIError::from_db)?) +impl From for APIError { + fn from(err: redis::RedisError) -> APIError { + APIError::RdsError(err) } } +pub type API = Result; +pub type JsonAPI = API; + #[rocket::async_trait] pub trait UGC { fn get_author_hash(&self) -> &str; @@ -178,7 +161,7 @@ impl UGC for Post { self.n_comments == 0 } async fn do_set_deleted(&self, db: &Db) -> API { - self.set_deleted(db).await.m() + self.set_deleted(db).await.map_err(From::from) } } @@ -197,7 +180,7 @@ impl UGC for Comment { true } async fn do_set_deleted(&self, db: &Db) -> API { - self.set_deleted(db).await.m() + self.set_deleted(db).await.map_err(From::from) } } @@ -211,4 +194,5 @@ pub mod attention; pub mod comment; pub mod operation; pub mod post; +pub mod search; pub mod systemlog; diff --git a/src/api/operation.rs b/src/api/operation.rs index c3c7767..6b5258b 100644 --- a/src/api/operation.rs +++ b/src/api/operation.rs @@ -1,5 +1,6 @@ -use crate::api::{APIError, CurrentUser, PolicyError::*, API, UGC, MapToAPIError}; +use crate::api::{APIError, CurrentUser, PolicyError::*, API, UGC}; use crate::db_conn::Db; +use crate::rds_conn::RdsConn; use crate::models::*; use rocket::form::Form; use rocket::serde::json::{json, Value}; @@ -13,16 +14,18 @@ pub struct DeleteInput { } #[post("/delete", data = "")] -pub async fn delete(di: Form, user: CurrentUser, db: Db) -> API { +pub async fn delete(di: Form, user: CurrentUser, db: Db, rconn: RdsConn) -> API { match di.id_type.as_str() { "cid" => { - let c = Comment::get(&db, di.id).await.m()?; + let c = Comment::get(&db, di.id).await?; c.soft_delete(&user, &db).await?; - let p = Post::get(&db, c.post_id).await.m()?; - p.change_n_comments(&db, -1).await.m()?; + let mut p = Post::get(&db, c.post_id).await?; + p = p.change_n_comments(&db, -1).await?; + p = p.change_hot_score(&db, -2).await?; + p.refresh_cache(&rconn, false).await; } "pid" => { - let p = Post::get(&db, di.id).await.m()?; + let p = Post::get(&db, di.id).await?; p.soft_delete(&user, &db).await?; } _ => return Err(APIError::PcError(NotAllowed)), diff --git a/src/api/post.rs b/src/api/post.rs index 175f0e9..1ca14fc 100644 --- a/src/api/post.rs +++ b/src/api/post.rs @@ -1,5 +1,5 @@ use crate::api::comment::{c2output, CommentOutput}; -use crate::api::{APIError, CurrentUser, JsonAPI, MapToAPIError, PolicyError::*, UGC}; +use crate::api::{APIError, CurrentUser, JsonAPI, PolicyError::*, UGC}; use crate::db_conn::Db; use crate::models::*; use crate::rds_conn::RdsConn; @@ -25,7 +25,7 @@ pub struct PostOutput { pid: i32, text: String, cw: Option, - custom_title: Option, + author_title: Option, is_tmp: bool, n_attentions: i32, n_comments: i32, @@ -49,10 +49,21 @@ pub struct CwInput { cw: String, } -async fn p2output(p: &Post, user: &CurrentUser, db: &Db, rconn: RdsConn) -> PostOutput { +async fn p2output( + p: &Post, + user: &CurrentUser, + db: &Db, + rconn: &RdsConn, + kws: &Vec<&str>, +) -> PostOutput { + let mut text = p.content.to_string(); + for kw in kws { + text = text.replace(kw, &format!(" **{}**", kw)); + } + PostOutput { pid: p.id, - text: format!("{}{}", if p.is_tmp { "[tmp]\n" } else { "" }, p.content), + text: format!("{}{}", if p.is_tmp { "[tmp]\n" } else { "" }, text), cw: if p.cw.len() > 0 { Some(p.cw.to_string()) } else { @@ -63,7 +74,7 @@ async fn p2output(p: &Post, user: &CurrentUser, db: &Db, rconn: RdsConn) -> Post create_time: p.create_time, last_comment_time: p.last_comment_time, allow_search: p.allow_search, - custom_title: if p.author_title.len() > 0 { + author_title: if p.author_title.len() > 0 { Some(p.author_title.to_string()) } else { None @@ -80,13 +91,13 @@ async fn p2output(p: &Post, user: &CurrentUser, db: &Db, rconn: RdsConn) -> Post // 单个洞还有查询评论的接口,这里挂了不用报错 let pid = p.id; if let Some(cs) = Comment::gets_by_post_id(db, pid).await.ok() { - Some(c2output(p, &cs, user)) + Some(c2output(p, &cs, user, kws)) } else { None } }, can_del: p.check_permission(user, "wd").is_ok(), - attention: Attention::init(&user.namehash, rconn.clone()) + attention: Attention::init(&user.namehash, &rconn) .has(p.id) .await .unwrap_or_default(), @@ -101,21 +112,23 @@ pub async fn ps2outputs( ps: &Vec, user: &CurrentUser, db: &Db, - rconn: RdsConn, + rconn: &RdsConn, + kws: &Vec<&str>, ) -> Vec { future::join_all( ps.iter() - .map(|p| async { p2output(p, &user, &db, rconn.clone()).await }), + .map(|p| async { p2output(p, &user, &db, &rconn, &kws.clone()).await }), ) .await } #[get("/getone?")] pub async fn get_one(pid: i32, user: CurrentUser, db: Db, rconn: RdsConn) -> JsonAPI { - let p = Post::get(&db, pid).await.m()?; + // let p = Post::get(&db, pid).await?; + let p = Post::get_with_cache(&db, &rconn, pid).await?; p.check_permission(&user, "ro")?; Ok(json!({ - "data": p2output(&p, &user,&db, rconn).await, + "data": p2output(&p, &user,&db, &rconn, &vec![]).await, "code": 0, })) } @@ -129,8 +142,10 @@ pub async fn get_list( rconn: RdsConn, ) -> JsonAPI { let page = p.unwrap_or(1); - let ps = Post::gets_by_page(&db, order_mode, page, 25).await.m()?; - let ps_data = ps2outputs(&ps, &user, &db, rconn.clone()).await; + let page_size = 25; + let start = (page - 1) * page_size; + let ps = Post::gets_by_page(&db, order_mode, start.into(), page_size.into()).await?; + let ps_data = ps2outputs(&ps, &user, &db, &rconn, &vec![]).await; Ok(json!({ "data": ps_data, "count": ps_data.len(), @@ -139,7 +154,12 @@ pub async fn get_list( } #[post("/dopost", data = "")] -pub async fn publish_post(poi: Form, user: CurrentUser, db: Db) -> JsonAPI { +pub async fn publish_post( + poi: Form, + user: CurrentUser, + db: Db, + rconn: RdsConn, +) -> JsonAPI { let p = Post::create( &db, NewPost { @@ -152,9 +172,8 @@ pub async fn publish_post(poi: Form, user: CurrentUser, db: Db) -> Js allow_search: poi.allow_search.is_some(), }, ) - .await - .m()?; - // TODO: attention + .await?; + Attention::init(&user.namehash, &rconn).add(p.id).await?; Ok(json!({ "code": 0 })) @@ -162,19 +181,19 @@ pub async fn publish_post(poi: Form, user: CurrentUser, db: Db) -> Js #[post("/editcw", data = "")] pub async fn edit_cw(cwi: Form, user: CurrentUser, db: Db) -> JsonAPI { - let p = Post::get(&db, cwi.pid).await.m()?; + let p = Post::get(&db, cwi.pid).await?; if !(user.is_admin || p.author_hash == user.namehash) { return Err(APIError::PcError(NotAllowed)); } p.check_permission(&user, "w")?; - _ = p.update_cw(&db, cwi.cw.to_string()).await.m()?; + _ = p.update_cw(&db, cwi.cw.to_string()).await?; Ok(json!({"code": 0})) } #[get("/getmulti?")] pub async fn get_multi(pids: Vec, user: CurrentUser, db: Db, rconn: RdsConn) -> JsonAPI { - let ps = Post::get_multi(&db, pids).await.m()?; - let ps_data = ps2outputs(&ps, &user, &db, rconn.clone()).await; + let ps = Post::get_multi(&db, pids).await?; + let ps_data = ps2outputs(&ps, &user, &db, &rconn, &vec![]).await; Ok(json!({ "code": 0, diff --git a/src/api/search.rs b/src/api/search.rs new file mode 100644 index 0000000..29e59c6 --- /dev/null +++ b/src/api/search.rs @@ -0,0 +1,40 @@ +use crate::api::post::ps2outputs; +use crate::api::{CurrentUser, JsonAPI}; +use crate::db_conn::Db; +use crate::models::*; +use crate::rds_conn::RdsConn; +use rocket::serde::json::json; + +#[get("/search?&&")] +pub async fn search( + keywords: String, + search_mode: u8, + page: i32, + user: CurrentUser, + db: Db, + rconn: RdsConn, +) -> JsonAPI { + let page_size = 25; + let start = (page - 1) * page_size; + + let kws = keywords.split(" ").filter(|x| !x.is_empty()).collect::>(); + let ps = if kws.is_empty() { + vec![] + } else { + Post::search( + &db, + search_mode, + keywords.to_string(), + start.into(), + page_size.into(), + ) + .await? + }; + let mark_kws = if search_mode == 1 {kws} else {vec![]}; + let ps_data = ps2outputs(&ps, &user, &db, &rconn, &mark_kws).await; + Ok(json!({ + "data": ps_data, + "count": ps_data.len(), + "code": 0 + })) +} diff --git a/src/main.rs b/src/main.rs index 935178f..501270d 100644 --- a/src/main.rs +++ b/src/main.rs @@ -30,6 +30,7 @@ async fn main() -> Result<(), rocket::Error> { api::post::publish_post, api::post::edit_cw, api::post::get_multi, + api::search::search, api::attention::attention_post, api::attention::get_attention, api::systemlog::get_systemlog, diff --git a/src/models.rs b/src/models.rs index 0e0d4e4..d00361e 100644 --- a/src/models.rs +++ b/src/models.rs @@ -1,9 +1,15 @@ #![allow(clippy::all)] -use diesel::{insert_into, ExpressionMethods, QueryDsl, QueryResult, RunQueryDsl}; - use crate::db_conn::Db; +use crate::rds_conn::RdsConn; +use crate::rds_models::PostCache; use crate::schema::*; +use chrono::{offset::Utc, DateTime}; +use diesel::{ + insert_into, BoolExpressionMethods, ExpressionMethods, QueryDsl, QueryResult, RunQueryDsl, + TextExpressionMethods, +}; +use rocket::serde::{Deserialize, Serialize}; no_arg_sql_function!(RANDOM, (), "Represents the sql RANDOM() function"); @@ -23,6 +29,7 @@ macro_rules! get_multi { db.run(move |c| { $table::table .filter($table::id.eq_any(ids)) + .filter($table::is_deleted.eq(false)) .order($table::id.desc()) .load(c) }) @@ -45,7 +52,14 @@ macro_rules! set_deleted { }; } -use chrono::{offset::Utc, DateTime}; +macro_rules! base_query { + ($table:ident) => { + $table::table + .into_boxed() + .filter($table::is_deleted.eq(false)) + }; +} + #[derive(Queryable, Insertable)] pub struct Comment { pub id: i32, @@ -59,7 +73,8 @@ pub struct Comment { pub post_id: i32, } -#[derive(Queryable, Insertable)] +#[derive(Queryable, Insertable, Serialize, Deserialize)] +#[serde(crate = "rocket::serde")] pub struct Post { pub id: i32, pub author_hash: String, @@ -105,29 +120,83 @@ impl Post { set_deleted!(posts); + 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?; + cacher.set(&p).await; + Ok(p) + } + } + pub async fn gets_by_page( db: &Db, order_mode: u8, - page: u32, - page_size: u32, + start: i64, + limit: i64, ) -> QueryResult> { db.run(move |c| { - let mut query = posts::table.into_boxed(); - query = query.filter(posts::is_deleted.eq(false)); + let mut query = base_query!(posts); if order_mode > 0 { query = query.filter(posts::is_reported.eq(false)) } - match order_mode { - 1 => query = query.order(posts::last_comment_time.desc()), - 2 => query = query.order(posts::hot_score.desc()), - 3 => query = query.order(RANDOM), - _ => query = query.order(posts::id.desc()), - } + query = match order_mode { + 0 => query.order(posts::id.desc()), + 1 => query.order(posts::last_comment_time.desc()), + 2 => query.order(posts::hot_score.desc()), + 3 => query.order(RANDOM), + _ => panic!("Wrong order mode!"), + }; + + query.offset(start).limit(limit).load(c) + }) + .await + } + + pub async fn search( + db: &Db, + search_mode: u8, + search_text: String, + start: i64, + limit: i64, + ) -> QueryResult> { + let search_text2 = search_text.replace("%", "\\%"); + db.run(move |c| { + let pat; + let mut query = base_query!(posts) + .distinct() + .left_join(comments::table) + .filter(comments::is_deleted.eq(false)); + // 先用搜索+缓存,性能有问题了再真的做tag表 + query = match search_mode { + 0 => { + pat = format!("%#{}%", &search_text2); + query + .filter(posts::cw.eq(&search_text)) + .or_filter(posts::cw.eq(format!("#{}", &search_text))) + .or_filter(posts::content.like(&pat)) + .or_filter(comments::content.like(&pat)) + } + 1 => { + pat = format!("%{}%", search_text2.replace(" ", "%")); + query + .filter(posts::content.like(&pat).or(comments::content.like(&pat))) + .filter(posts::allow_search.eq(true)) + } + 2 => query + .filter(posts::author_title.eq(&search_text)) + .or_filter(comments::author_title.eq(&search_text)), + _ => panic!("Wrong search mode!"), + }; query - .offset(((page - 1) * page_size).into()) - .limit(page_size.into()) + .order(posts::id.desc()) + .offset(start) + .limit(limit) .load(c) }) .await @@ -149,25 +218,42 @@ impl Post { .await } - pub async fn change_n_comments(&self, db: &Db, delta: i32) -> QueryResult { + pub async fn change_n_comments(&self, db: &Db, delta: i32) -> QueryResult { let pid = self.id; db.run(move |c| { diesel::update(posts::table.find(pid)) .set(posts::n_comments.eq(posts::n_comments + delta)) - .execute(c) + .get_result(c) }) .await } - pub async fn change_n_attentions(&self, db: &Db, delta: i32) -> QueryResult { + pub async fn change_n_attentions(&self, db: &Db, delta: i32) -> QueryResult { let pid = self.id; db.run(move |c| { diesel::update(posts::table.find(pid)) .set(posts::n_attentions.eq(posts::n_attentions + delta)) - .execute(c) + .get_result(c) }) .await } + + pub async fn change_hot_score(&self, db: &Db, delta: i32) -> QueryResult { + let pid = self.id; + db.run(move |c| { + diesel::update(posts::table.find(pid)) + .set(posts::hot_score.eq(posts::hot_score + delta)) + .get_result(c) + }) + .await + } + + pub async fn set_instance_cache(&self, rconn: &RdsConn) { + PostCache::init(&self.id, rconn).set(self).await; + } + pub async fn refresh_cache(&self, rconn: &RdsConn, is_new: bool) { + self.set_instance_cache(rconn).await; + } } impl User { diff --git a/src/rds_models.rs b/src/rds_models.rs index 5341aec..4be2d58 100644 --- a/src/rds_models.rs +++ b/src/rds_models.rs @@ -1,5 +1,10 @@ +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, @@ -7,10 +12,10 @@ pub struct Attention { } impl Attention { - pub fn init(namehash: &str, rconn: RdsConn) -> Self { + pub fn init(namehash: &str, rconn: &RdsConn) -> Self { Attention { key: format!("hole_v2:attention:{}", namehash), - rconn: rconn, + rconn: rconn.clone(), } } @@ -30,3 +35,50 @@ 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| { + dbg!("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 { + dbg!("hint post cache", &s); + self.rconn + .expire::<&String, bool>(&self.key, INSTANCE_EXPIRE_TIME) + .await + .unwrap_or_else(|e| { + dbg!("get post cache, set new expire failed", e, &self.key, &s); + false + }); + serde_json::from_str(&s).unwrap_or_else(|e| { + dbg!("get post cache failed", e, s); + None + }) + } else { + None + } + } +} diff --git a/src/schema.rs b/src/schema.rs index db6da45..83a6e58 100644 --- a/src/schema.rs +++ b/src/schema.rs @@ -42,8 +42,4 @@ table! { joinable!(comments -> posts (post_id)); -allow_tables_to_appear_in_same_query!( - comments, - posts, - users, -); +allow_tables_to_appear_in_same_query!(comments, posts, users,);