Skip to main content

futu_backend/auth/commconfig/
snapshot.rs

1//! Shared CommConfig snapshot boundary.
2
3use std::collections::HashMap;
4use std::sync::Arc;
5
6use arc_swap::{ArcSwap, Guard};
7use tokio::sync::watch;
8
9use super::types::{CommConfigSource, CommonConfigSnapshot};
10
11/// Atomically published complete CommConfig snapshot plus generation events.
12///
13/// Readers keep the existing lock-free `load` / `load_full` API. Writers must
14/// use `store`, which publishes the snapshot first and then wakes lifecycle
15/// actors that need to react to connection-target changes.
16pub struct CommConfigSnapshotStore {
17    current: ArcSwap<CommonConfigSnapshot>,
18    generation_tx: watch::Sender<u64>,
19}
20
21impl std::fmt::Debug for CommConfigSnapshotStore {
22    fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
23        formatter
24            .debug_struct("CommConfigSnapshotStore")
25            .field("generation", &self.current.load().generation)
26            .finish_non_exhaustive()
27    }
28}
29
30impl CommConfigSnapshotStore {
31    fn new(snapshot: CommonConfigSnapshot) -> Self {
32        let generation = snapshot.generation;
33        let (generation_tx, _) = watch::channel(generation);
34        Self {
35            current: ArcSwap::new(Arc::new(snapshot)),
36            generation_tx,
37        }
38    }
39
40    #[must_use]
41    pub fn load(&self) -> Guard<Arc<CommonConfigSnapshot>> {
42        self.current.load()
43    }
44
45    #[must_use]
46    pub fn load_full(&self) -> Arc<CommonConfigSnapshot> {
47        self.current.load_full()
48    }
49
50    pub fn store(&self, snapshot: Arc<CommonConfigSnapshot>) {
51        let generation = snapshot.generation;
52        self.current.store(snapshot);
53        self.generation_tx.send_replace(generation);
54    }
55
56    #[must_use]
57    pub fn subscribe_generation(&self) -> watch::Receiver<u64> {
58        self.generation_tx.subscribe()
59    }
60}
61
62pub type SharedCommConfig = Arc<CommConfigSnapshotStore>;
63
64#[must_use]
65pub fn new_shared_snapshot(snapshot: CommonConfigSnapshot) -> SharedCommConfig {
66    Arc::new(CommConfigSnapshotStore::new(snapshot))
67}
68
69/// Empty startup snapshot used only when no valid persisted last-good exists.
70pub fn empty_snapshot() -> CommonConfigSnapshot {
71    CommonConfigSnapshot {
72        source: CommConfigSource::Empty,
73        generation: 0,
74        guaranteed_ip: HashMap::new(),
75        guaranteed_ip_broker: HashMap::new(),
76        guaranteed_ip_web: HashMap::new(),
77        web_conn_identity: None,
78        auth_guaranteed_domains: HashMap::new(),
79        auth_guaranteed_domains_configured: false,
80        forced_ip: HashMap::new(),
81        next_refresh_ts: 0,
82    }
83}