mirror of
https://github.com/stoatchat/stoatchat.git
synced 2026-07-14 05:26:59 +00:00
Add user cache, no more "guard refs".
This commit is contained in:
@@ -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