1use std::sync::Arc;
11use std::time::Duration;
12
13use axum::http::HeaderMap;
14use brain_db_sdk::BrainClient;
15
16use crate::config::EdgeConfig;
17use crate::error::ApiError;
18use crate::pool::{BrainPool, BrainPoolConfig};
19use crate::port::{
20 BearerResolver, CredentialResolver, MeterEvent, MeteringSink, NoopMeter, Outcome,
21 ResolvedCredential,
22};
23
24#[derive(Clone)]
26pub struct EdgeState {
27 inner: Arc<Inner>,
28}
29
30impl std::fmt::Debug for EdgeState {
31 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
34 f.debug_struct("EdgeState")
35 .field("pool", &self.inner.pool)
36 .finish_non_exhaustive()
37 }
38}
39
40struct Inner {
41 pool: BrainPool,
42 resolver: Arc<dyn CredentialResolver>,
43 meter: Arc<dyn MeteringSink>,
44}
45
46impl EdgeState {
47 #[must_use]
49 pub fn new(config: EdgeConfig) -> Self {
50 Self::with_ports(config, Arc::new(BearerResolver), Arc::new(NoopMeter))
51 }
52
53 #[must_use]
56 pub fn with_ports(
57 config: EdgeConfig,
58 resolver: Arc<dyn CredentialResolver>,
59 meter: Arc<dyn MeteringSink>,
60 ) -> Self {
61 let pool = BrainPool::new(BrainPoolConfig {
62 brain_addr: config.brain_addr,
63 pool_size: config.pool_size,
64 max_credentials: config.max_credentials,
65 idle_ttl: Duration::from_secs(config.idle_ttl_secs),
66 });
67 Self {
68 inner: Arc::new(Inner {
69 pool,
70 resolver,
71 meter,
72 }),
73 }
74 }
75
76 pub async fn resolve(&self, headers: &HeaderMap) -> Result<ResolvedCredential, ApiError> {
81 self.inner.resolver.resolve(headers).await
82 }
83
84 pub fn record(&self, op: &str, ident: &ResolvedCredential, outcome: Outcome) {
86 self.inner.meter.record(&MeterEvent {
87 tenant: ident.tenant.as_deref(),
88 op,
89 outcome,
90 });
91 }
92
93 pub async fn client_for(&self, credential: &str) -> Result<Arc<BrainClient>, ApiError> {
99 self.inner
100 .pool
101 .client_for(credential)
102 .await
103 .map_err(|e| ApiError::from_brain(&e))
104 }
105
106 #[must_use]
109 pub fn pool(&self) -> &BrainPool {
110 &self.inner.pool
111 }
112
113 #[must_use]
116 pub fn meter(&self) -> Arc<dyn MeteringSink> {
117 Arc::clone(&self.inner.meter)
118 }
119}