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