feat: post comments cache & use cache everywhere

This commit is contained in:
2022-03-24 23:33:32 +08:00
parent cc32c318a7
commit c8b8ad0787
8 changed files with 228 additions and 131 deletions

View File

@@ -22,7 +22,7 @@ pub async fn attention_post(
rconn: RdsConn,
) -> API<Value> {
user.id.ok_or_else(|| APIError::PcError(NotAllowed))?;
let mut p = Post::get(&db, ai.pid).await?;
let mut p = Post::get(&db, &rconn, ai.pid).await?;
p.check_permission(&user, "r")?;
let mut att = Attention::init(&user.namehash, &rconn);
let switch_to = ai.switch == 1;
@@ -35,8 +35,8 @@ pub async fn attention_post(
att.remove(ai.pid).await?;
delta = -1;
}
p = p.change_n_attentions(&db, delta).await?;
p = p.change_hot_score(&db, delta * 2).await?;
p.change_n_attentions(&db, delta).await?;
p.change_hot_score(&db, delta * 2).await?;
p.refresh_cache(&rconn, false).await;
}
@@ -52,7 +52,7 @@ pub async fn attention_post(
#[get("/getattention")]
pub async fn get_attention(user: CurrentUser, db: Db, rconn: RdsConn) -> API<Value> {
let ids = Attention::init(&user.namehash, &rconn).all().await?;
let ps = Post::get_multi(&db, ids).await?;
let ps = Post::get_multi(&db, &rconn, &ids).await?;
let ps_data = ps2outputs(&ps, &user, &db, &rconn).await;
Ok(json!({

View File

@@ -5,7 +5,7 @@ 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::futures::{future::TryFutureExt, join, try_join};
use rocket::serde::{
json::{json, Value},
Serialize,
@@ -34,11 +34,7 @@ pub struct CommentOutput {
timestamp: i64,
}
pub fn c2output<'r>(
p: &'r Post,
cs: &Vec<Comment>,
user: &CurrentUser,
) -> Vec<CommentOutput> {
pub fn c2output<'r>(p: &'r Post, cs: &Vec<Comment>, user: &CurrentUser) -> Vec<CommentOutput> {
let mut hash2id = HashMap::<&String, i32>::from([(&p.author_hash, 0)]);
cs.iter()
.filter_map(|c| {
@@ -71,12 +67,11 @@ pub fn c2output<'r>(
#[get("/getcomment?<pid>")]
pub async fn get_comment(pid: i32, user: CurrentUser, db: Db, rconn: RdsConn) -> API<Value> {
let p = Post::get(&db, pid).await?;
let p = Post::get(&db, &rconn, 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?;
let cs = p.get_comments(&db, &rconn).await?;
let data = c2output(&p, &cs, &user);
Ok(json!({
@@ -96,7 +91,7 @@ pub async fn add_comment(
db: Db,
rconn: RdsConn,
) -> API<Value> {
let mut p = Post::get(&db, ci.pid).await?;
let mut p = Post::get(&db, &rconn, ci.pid).await?;
Comment::create(
&db,
NewComment {
@@ -108,7 +103,7 @@ pub async fn add_comment(
},
)
.await?;
p = p.change_n_comments(&db, 1).await?;
p.change_n_comments(&db, 1).await?;
// auto attention after comment
let mut att = Attention::init(&user.namehash, &rconn);
@@ -119,15 +114,18 @@ pub async fn add_comment(
try_join!(
att.add(p.id).err_into::<APIError>(),
async {
p = p.change_n_attentions(&db, 1).await?;
p.change_n_attentions(&db, 1).await?;
Ok::<(), APIError>(())
}
.err_into::<APIError>(),
)?;
}
p = p.change_hot_score(&db, hs_delta).await?;
p.refresh_cache(&rconn, false).await;
p.change_hot_score(&db, hs_delta).await?;
join!(
p.refresh_cache(&rconn, false),
p.clear_comments_cache(&rconn),
);
Ok(json!({
"code": 0

View File

@@ -40,7 +40,7 @@ impl<'r> FromRequest<'r> for CurrentUser {
} else {
let db = try_outcome!(request.guard::<Db>().await);
let rconn = try_outcome!(request.guard::<RdsConn>().await);
if let Some(user) = User::get_by_token_with_cache(&db, &rconn, token).await {
if let Some(user) = User::get_by_token(&db, &rconn, token).await {
let namehash = rh.hash_with_salt(&user.name);
cu = Some(CurrentUser {
id: Some(user.id),
@@ -74,7 +74,6 @@ pub enum APIError {
impl<'r> Responder<'r, 'static> for APIError {
fn respond_to(self, req: &'r Request<'_>) -> response::Result<'static> {
dbg!(&self);
match self {
APIError::DbError(e) => json!({
"code": -1,
@@ -120,7 +119,7 @@ pub trait UGC {
fn get_is_deleted(&self) -> bool;
fn get_is_reported(&self) -> bool;
fn extra_delete_condition(&self) -> bool;
async fn do_set_deleted(&self, db: &Db) -> API<usize>;
async fn do_set_deleted(&mut self, db: &Db) -> API<()>;
fn check_permission(&self, user: &CurrentUser, mode: &str) -> API<()> {
if user.is_admin {
return Ok(());
@@ -140,10 +139,10 @@ pub trait UGC {
Ok(())
}
async fn soft_delete(&self, user: &CurrentUser, db: &Db) -> API<()> {
async fn soft_delete(&mut self, user: &CurrentUser, db: &Db) -> API<()> {
self.check_permission(user, "rwd")?;
let _ = self.do_set_deleted(db).await?;
self.do_set_deleted(db).await?;
Ok(())
}
}
@@ -162,7 +161,7 @@ impl UGC for Post {
fn extra_delete_condition(&self) -> bool {
self.n_comments == 0
}
async fn do_set_deleted(&self, db: &Db) -> API<usize> {
async fn do_set_deleted(&mut self, db: &Db) -> API<()> {
self.set_deleted(db).await.map_err(From::from)
}
}
@@ -181,7 +180,7 @@ impl UGC for Comment {
fn extra_delete_condition(&self) -> bool {
true
}
async fn do_set_deleted(&self, db: &Db) -> API<usize> {
async fn do_set_deleted(&mut self, db: &Db) -> API<()> {
self.set_deleted(db).await.map_err(From::from)
}
}

View File

@@ -1,7 +1,7 @@
use crate::api::{APIError, CurrentUser, PolicyError::*, API, UGC};
use crate::db_conn::Db;
use crate::rds_conn::RdsConn;
use crate::models::*;
use crate::rds_conn::RdsConn;
use rocket::form::Form;
use rocket::serde::json::{json, Value};
@@ -14,23 +14,32 @@ pub struct DeleteInput {
}
#[post("/delete", data = "<di>")]
pub async fn delete(di: Form<DeleteInput>, user: CurrentUser, db: Db, rconn: RdsConn) -> API<Value> {
pub async fn delete(
di: Form<DeleteInput>,
user: CurrentUser,
db: Db,
rconn: RdsConn,
) -> API<Value> {
let mut p: Post;
match di.id_type.as_str() {
"cid" => {
let c = Comment::get(&db, di.id).await?;
let mut c = Comment::get(&db, di.id).await?;
c.soft_delete(&user, &db).await?;
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;
p = Post::get(&db, &rconn, c.post_id).await?;
p.change_n_comments(&db, -1).await?;
p.change_hot_score(&db, -1).await?;
p.clear_comments_cache(&rconn).await;
}
"pid" => {
let p = Post::get(&db, di.id).await?;
p = Post::get(&db, &rconn, di.id).await?;
p.soft_delete(&user, &db).await?;
}
_ => return Err(APIError::PcError(NotAllowed)),
}
p.refresh_cache(&rconn, false).await;
Ok(json!({
"code": 0
}))

View File

@@ -50,12 +50,7 @@ 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) -> PostOutput {
PostOutput {
pid: p.id,
text: format!("{}{}", if p.is_tmp { "[tmp]\n" } else { "" }, p.content),
@@ -84,8 +79,7 @@ async fn p2output(
None
} else {
// 单个洞还有查询评论的接口,这里挂了不用报错
let pid = p.id;
if let Some(cs) = Comment::gets_by_post_id(db, pid).await.ok() {
if let Some(cs) = p.get_comments(db, rconn).await.ok() {
Some(c2output(p, &cs, user))
} else {
None
@@ -96,7 +90,11 @@ async fn p2output(
.has(p.id)
.await
.unwrap_or_default(),
hot_score: if user.is_admin { Some(p.hot_score) } else { None },
hot_score: if user.is_admin {
Some(p.hot_score)
} else {
None
},
// for old version frontend
timestamp: p.create_time.timestamp(),
likenum: p.n_attentions,
@@ -120,7 +118,7 @@ pub async fn ps2outputs(
#[get("/getone?<pid>")]
pub async fn get_one(pid: i32, user: CurrentUser, db: Db, rconn: RdsConn) -> JsonAPI {
// let p = Post::get(&db, pid).await?;
let p = Post::get_with_cache(&db, &rconn, pid).await?;
let p = Post::get(&db, &rconn, pid).await?;
p.check_permission(&user, "ro")?;
Ok(json!({
"data": p2output(&p, &user,&db, &rconn).await,
@@ -175,19 +173,20 @@ pub async fn publish_post(
}
#[post("/editcw", data = "<cwi>")]
pub async fn edit_cw(cwi: Form<CwInput>, user: CurrentUser, db: Db) -> JsonAPI {
let p = Post::get(&db, cwi.pid).await?;
pub async fn edit_cw(cwi: Form<CwInput>, user: CurrentUser, db: Db, rconn: RdsConn) -> JsonAPI {
let mut p = Post::get(&db, &rconn, 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?;
p.update_cw(&db, cwi.cw.to_string()).await?;
p.refresh_cache(&rconn, false);
Ok(json!({"code": 0}))
}
#[get("/getmulti?<pids>")]
pub async fn get_multi(pids: Vec<i32>, user: CurrentUser, db: Db, rconn: RdsConn) -> JsonAPI {
let ps = Post::get_multi_with_cache(&db, &rconn, &pids).await?;
let ps = Post::get_multi(&db, &rconn, &pids).await?;
let ps_data = ps2outputs(&ps, &user, &db, &rconn).await;
Ok(json!({

View File

@@ -17,7 +17,10 @@ pub async fn search(
let page_size = 25;
let start = (page - 1) * page_size;
let kws = keywords.split(" ").filter(|x| !x.is_empty()).collect::<Vec<&str>>();
let kws = keywords
.split(" ")
.filter(|x| !x.is_empty())
.collect::<Vec<&str>>();
let ps = if kws.is_empty() {
vec![]
} else {
@@ -30,7 +33,6 @@ pub async fn search(
)
.await?
};
let mark_kws = if search_mode == 1 {kws} else {vec![]};
let ps_data = ps2outputs(&ps, &user, &db, &rconn).await;
Ok(json!({
"data": ps_data,