538d47b
use std::time::Duration;
use crate::models::users::users;
use crate::session::Session;
use sea_orm::{ColumnTrait, EntityTrait, QueryFilter};
use crate::AuthSvc;
use crate::errors::{AuthError, AuthResult};
use crate::me::types::MeResponse;
pub const ME_CACHE_TTL_SECS: u64 = 300;
const ME_COUNT_TTL_SECS: u64 = 600;
const ME_REFRESH_EVERY: i64 = 5;
pub fn me_cache_keys(user_id: i64) -> (String, String) {
(
format!("auth:me:{user_id}"),
format!("auth:me:count:{user_id}"),
)
}
pub async fn invalidate_me_cache(cache: &crate::cache::Cache, user_id: i64) {
let (cache_key, count_key) = me_cache_keys(user_id);
let dropped = async {
cache.delete(&cache_key).await?;
cache.delete(&count_key).await?;
Ok::<(), crate::cache::CacheError>(())
}
.await;
if let Err(error) = dropped {
tracing::warn!(%error, user_id, "failed to drop the me cache");
}
}
impl AuthSvc {
#[tracing::instrument(skip_all, fields(request_id = %_request_id, client_ip = ?session.client_ip().ok().flatten()))]
pub async fn me(&self, session: Session, _request_id: String) -> AuthResult<MeResponse> {
let user_id = self
.require_session(&session, Some(_request_id.as_str()))
.await?;
self.me_for_user(user_id).await
}
pub(crate) async fn me_for_user(&self, user_id: i64) -> AuthResult<MeResponse> {
let (cache_key, count_key) = me_cache_keys(user_id);
let count = self.cache().incr(&count_key).await?;
if count == 1 {
let _ = self
.cache()
.expire(&count_key, Duration::from_secs(ME_COUNT_TTL_SECS))
.await;
}
if count % ME_REFRESH_EVERY != 0
&& let Some(cached) = self.cache().get_json::<MeResponse>(&cache_key).await?
{
return Ok(cached);
}
let user = users::Entity::find_by_id(user_id)
.filter(users::Column::DeletedAt.is_null())
.one(self.db().read())
.await?
.ok_or(AuthError::Unauthenticated)?;
let me = MeResponse::from(user);
let _ = self
.cache()
.set_json_ex(&cache_key, &me, Duration::from_secs(ME_CACHE_TTL_SECS))
.await;
Ok(me)
}
}