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