use std::{sync::Arc, time::Duration};
#[cfg(feature = "cacache-storage")]
mod cacache_storage;
mod memory_storage;
#[cfg(feature = "cacache-storage")]
pub use cacache_storage::*;
pub use memory_storage::*;
pub trait CaptchaStorage: Send + Sync + 'static {
type Error: std::error::Error + Send;
fn store_answer(
&self,
answer: String,
) -> impl std::future::Future<Output = Result<String, Self::Error>> + Send;
fn get_answer(
&self,
token: &str,
) -> impl std::future::Future<Output = Result<Option<String>, Self::Error>> + Send;
fn clear_expired(
&self,
expired_after: Duration,
) -> impl std::future::Future<Output = Result<(), Self::Error>> + Send;
fn clear_by_token(
&self,
token: &str,
) -> impl std::future::Future<Output = Result<(), Self::Error>> + Send;
fn new_captcha<G: crate::CaptchaGenerator>(
&self,
generator: G,
) -> impl std::future::Future<
Output = Result<(String, Vec<u8>), either::Either<Self::Error, G::Error>>,
> + Send {
async move {
let (answer, image) = generator.new_captcha().await.map_err(either::Right)?;
Ok((
self.store_answer(answer).await.map_err(either::Left)?,
image,
))
}
}
}
impl<T> CaptchaStorage for Arc<T>
where
T: CaptchaStorage,
{
type Error = T::Error;
fn store_answer(
&self,
answer: String,
) -> impl std::future::Future<Output = Result<String, Self::Error>> + Send {
self.as_ref().store_answer(answer)
}
fn get_answer(
&self,
token: &str,
) -> impl std::future::Future<Output = Result<Option<String>, Self::Error>> + Send {
self.as_ref().get_answer(token)
}
fn clear_expired(
&self,
expired_after: Duration,
) -> impl std::future::Future<Output = Result<(), Self::Error>> + Send {
self.as_ref().clear_expired(expired_after)
}
fn clear_by_token(
&self,
token: &str,
) -> impl std::future::Future<Output = Result<(), Self::Error>> + Send {
self.as_ref().clear_by_token(token)
}
}