use std::sync::Arc;
use arc_swap::ArcSwap;
use awp_types::BusinessContext;
use crate::consent::{ConsentService, InMemoryConsentService};
use crate::events::{EventSubscriptionService, InMemoryEventSubscriptionService};
use crate::health::HealthStateMachine;
use crate::rate_limit::{InMemoryRateLimiter, RateLimiter};
use crate::trust::{DefaultTrustAssigner, TrustLevelAssigner};
#[derive(Clone)]
pub struct AwpState {
pub business_context: Arc<ArcSwap<BusinessContext>>,
pub rate_limiter: Arc<dyn RateLimiter>,
pub consent_service: Arc<dyn ConsentService>,
pub event_service: Arc<dyn EventSubscriptionService>,
pub health: Arc<HealthStateMachine>,
pub trust_assigner: Arc<dyn TrustLevelAssigner>,
}
pub struct AwpStateBuilder {
business_context: Arc<ArcSwap<BusinessContext>>,
rate_limiter: Option<Arc<dyn RateLimiter>>,
consent_service: Option<Arc<dyn ConsentService>>,
event_service: Option<Arc<dyn EventSubscriptionService>>,
trust_assigner: Option<Arc<dyn TrustLevelAssigner>>,
}
impl AwpStateBuilder {
pub fn new(business_context: Arc<ArcSwap<BusinessContext>>) -> Self {
Self {
business_context,
rate_limiter: None,
consent_service: None,
event_service: None,
trust_assigner: None,
}
}
pub fn rate_limiter(mut self, limiter: Arc<dyn RateLimiter>) -> Self {
self.rate_limiter = Some(limiter);
self
}
pub fn consent_service(mut self, service: Arc<dyn ConsentService>) -> Self {
self.consent_service = Some(service);
self
}
pub fn event_service(mut self, service: Arc<dyn EventSubscriptionService>) -> Self {
self.event_service = Some(service);
self
}
pub fn trust_assigner(mut self, assigner: Arc<dyn TrustLevelAssigner>) -> Self {
self.trust_assigner = Some(assigner);
self
}
pub fn build(self) -> AwpState {
let event_service =
self.event_service.unwrap_or_else(|| Arc::new(InMemoryEventSubscriptionService::new()));
AwpState {
business_context: self.business_context,
rate_limiter: self.rate_limiter.unwrap_or_else(|| Arc::new(InMemoryRateLimiter::new())),
consent_service: self
.consent_service
.unwrap_or_else(|| Arc::new(InMemoryConsentService::new())),
health: Arc::new(HealthStateMachine::new(event_service.clone())),
event_service,
trust_assigner: self.trust_assigner.unwrap_or_else(|| Arc::new(DefaultTrustAssigner)),
}
}
}
impl AwpState {
pub fn builder(business_context: Arc<ArcSwap<BusinessContext>>) -> AwpStateBuilder {
AwpStateBuilder::new(business_context)
}
}
#[cfg(test)]
mod tests {
use super::*;
use awp_types::BusinessContext;
fn test_context() -> Arc<ArcSwap<BusinessContext>> {
Arc::new(ArcSwap::from_pointee(BusinessContext::core("Test", "Test site", "example.com")))
}
#[test]
fn test_builder_defaults() {
let state = AwpState::builder(test_context()).build();
assert_eq!(state.business_context.load().site_name, "Test");
}
#[test]
fn test_builder_custom_rate_limiter() {
let limiter = Arc::new(InMemoryRateLimiter::new());
let state = AwpState::builder(test_context()).rate_limiter(limiter).build();
assert_eq!(state.business_context.load().site_name, "Test");
}
#[test]
fn test_builder_custom_consent() {
let consent = Arc::new(InMemoryConsentService::new());
let state = AwpState::builder(test_context()).consent_service(consent).build();
assert_eq!(state.business_context.load().site_name, "Test");
}
#[test]
fn test_builder_custom_events() {
let events = Arc::new(InMemoryEventSubscriptionService::new());
let state = AwpState::builder(test_context()).event_service(events).build();
assert_eq!(state.business_context.load().site_name, "Test");
}
#[test]
fn test_builder_custom_trust() {
let trust = Arc::new(DefaultTrustAssigner);
let state = AwpState::builder(test_context()).trust_assigner(trust).build();
assert_eq!(state.business_context.load().site_name, "Test");
}
#[tokio::test]
async fn test_builder_health_wired_to_events() {
let state = AwpState::builder(test_context()).build();
let snap = state.health.snapshot().await;
assert_eq!(snap.state, crate::health::HealthState::Healthy);
}
#[test]
fn test_builder_all_custom() {
let state = AwpState::builder(test_context())
.rate_limiter(Arc::new(InMemoryRateLimiter::new()))
.consent_service(Arc::new(InMemoryConsentService::new()))
.event_service(Arc::new(InMemoryEventSubscriptionService::new()))
.trust_assigner(Arc::new(DefaultTrustAssigner))
.build();
assert_eq!(state.business_context.load().site_name, "Test");
}
}