Skip to main content

myko/server/
handler_registry.rs

1//! Handler registry for the cell-based server.
2//!
3//! Collects all Item, Query, and Report registrations from inventory
4//! and provides lookup by type/id.
5
6use std::sync::Arc;
7
8use crate::{
9    command::CommandHandlerRegistration,
10    item::{IngestBufferPolicy, IngestBufferRegistration, ItemParseFn, ItemRegistration},
11    query::{QueryCellFactory, QueryParseFn, QueryRegistration},
12    report::{ReportCellFactory, ReportParseFn, ReportRegistration},
13    view::{ViewCellFactory, ViewParseFn, ViewRegistration},
14};
15
16// AHash on the dispatch maps below: every wire-routed command/query/view/
17// report/event hits one of these. Bench: ~3.1× faster std HashMap lookups
18// vs default SipHash on Arc<str> keys.
19type AMap<K, V> = std::collections::HashMap<K, V, ahash::RandomState>;
20
21/// Stored query registration data.
22pub struct StoredQueryData {
23    pub query_id: Arc<str>,
24    pub query_item_type: Arc<str>,
25    pub parse: QueryParseFn,
26    pub cell_factory: QueryCellFactory,
27}
28
29/// Stored view registration data.
30pub struct StoredViewData {
31    pub view_id: Arc<str>,
32    pub view_item_type: Arc<str>,
33    pub parse: ViewParseFn,
34    pub cell_factory: ViewCellFactory,
35}
36
37/// Stored report registration data.
38pub struct StoredReportData {
39    pub report_id: Arc<str>,
40    pub parse: ReportParseFn,
41    pub cell_factory: ReportCellFactory,
42}
43
44/// Registry of all handlers for the cell-based server.
45///
46/// Collects registrations from inventory at construction time
47/// and provides O(1) lookup by type/id.
48pub struct HandlerRegistry {
49    /// Item parse functions by entity type name
50    item_parsers: AMap<Arc<str>, ItemParseFn>,
51    /// Optional ingest buffering policy by entity type name
52    item_buffer_policies: AMap<Arc<str>, IngestBufferPolicy>,
53    /// Query data by query id
54    query_data: AMap<Arc<str>, StoredQueryData>,
55    /// View data by view id
56    view_data: AMap<Arc<str>, StoredViewData>,
57    /// Report data by report id
58    report_data: AMap<Arc<str>, StoredReportData>,
59}
60
61impl HandlerRegistry {
62    /// Create a new handler registry by collecting all registrations from inventory.
63    pub fn new() -> Self {
64        let mut item_parsers = AMap::default();
65        let mut item_buffer_policies = AMap::default();
66        let mut query_data = AMap::default();
67        let mut view_data = AMap::default();
68        let mut report_data = AMap::default();
69
70        // Collect item registrations
71        for registration in inventory::iter::<ItemRegistration> {
72            log::trace!("Registered item parser: {}", registration.entity_type);
73            item_parsers.insert(registration.entity_type.into(), registration.parse);
74        }
75
76        for registration in inventory::iter::<IngestBufferRegistration> {
77            log::trace!(
78                "Registered ingest buffer policy: {} -> {:?}",
79                registration.entity_type,
80                registration.policy
81            );
82            item_buffer_policies.insert(registration.entity_type.into(), registration.policy);
83        }
84
85        // Collect query registrations
86        for registration in inventory::iter::<QueryRegistration> {
87            log::trace!("Registered query: {}", registration.query_id);
88            let data = StoredQueryData {
89                query_id: registration.query_id.into(),
90                query_item_type: registration.query_item_type.into(),
91                parse: registration.parse,
92                cell_factory: registration.cell_factory,
93            };
94            query_data.insert(data.query_id.clone(), data);
95        }
96
97        // Collect view registrations
98        for registration in inventory::iter::<ViewRegistration> {
99            log::trace!("Registered view: {}", registration.view_id);
100            let data = StoredViewData {
101                view_id: registration.view_id.into(),
102                view_item_type: registration.view_item_type.into(),
103                parse: registration.parse,
104                cell_factory: registration.cell_factory,
105            };
106            view_data.insert(data.view_id.clone(), data);
107        }
108
109        // Collect report registrations
110        for registration in inventory::iter::<ReportRegistration> {
111            log::trace!("Registered report: {}", registration.report_id);
112            let data = StoredReportData {
113                report_id: registration.report_id.into(),
114                parse: registration.parse,
115                cell_factory: registration.cell_factory,
116            };
117            report_data.insert(data.report_id.clone(), data);
118        }
119
120        // Collect command handler names for logging
121        let mut command_ids: Vec<&str> = inventory::iter::<CommandHandlerRegistration>()
122            .map(|r| r.command_id)
123            .collect();
124        command_ids.sort_unstable();
125
126        fn format_list<'a>(keys: impl Iterator<Item = &'a Arc<str>>) -> String {
127            let mut items: Vec<&str> = keys.map(|k| k.as_ref()).collect();
128            items.sort_unstable();
129            if items.is_empty() {
130                "(none)".to_string()
131            } else {
132                items.join(", ")
133            }
134        }
135
136        fn format_str_list(items: &[&str]) -> String {
137            if items.is_empty() {
138                "(none)".to_string()
139            } else {
140                items.join(", ")
141            }
142        }
143
144        log::trace!(
145            "HandlerRegistry initialized:\n  Items ({}):\n    {}\n  Queries ({}):\n    {}\n  Views ({}):\n    {}\n  Reports ({}):\n    {}\n  Commands ({}):\n    {}",
146            item_parsers.len(),
147            format_list(item_parsers.keys()),
148            query_data.len(),
149            format_list(query_data.keys()),
150            view_data.len(),
151            format_list(view_data.keys()),
152            report_data.len(),
153            format_list(report_data.keys()),
154            command_ids.len(),
155            format_str_list(&command_ids),
156        );
157
158        Self {
159            item_parsers,
160            item_buffer_policies,
161            query_data,
162            view_data,
163            report_data,
164        }
165    }
166
167    /// Get an item parse function by entity type name.
168    pub fn get_item_parser(&self, entity_type: &str) -> Option<ItemParseFn> {
169        self.item_parsers.get(entity_type).copied()
170    }
171
172    /// Get the ingest buffering policy for an entity type.
173    pub fn get_item_buffer_policy(&self, entity_type: &str) -> IngestBufferPolicy {
174        self.item_buffer_policies
175            .get(entity_type)
176            .copied()
177            .unwrap_or(IngestBufferPolicy::None)
178    }
179
180    /// Get query registration data by query id.
181    pub fn get_query(&self, query_id: &str) -> Option<&StoredQueryData> {
182        self.query_data.get(query_id)
183    }
184
185    /// Get report registration data by report id.
186    pub fn get_report(&self, report_id: &str) -> Option<&StoredReportData> {
187        self.report_data.get(report_id)
188    }
189
190    /// Get view registration data by view id.
191    pub fn get_view(&self, view_id: &str) -> Option<&StoredViewData> {
192        self.view_data.get(view_id)
193    }
194
195    /// Check if an entity type has a registered parser.
196    pub fn has_item_parser(&self, entity_type: &str) -> bool {
197        self.item_parsers.contains_key(entity_type)
198    }
199
200    /// Get all registered entity type names.
201    pub fn entity_types(&self) -> impl Iterator<Item = &Arc<str>> {
202        self.item_parsers.keys()
203    }
204
205    /// Get all registered query ids.
206    pub fn query_ids(&self) -> impl Iterator<Item = &Arc<str>> {
207        self.query_data.keys()
208    }
209
210    /// Get all registered report ids.
211    pub fn report_ids(&self) -> impl Iterator<Item = &Arc<str>> {
212        self.report_data.keys()
213    }
214
215    /// Get all registered view ids.
216    pub fn view_ids(&self) -> impl Iterator<Item = &Arc<str>> {
217        self.view_data.keys()
218    }
219}
220
221impl Default for HandlerRegistry {
222    fn default() -> Self {
223        Self::new()
224    }
225}
226
227#[cfg(test)]
228mod tests {
229    use super::*;
230
231    #[test]
232    fn test_registry_creation() {
233        // Just verify it doesn't panic - actual registrations depend on linked crates
234        let registry = HandlerRegistry::new();
235        // Registry should be created without error
236        let _ = registry.entity_types().count();
237    }
238}