use std::sync::Arc;
#[derive(Debug, Clone)]
pub struct GatewayDenyReason {
pub message: String,
pub retry_after_seconds: i32,
}
impl GatewayDenyReason {
pub fn new(message: impl Into<String>) -> Self {
Self {
message: message.into(),
retry_after_seconds: 0,
}
}
}
#[async_trait::async_trait]
pub trait GatewayRequestGuard: Send + Sync {
async fn check(&self, pool: &sqlx::PgPool, user_id: &str) -> Result<(), GatewayDenyReason>;
}
#[derive(Debug, Clone, Copy)]
pub struct GatewayRequestGuardRegistration {
pub factory: fn() -> Arc<dyn GatewayRequestGuard>,
}
inventory::collect!(GatewayRequestGuardRegistration);
#[macro_export]
macro_rules! register_gateway_guard {
($guard_type:ty) => {
::inventory::submit! {
$crate::GatewayRequestGuardRegistration {
factory: || ::std::sync::Arc::new(<$guard_type>::default())
as ::std::sync::Arc<dyn $crate::GatewayRequestGuard>,
}
}
};
($guard_expr:expr) => {
::inventory::submit! {
$crate::GatewayRequestGuardRegistration {
factory: || ::std::sync::Arc::new($guard_expr)
as ::std::sync::Arc<dyn $crate::GatewayRequestGuard>,
}
}
};
}
pub async fn run_gateway_guards(
pool: &sqlx::PgPool,
user_id: &str,
) -> Result<(), GatewayDenyReason> {
for registration in inventory::iter::<GatewayRequestGuardRegistration> {
let guard = (registration.factory)();
guard.check(pool, user_id).await?;
}
Ok(())
}