use async_session::{Result, Session, SessionStore};
use async_trait::async_trait;
use shared_svc::cache::{CacheKey, RedisManager, redis::AsyncCommands};
use sqlx::{PgPool, Postgres, Transaction};
use tracing::{debug, instrument};
use crate::Provider;
#[async_trait]
pub trait AccountMgr {
async fn get_apid_by_email(&self, email: &str) -> Result>;
async fn create_account(&self, provider: Provider, provider_user_id: &str, ap_id: &str);
async fn create_account_step(
&self,
provider: Provider,
provider_user_id: &str,
ap_id: &str,
email: &str,
transaction: &mut Transaction<'_, Postgres>,
) -> Result;
async fn persist_session(&self);
}
#[derive(Debug, Clone)]
pub struct AuthService {
cache: RedisManager,
database: PgPool,
}
#[async_trait]
impl AccountMgr for AuthService {
#[instrument(skip(self))]
async fn get_apid_by_email(&self, email: &str) -> Result > {
todo!()
}
#[instrument(skip(self))]
async fn create_account(&self, provider: Provider, provider_user_id: &str, ap_id: &str) {
todo!()
}
#[instrument(skip(self, transaction))]
async fn create_account_step(
&self,
provider: Provider,
provider_user_id: &str,
ap_id: &str,
email: &str,
transaction: &mut Transaction<'_, Postgres>,
) -> Result {
sqlx::query!(
"insert into account
(provider_id, provider_user_id, email, ap_id)
values ($1, $2, $3, $4)
",
"",
provider_user_id,
"",
ap_id
)
.execute(&mut **transaction)
.await?;
todo!()
}
#[instrument(skip(self))]
async fn persist_session(&self) {}
}
impl AuthService {
pub fn new(cache: &RedisManager, database: &PgPool) -> Self {
Self {
cache: cache.clone(),
database: database.clone(),
}
}
}
#[async_trait]
impl SessionStore for AuthService {
#[doc = " Get a session from the storage backend."]
#[doc = ""]
#[doc = " The input is expected to be the value of an identifying"]
#[doc = " cookie. This will then be parsed by the session middleware"]
#[doc = " into a session if possible"]
#[instrument(skip(self, cookie_value))]
async fn load_session(&self, cookie_value: String) -> Result > {
debug!("getting session");
let id = Session::id_from_cookie_value(&cookie_value)?;
let mut client = self.cache.get().await?;
let session = client
.get::<_, Option>>(CacheKey::Session(&id))
.await?;
match session {
Some(value) => Ok(Some(serde_json::from_slice(&value)?)),
None => Ok(None),
}
}
#[doc = " Store a session on the storage backend."]
#[doc = ""]
#[doc = " The return value is the value of the cookie to store for the"]
#[doc = " user that represents this session"]
#[instrument(err(Debug), skip(self, session), fields(id = session.id()))]
async fn store_session(&self, session: Session) -> Result> {
debug!("storing session");
let mut client = self.cache.get().await?;
let bytes = serde_json::to_vec(&session)?;
client
.set_ex::<_, _, ()>(CacheKey::Session(session.id()), bytes, 3600)
.await?;
Ok(session.into_cookie_value())
}
#[doc = " Remove a session from the session store"]
#[instrument(err(Debug), skip(self, session), fields(id = session.id()))]
async fn destroy_session(&self, session: Session) -> Result {
debug!("destroying session");
let mut client = self.cache.get().await?;
client.del::<_, ()>(CacheKey::Session(session.id())).await?;
Ok(())
}
#[doc = " Empties the entire store, destroying all sessions"]
#[instrument(skip(self))]
async fn clear_store(&self) -> Result {
debug!("clearing store");
let mut client = self.cache.get().await?;
client.del::<_, ()>(CacheKey::Session("").key()).await?;
Ok(())
}
}