/// Storage impls to persis OAuth sessions if you are not using the memory stores /// https://github.com/bluesky-social/statusphere-example-app/blob/main/src/auth/storage.ts use crate::cache::{ ATRIUM_SESSION_STORE_PREFIX, ATRIUM_STATE_STORE_KEY, Cache, create_prefixed_key, }; use atrium_api::types::string::Did; use atrium_common::store::Store; use atrium_oauth::store::session::SessionStore; use atrium_oauth::store::state::StateStore; use bb8::Pool; use bb8_redis::RedisConnectionManager; use bb8_redis::redis::AsyncCommands; use serde::Serialize; use serde::de::DeserializeOwned; use std::fmt::Debug; use std::hash::Hash; use thiserror::Error; #[derive(Error, Debug)] pub enum AtriumStoreError { #[error("No session found")] NoSessionFound, #[error("Redis error: {0}")] RedisError(#[from] bb8_redis::redis::RedisError), #[error("Serialization error: {0}")] SerializationError(#[from] serde_json::Error), #[error("Database error: {0}")] DatabaseError(#[from] sqlx::Error), #[error("Pool error: {0}")] PoolError(#[from] bb8::RunError), } impl SessionStore for AtriumSessionStore {} pub struct AtriumSessionStore { cache_pool: Pool, } impl AtriumSessionStore { pub fn new(pool: Pool) -> Self { Self { cache_pool: pool } } } impl Store for AtriumSessionStore where K: Debug + Eq + Hash + Send + Sync + 'static + From + AsRef, V: Debug + Clone + Send + Sync + 'static + Serialize + DeserializeOwned, { type Error = AtriumStoreError; async fn get(&self, key: &K) -> Result, Self::Error> { let key = create_prefixed_key(ATRIUM_SESSION_STORE_PREFIX, key.as_ref()); let mut cache = self.cache_pool.get().await?; let value: Option = cache.get(key).await?; match value { Some(json_str) => { let deserialized: V = serde_json::from_str(&json_str)?; Ok(Some(deserialized)) } None => Ok(None), } } async fn set(&self, key: K, value: V) -> Result<(), Self::Error> { let cache_key = create_prefixed_key(ATRIUM_SESSION_STORE_PREFIX, key.as_ref()); let json_value = serde_json::to_string(&value)?; let mut cache = self.cache_pool.get().await?; let _: () = cache.set(cache_key, json_value).await?; Ok(()) } async fn del(&self, key: &K) -> Result<(), Self::Error> { let cache_key = create_prefixed_key(ATRIUM_SESSION_STORE_PREFIX, key.as_ref()); let mut cache = self.cache_pool.get().await?; let _: usize = cache.del(cache_key).await?; Ok(()) } async fn clear(&self) -> Result<(), Self::Error> { let pattern = format!("{}*", ATRIUM_SESSION_STORE_PREFIX); let mut cache = self.cache_pool.get().await?; let keys: Vec = cache.keys(pattern).await?; if !keys.is_empty() { let _: usize = cache.del(keys).await?; } Ok(()) } } impl StateStore for AtriumStateStore {} pub struct AtriumStateStore { cache_pool: Pool, } impl AtriumStateStore { pub fn new(pool: Pool) -> Self { Self { cache_pool: pool } } } impl Store for AtriumStateStore where K: Debug + Eq + Hash + Send + Sync + 'static + From + AsRef, V: Debug + Clone + Send + Sync + 'static + Serialize + DeserializeOwned, { type Error = AtriumStoreError; async fn get(&self, key: &K) -> Result, Self::Error> { let key = create_prefixed_key(ATRIUM_STATE_STORE_KEY, key.as_ref()); let mut cache = self.cache_pool.get().await?; let value: Option = cache.get(key).await?; match value { Some(json_str) => { let deserialized: V = serde_json::from_str(&json_str)?; Ok(Some(deserialized)) } None => Ok(None), } } async fn set(&self, key: K, value: V) -> Result<(), Self::Error> { let cache_key = create_prefixed_key(ATRIUM_STATE_STORE_KEY, key.as_ref()); let mut cache = Cache::new(self.cache_pool.get().await?); let _ = cache .write_to_cache_with_seconds(&cache_key, value, 3_6000) .await?; Ok(()) } async fn del(&self, key: &K) -> Result<(), Self::Error> { let cache_key = create_prefixed_key(ATRIUM_STATE_STORE_KEY, key.as_ref()); let mut cache = self.cache_pool.get().await?; let _: usize = cache.del(cache_key).await?; Ok(()) } async fn clear(&self) -> Result<(), Self::Error> { let pattern = format!("{}*", ATRIUM_STATE_STORE_KEY); let mut cache = self.cache_pool.get().await?; let keys: Vec = cache.keys(pattern).await?; if !keys.is_empty() { let _: usize = cache.del(keys).await?; } Ok(()) } }