notedthat_api_http/
state.rs1use notedthat_core::{
4 AccessPolicy, Authenticator, EventPublisher, EventSource, KbDetails, KbSlug, Storage,
5};
6use notedthat_indexer::{IndexHealth, Searcher};
7
8use crate::readiness::ReadinessReceiver;
9use std::collections::BTreeMap;
10use std::sync::Arc;
11
12#[derive(Clone)]
16pub struct AppState {
17 pub storage: Arc<dyn Storage>,
19 pub declared_kbs: Arc<BTreeMap<String, KbSlug>>,
21 pub access_policies: Arc<BTreeMap<String, Arc<AccessPolicy>>>,
26 pub kb_details: Arc<BTreeMap<String, KbDetails>>,
29 pub authenticator: Arc<Authenticator>,
31 pub max_body_size: u64,
33 pub max_patchable_size: u64,
35 pub indexer_tx: tokio::sync::mpsc::Sender<notedthat_indexer::IndexEvent>,
37 pub searcher: Arc<dyn Searcher>,
39 pub events: Option<Arc<dyn EventPublisher>>,
43 pub index_health: Arc<IndexHealth>,
46 pub readiness: ReadinessReceiver,
49}
50
51impl AppState {
52 pub(crate) fn sinks(&self, source: EventSource) -> notedthat_write::WriteSinks<'_> {
55 notedthat_write::WriteSinks::new(
56 &self.indexer_tx,
57 self.events.as_deref(),
58 &self.index_health,
59 source,
60 )
61 }
62}
63
64#[cfg(test)]
65mod tests {
66 use super::*;
67 use crate::testing::InMemoryStorage;
68 use std::collections::BTreeMap;
69 use std::sync::Arc;
70
71 fn minimal_state(tx: tokio::sync::mpsc::Sender<notedthat_indexer::IndexEvent>) -> AppState {
72 AppState {
73 storage: Arc::new(InMemoryStorage::default()),
74 declared_kbs: Arc::new(BTreeMap::new()),
75 access_policies: Arc::new(BTreeMap::new()),
76 kb_details: Arc::new(BTreeMap::new()),
77 authenticator: Arc::new(Authenticator::new("token")),
78 max_body_size: 1024,
79 max_patchable_size: 1024,
80 indexer_tx: tx,
81 searcher: Arc::new(crate::testing::NoopSearcher),
82 events: None,
83 index_health: Arc::new(notedthat_indexer::IndexHealth::new()),
84 readiness: crate::testing::ready_receiver(),
85 }
86 }
87
88 #[tokio::test]
89 async fn clone_shares_same_channel() {
90 let (tx, mut rx) = tokio::sync::mpsc::channel(10);
91 let state = minimal_state(tx);
92 let cloned = state.clone();
93
94 let event = notedthat_indexer::IndexEvent::Tombstone {
95 kb: notedthat_core::KbSlug::try_new("test").expect("valid kb slug"),
96 object_key: notedthat_core::ObjectPath::try_from("a.md").expect("valid path"),
97 };
98 cloned
99 .indexer_tx
100 .send(event.clone())
101 .await
102 .expect("send on cloned tx");
103
104 let received = rx.recv().await.expect("receive on original rx");
105 assert_eq!(
106 received, event,
107 "cloned Sender must share the same underlying channel"
108 );
109 }
110}