mirror of
https://github.com/stoatchat/stoatchat.git
synced 2026-07-14 13:36:59 +00:00
Add user cache, no more "guard refs".
This commit is contained in:
@@ -1,8 +1,7 @@
|
||||
use super::mutual::has_mutual_connection;
|
||||
use crate::database::channel::Channel;
|
||||
use crate::database::guild::{fetch_guild, fetch_member, Guild, Member, MemberKey};
|
||||
use crate::database::user::UserRelationship;
|
||||
use crate::guards::auth::UserRef;
|
||||
use crate::database::user::{User, UserRelationship};
|
||||
|
||||
use num_enum::TryFromPrimitive;
|
||||
|
||||
@@ -77,23 +76,23 @@ pub fn get_relationship_internal(
|
||||
Relationship::NONE
|
||||
}
|
||||
|
||||
pub fn get_relationship(a: &UserRef, b: &UserRef) -> Relationship {
|
||||
pub fn get_relationship(a: &User, b: &User) -> Relationship {
|
||||
if a.id == b.id {
|
||||
return Relationship::SELF;
|
||||
}
|
||||
|
||||
get_relationship_internal(&a.id, &b.id, &a.fetch_relationships())
|
||||
get_relationship_internal(&a.id, &b.id, &a.relations)
|
||||
}
|
||||
|
||||
pub struct PermissionCalculator {
|
||||
pub user: UserRef,
|
||||
pub user: User,
|
||||
pub channel: Option<Channel>,
|
||||
pub guild: Option<Guild>,
|
||||
pub member: Option<Member>,
|
||||
}
|
||||
|
||||
impl PermissionCalculator {
|
||||
pub fn new(user: UserRef) -> PermissionCalculator {
|
||||
pub fn new(user: User) -> PermissionCalculator {
|
||||
PermissionCalculator {
|
||||
user,
|
||||
channel: None,
|
||||
@@ -174,9 +173,8 @@ impl PermissionCalculator {
|
||||
}
|
||||
|
||||
if let Some(other) = other_user {
|
||||
let relationships = self.user.fetch_relationships();
|
||||
let relationship =
|
||||
get_relationship_internal(&self.user.id, &other, &relationships);
|
||||
get_relationship_internal(&self.user.id, &other, &self.user.relations);
|
||||
|
||||
if relationship == Relationship::Friend {
|
||||
permissions = 1024 + 128 + 32 + 16 + 1;
|
||||
|
||||
@@ -1,4 +1,11 @@
|
||||
use mongodb::bson::DateTime;
|
||||
use super::get_collection;
|
||||
|
||||
use lru::LruCache;
|
||||
use mongodb::bson::{doc, from_bson, Bson, DateTime};
|
||||
use rocket::http::{RawStr, Status};
|
||||
use rocket::request::{self, FromParam, FromRequest, Request};
|
||||
use rocket::Outcome;
|
||||
use std::sync::{Arc, Mutex};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||
@@ -28,3 +35,98 @@ pub struct User {
|
||||
pub email_verification: UserEmailVerification,
|
||||
pub relations: Option<Vec<UserRelationship>>,
|
||||
}
|
||||
|
||||
lazy_static! {
|
||||
static ref CACHE: Arc<Mutex<LruCache<String, User>>> =
|
||||
Arc::new(Mutex::new(LruCache::new(4_000_000)));
|
||||
}
|
||||
|
||||
pub fn fetch_user(id: &str) -> Result<Option<User>, String> {
|
||||
{
|
||||
if let Ok(mut cache) = CACHE.lock() {
|
||||
let existing = cache.get(&id.to_string());
|
||||
|
||||
if let Some(user) = existing {
|
||||
return Ok(Some((*user).clone()));
|
||||
}
|
||||
} else {
|
||||
return Err("Failed to lock cache.".to_string());
|
||||
}
|
||||
}
|
||||
|
||||
let col = get_collection("users");
|
||||
if let Ok(result) = col.find_one(doc! { "_id": id }, None) {
|
||||
if let Some(doc) = result {
|
||||
if let Ok(user) = from_bson(Bson::Document(doc)) as Result<User, _> {
|
||||
let mut cache = CACHE.lock().unwrap();
|
||||
cache.put(id.to_string(), user.clone());
|
||||
|
||||
Ok(Some(user))
|
||||
} else {
|
||||
Err("Failed to deserialize user!".to_string())
|
||||
}
|
||||
} else {
|
||||
Ok(None)
|
||||
}
|
||||
} else {
|
||||
Err("Failed to fetch user from database.".to_string())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum AuthError {
|
||||
Failed,
|
||||
Missing,
|
||||
Invalid,
|
||||
}
|
||||
|
||||
impl<'a, 'r> FromRequest<'a, 'r> for User {
|
||||
type Error = AuthError;
|
||||
|
||||
fn from_request(request: &'a Request<'r>) -> request::Outcome<Self, Self::Error> {
|
||||
let u = request.headers().get("x-user").next();
|
||||
let t = request.headers().get("x-auth-token").next();
|
||||
|
||||
if let Some(uid) = u {
|
||||
if let Some(token) = t {
|
||||
if let Ok(result) = fetch_user(uid) {
|
||||
if let Some(user) = result {
|
||||
if let Some(access_token) = &user.access_token {
|
||||
if access_token == token {
|
||||
Outcome::Success(user)
|
||||
} else {
|
||||
Outcome::Failure((Status::Forbidden, AuthError::Invalid))
|
||||
}
|
||||
} else {
|
||||
Outcome::Failure((Status::Forbidden, AuthError::Invalid))
|
||||
}
|
||||
} else {
|
||||
Outcome::Failure((Status::Forbidden, AuthError::Invalid))
|
||||
}
|
||||
} else {
|
||||
Outcome::Failure((Status::Forbidden, AuthError::Failed))
|
||||
}
|
||||
} else {
|
||||
Outcome::Failure((Status::Forbidden, AuthError::Missing))
|
||||
}
|
||||
} else {
|
||||
Outcome::Failure((Status::Forbidden, AuthError::Missing))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'r> FromParam<'r> for User {
|
||||
type Error = &'r RawStr;
|
||||
|
||||
fn from_param(param: &'r RawStr) -> Result<Self, Self::Error> {
|
||||
if let Ok(result) = fetch_user(¶m.to_string()) {
|
||||
if let Some(user) = result {
|
||||
Ok(user)
|
||||
} else {
|
||||
Err(param)
|
||||
}
|
||||
} else {
|
||||
Err(param)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user