use crate::config::FlowControlConfig;
use crate::error::LimiteronError;
use crate::governor::Governor;
use std::any::TypeId;
use std::future::Future;
use std::pin::Pin;
use std::sync::Arc;
use trait_kit::prelude::*;
pub struct LimiteronModule;
impl ModuleMeta for LimiteronModule {
const NAME: &'static str = "limiteron";
fn dependencies() -> &'static [(&'static str, TypeId)] {
&[]
}
}
impl AsyncAutoBuilder for LimiteronModule {
type Capability = Arc<Governor>;
type Error = LimiteronError;
fn build<'a>(
kit: &'a AsyncKit,
) -> Pin<Box<dyn Future<Output = Result<Self::Capability, Self::Error>> + Send + 'a>> {
Box::pin(async move {
let config: FlowControlConfig = kit.config().map_err(|e| {
LimiteronError::ConfigError(format!("LimiteronModule: read config: {e}"))
})?;
use crate::storage::{BanStorage, MemoryBanStorage, MemoryStorage, Storage};
let storage: Arc<dyn Storage> = Arc::new(MemoryStorage::new());
let ban_storage: Arc<dyn BanStorage> = Arc::new(MemoryBanStorage::new());
let governor = Governor::builder()
.with_config(config)
.with_storage(storage)
.with_ban_storage(ban_storage)
.build()
.await?;
Ok(Arc::new(governor))
})
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::config::FlowControlConfig;
use crate::governor::Governor;
use std::any::TypeId;
use std::sync::Arc;
fn make_minimal_valid_config() -> FlowControlConfig {
use crate::config::{Action, ActionConfig, LimiterConfig, Matcher, Rule};
let mut config = FlowControlConfig::default();
config.rules.push(Rule {
id: "default".to_string(),
name: "default rule".to_string(),
priority: 0,
matchers: vec![Matcher::User {
user_ids: vec!["user1".to_string()],
}],
limiters: vec![LimiterConfig::TokenBucket {
capacity: 100,
refill_rate: 10,
}],
action: ActionConfig {
on_exceed: Action::Reject,
ban: None,
},
});
config
}
#[test]
fn limiteron_module_meta_name() {
assert_eq!(LimiteronModule::NAME, "limiteron");
}
#[test]
fn limiteron_module_meta_dependencies_empty() {
assert_eq!(
LimiteronModule::dependencies(),
&[] as &[(&'static str, TypeId)]
);
}
#[tokio::test]
async fn limiteron_module_build_returns_governor_capability() {
let mut kit = AsyncKit::new();
kit.set_config(make_minimal_valid_config());
kit.register::<LimiteronModule>()
.expect("register LimiteronModule");
let kit = kit.build().await.expect("AsyncKit::build");
let governor: Arc<Governor> = kit
.require::<LimiteronModule>()
.expect("require LimiteronModule");
let _ = governor;
}
#[tokio::test]
async fn limiteron_module_build_reads_config_from_kit() {
let mut kit = AsyncKit::new();
kit.set_config(make_minimal_valid_config());
kit.register::<LimiteronModule>()
.expect("register LimiteronModule");
let kit = kit.build().await.expect("AsyncKit::build");
let _governor: Arc<Governor> = kit
.require::<LimiteronModule>()
.expect("require LimiteronModule");
}
#[tokio::test]
async fn limiteron_module_build_is_async() {
let kit = AsyncKit::new();
kit.set_config(make_minimal_valid_config());
let fut = <LimiteronModule as AsyncAutoBuilder>::build(&kit);
let _governor: Arc<Governor> = fut.await.expect("build future resolves");
fn assert_send_sync<T: Send + Sync>() {}
assert_send_sync::<Arc<Governor>>();
}
}