Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor: get rid of leaderboard cache #111

Merged
merged 1 commit into from
Jan 9, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
234 changes: 98 additions & 136 deletions src/api/leaderboards.rs
Original file line number Diff line number Diff line change
@@ -1,17 +1,13 @@
use actix_web::{
error::*,
web::{self, Data, Json, Path},
web::{self, Json, Path},
HttpResponse, Responder,
};
use dashmap::DashMap;
use diesel::result::DatabaseErrorKind;
use serde::{Deserialize, Serialize};

use crate::{
api::auth::SecuredUserIdentity,
database::DatabaseWrapper,
error::TimeError,
models::{PrivateLeaderboard, UserId},
api::auth::SecuredUserIdentity, database::DatabaseWrapper, error::TimeError, models::UserId,
};

#[derive(Deserialize, Serialize)]
Expand All @@ -29,13 +25,6 @@ pub struct LeaderboardUser {
pub user: String,
}

pub struct CachedLeaderboard {
pub board: PrivateLeaderboard,
pub valid_until: chrono::DateTime<chrono::Utc>,
}

pub type LeaderboardCache = DashMap<i32, CachedLeaderboard>;

#[post("/leaderboards/create")]
pub async fn create_leaderboard(
creator: UserId,
Expand Down Expand Up @@ -71,37 +60,17 @@ pub async fn get_leaderboard(
user: UserId,
path: Path<(String,)>,
db: DatabaseWrapper,
cache: Data<LeaderboardCache>,
) -> Result<impl Responder, TimeError> {
let name = path.0.clone();
if let Ok(lid) = db.get_leaderboard_id_by_name(name).await {
if db.is_leaderboard_member(user.id, lid).await? {
if let Some(cached_leaderboard) = cache.get(&lid) {
if cached_leaderboard.value().valid_until > chrono::Utc::now() {
return Ok(web::Json(cached_leaderboard.board.to_owned()));
} else {
drop(cached_leaderboard);
cache.remove(&lid);
}
}
let board = db.get_leaderboard(path.0.clone()).await?;

cache.insert(
lid,
CachedLeaderboard {
board: board.clone(),
valid_until: chrono::Utc::now() + chrono::Duration::minutes(5),
},
);
let lid = db
.get_leaderboard_id_by_name(path.0.clone())
.await
.map_err(|_| TimeError::LeaderboardNotFound)?;

Ok(web::Json(board))
} else {
error!("{}", TimeError::Unauthorized);
Err(TimeError::Unauthorized)
}
if db.is_leaderboard_member(user.id, lid).await? {
let board = db.get_leaderboard(path.0.clone()).await?;
Ok(web::Json(board))
} else {
error!("{}", TimeError::LeaderboardNotFound);
Err(TimeError::LeaderboardNotFound)
Err(TimeError::Unauthorized)
}
}

Expand All @@ -111,18 +80,16 @@ pub async fn delete_leaderboard(
path: Path<(String,)>,
db: DatabaseWrapper,
) -> Result<impl Responder, TimeError> {
let name = path.0.clone();
if let Ok(lid) = db.get_leaderboard_id_by_name(name).await {
if db.is_leaderboard_admin(user.identity.id, lid).await? {
db.delete_leaderboard(path.0.clone()).await?;
Ok(HttpResponse::Ok().finish())
} else {
error!("{}", TimeError::Unauthorized);
Err(TimeError::Unauthorized)
}
let lid = db
.get_leaderboard_id_by_name(path.0.clone())
.await
.map_err(|_| TimeError::LeaderboardNotFound)?;

if db.is_leaderboard_admin(user.identity.id, lid).await? {
db.delete_leaderboard(path.0.clone()).await?;
Ok(HttpResponse::Ok().finish())
} else {
error!("{}", TimeError::LeaderboardNotFound);
Err(TimeError::LeaderboardNotFound)
Err(TimeError::Unauthorized)
}
}

Expand Down Expand Up @@ -162,24 +129,24 @@ pub async fn leave_leaderboard(
path: Path<(String,)>,
db: DatabaseWrapper,
) -> Result<impl Responder, TimeError> {
if let Ok(lid) = db.get_leaderboard_id_by_name(path.0.clone()).await {
if db.is_leaderboard_admin(user.identity.id, lid).await?
&& db.get_leaderboard_admin_count(lid).await? == 1
{
return Err(TimeError::LastAdmin);
}
let left = db
.remove_user_from_leaderboard(lid, user.identity.id)
.await?;
let lid = db
.get_leaderboard_id_by_name(path.0.clone())
.await
.map_err(|_| TimeError::LeaderboardNotFound)?;

if left {
Ok(HttpResponse::Ok().finish())
} else {
Err(TimeError::NotMember)
}
if db.is_leaderboard_admin(user.identity.id, lid).await?
&& db.get_leaderboard_admin_count(lid).await? == 1
{
return Err(TimeError::LastAdmin);
}

if db
.remove_user_from_leaderboard(lid, user.identity.id)
.await?
{
Ok(HttpResponse::Ok().finish())
} else {
error!("{}", TimeError::LeaderboardNotFound);
Err(TimeError::LeaderboardNotFound)
Err(TimeError::NotMember)
}
}

Expand All @@ -190,29 +157,28 @@ pub async fn promote_member(
db: DatabaseWrapper,
promotion: Json<LeaderboardUser>,
) -> Result<impl Responder, TimeError> {
if let Ok(lid) = db.get_leaderboard_id_by_name(path.0.clone()).await {
if db.is_leaderboard_admin(user.identity.id, lid).await? {
if let Ok(newadmin) = db.get_user_by_name(promotion.user.clone()).await {
if db
.promote_user_to_leaderboard_admin(lid, newadmin.id)
.await?
{
Ok(HttpResponse::Ok().finish())
} else {
// FIXME: This is not correct
Err(TimeError::NotMember)
}
} else {
error!("{}", TimeError::UserNotFound);
Err(TimeError::UserNotFound)
}
let lid = db
.get_leaderboard_id_by_name(path.0.clone())
.await
.map_err(|_| TimeError::LeaderboardNotFound)?;

if db.is_leaderboard_admin(user.identity.id, lid).await? {
let newadmin = db
.get_user_by_name(promotion.user.clone())
.await
.map_err(|_| TimeError::UserNotFound)?;

if db
.promote_user_to_leaderboard_admin(lid, newadmin.id)
.await?
{
Ok(HttpResponse::Ok().finish())
} else {
error!("{}", TimeError::Unauthorized);
Err(TimeError::Unauthorized)
// FIXME: This is not correct
Err(TimeError::NotMember)
}
} else {
error!("{}", TimeError::LeaderboardNotFound);
Err(TimeError::LeaderboardNotFound)
Err(TimeError::Unauthorized)
}
}

Expand All @@ -223,29 +189,28 @@ pub async fn demote_member(
db: DatabaseWrapper,
demotion: Json<LeaderboardUser>,
) -> Result<impl Responder, TimeError> {
if let Ok(lid) = db.get_leaderboard_id_by_name(path.0.clone()).await {
if db.is_leaderboard_admin(user.identity.id, lid).await? {
if let Ok(oldadmin) = db.get_user_by_name(demotion.user.clone()).await {
if db
.demote_user_to_leaderboard_member(lid, oldadmin.id)
.await?
{
Ok(HttpResponse::Ok().finish())
} else {
// FIXME: This is not correct
Err(TimeError::NotMember)
}
} else {
error!("{}", TimeError::UserNotFound);
Err(TimeError::UserNotFound)
}
let lid = db
.get_leaderboard_id_by_name(path.0.clone())
.await
.map_err(|_| TimeError::LeaderboardNotFound)?;

if db.is_leaderboard_admin(user.identity.id, lid).await? {
let oldadmin = db
.get_user_by_name(demotion.user.clone())
.await
.map_err(|_| TimeError::UserNotFound)?;

if db
.demote_user_to_leaderboard_member(lid, oldadmin.id)
.await?
{
Ok(HttpResponse::Ok().finish())
} else {
error!("{}", TimeError::Unauthorized);
Err(TimeError::Unauthorized)
// FIXME: This is not correct
Err(TimeError::NotMember)
}
} else {
error!("{}", TimeError::LeaderboardNotFound);
Err(TimeError::LeaderboardNotFound)
Err(TimeError::Unauthorized)
}
}

Expand All @@ -256,25 +221,23 @@ pub async fn kick_member(
db: DatabaseWrapper,
kick: Json<LeaderboardUser>,
) -> Result<impl Responder, TimeError> {
if let Ok(lid) = db.get_leaderboard_id_by_name(path.0.clone()).await {
if db.is_leaderboard_admin(user.identity.id, lid).await? {
if let Ok(kmember) = db.get_user_by_name(kick.user.clone()).await {
if db.remove_user_from_leaderboard(lid, kmember.id).await? {
Ok(HttpResponse::Ok().finish())
} else {
Err(TimeError::NotMember)
}
} else {
error!("{}", TimeError::UserNotFound);
Err(TimeError::UserNotFound)
}
} else {
error!("{}", TimeError::Unauthorized);
Err(TimeError::Unauthorized)
}
let lid = db
.get_leaderboard_id_by_name(path.0.clone())
.await
.map_err(|_| TimeError::LeaderboardNotFound)?;

if db.is_leaderboard_admin(user.identity.id, lid).await? {
let kmember = db
.get_user_by_name(kick.user.clone())
.await
.map_err(|_| TimeError::UserNotFound)?;

db.remove_user_from_leaderboard(lid, kmember.id)
.await
.map_err(|_| TimeError::NotMember)?;
Ok(HttpResponse::Ok().finish())
} else {
error!("{}", TimeError::LeaderboardNotFound);
Err(TimeError::LeaderboardNotFound)
Err(TimeError::Unauthorized)
}
}

Expand All @@ -284,16 +247,15 @@ pub async fn regenerate_invite(
path: Path<(String,)>,
db: DatabaseWrapper,
) -> Result<impl Responder, TimeError> {
if let Ok(lid) = db.get_leaderboard_id_by_name(path.0.clone()).await {
if db.is_leaderboard_admin(user.identity.id, lid).await? {
let code = db.regenerate_leaderboard_invite(lid).await?;
Ok(web::Json(json!({ "invite_code": code })))
} else {
error!("{}", TimeError::Unauthorized);
Err(TimeError::Unauthorized)
}
let lid = db
.get_leaderboard_id_by_name(path.0.clone())
.await
.map_err(|_| TimeError::LeaderboardNotFound)?;

if db.is_leaderboard_admin(user.identity.id, lid).await? {
let code = db.regenerate_leaderboard_invite(lid).await?;
Ok(web::Json(json!({ "invite_code": code })))
} else {
error!("{}", TimeError::LeaderboardNotFound);
Err(TimeError::LeaderboardNotFound)
Err(TimeError::Unauthorized)
}
}
10 changes: 4 additions & 6 deletions src/api/users.rs
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@ pub async fn get_current_activity(

#[get("/users/{username}/activity/data")]
pub async fn get_activities(
data: Query<DataRequest>,
Query(data): Query<DataRequest>,
path: Path<(String,)>,
opt_user: UserIdentityOptional,
db: DatabaseWrapper,
Expand All @@ -141,16 +141,14 @@ pub async fn get_activities(
.map_err(|_| TimeError::UserNotFound)?;

if target_user.is_public {
return Ok(web::Json(
db.get_activity(data.into_inner(), target_user.id).await?,
));
return Ok(web::Json(db.get_activity(data, target_user.id).await?));
} else {
return Err(TimeError::UserNotFound);
};
};

let data = if path.0 == "@me" {
db.get_activity(data.into_inner(), user.id).await?
db.get_activity(data, user.id).await?
} else {
//FIXME: This is technically not required when the username equals the username of the
//authenticated user
Expand All @@ -163,7 +161,7 @@ pub async fn get_activities(
|| target_user.is_public
|| db.are_friends(user.id, target_user.id).await?
{
db.get_activity(data.into_inner(), target_user.id).await?
db.get_activity(data, target_user.id).await?
} else {
return Err(TimeError::Unauthorized);
}
Expand Down
2 changes: 0 additions & 2 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,6 @@ async fn main() -> std::io::Result<()> {
);

let heartbeat_store = Data::new(api::activity::HeartBeatMemoryStore::new());
let leaderboard_cache = Data::new(api::leaderboards::LeaderboardCache::new());

let secured_access_token_storage = Data::new(SecuredAccessTokenStorage::new());

Expand Down Expand Up @@ -182,7 +181,6 @@ async fn main() -> std::io::Result<()> {
scope
}
})
.app_data(Data::clone(&leaderboard_cache))
.app_data(Data::clone(&database))
.app_data(Data::clone(&heartbeat_store));
#[cfg(feature = "testausid")]
Expand Down
4 changes: 1 addition & 3 deletions src/tests/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,6 @@ fn init_test_services(cfg: &mut ServiceConfig) {
);

let heartbeat_store = Data::new(crate::api::activity::HeartBeatMemoryStore::new());
let leaderboard_cache = Data::new(crate::api::leaderboards::LeaderboardCache::new());

let secured_access_token_storage = Data::new(crate::SecuredAccessTokenStorage::new());

Expand Down Expand Up @@ -115,8 +114,7 @@ fn init_test_services(cfg: &mut ServiceConfig) {
}
}),
)
.app_data(Data::clone(&heartbeat_store))
.app_data(Data::clone(&leaderboard_cache));
.app_data(Data::clone(&heartbeat_store));
#[cfg(feature = "testausid")]
{
cfg.app_data(Data::new(client));
Expand Down
Loading