omni_dev/daemon/
registry.rs1use std::sync::Arc;
4
5use anyhow::{anyhow, Result};
6use serde_json::Value;
7
8use super::service::{DaemonService, ServiceStatus};
9
10#[derive(Clone, Default)]
13pub struct ServiceRegistry {
14 services: Vec<Arc<dyn DaemonService>>,
15}
16
17impl ServiceRegistry {
18 pub fn new() -> Self {
20 Self::default()
21 }
22
23 pub fn register(&mut self, service: Arc<dyn DaemonService>) {
28 let name = service.name();
29 if self.services.iter().any(|s| s.name() == name) {
30 tracing::warn!("ignoring duplicate registration of daemon service `{name}`");
31 return;
32 }
33 self.services.push(service);
34 }
35
36 pub fn get(&self, name: &str) -> Option<&Arc<dyn DaemonService>> {
38 self.services.iter().find(|s| s.name() == name)
39 }
40
41 pub fn services(&self) -> &[Arc<dyn DaemonService>] {
43 &self.services
44 }
45
46 pub async fn dispatch(&self, service: &str, op: &str, payload: Value) -> Result<Value> {
49 let svc = self
50 .get(service)
51 .ok_or_else(|| anyhow!("unknown service: {service}"))?;
52 svc.handle(op, payload).await
53 }
54
55 pub async fn statuses(&self) -> Vec<ServiceStatus> {
57 let mut out = Vec::with_capacity(self.services.len());
58 for svc in &self.services {
59 out.push(svc.status().await);
60 }
61 out
62 }
63
64 pub async fn shutdown_all(&self) {
66 for svc in &self.services {
67 svc.shutdown().await;
68 }
69 }
70}
71
72#[cfg(test)]
73#[allow(clippy::unwrap_used, clippy::expect_used)]
74mod tests {
75 use super::*;
76 use crate::daemon::services::echo::EchoService;
77 use serde_json::json;
78
79 #[tokio::test]
80 async fn routes_known_service_and_rejects_unknown() {
81 let mut registry = ServiceRegistry::new();
82 assert!(registry.services().is_empty());
83 registry.register(Arc::new(EchoService));
84
85 assert!(registry.get("echo").is_some());
86 assert!(registry.get("missing").is_none());
87
88 assert_eq!(
90 registry
91 .dispatch("echo", "echo", json!({ "x": 1 }))
92 .await
93 .unwrap(),
94 json!({ "x": 1 })
95 );
96 let err = registry
97 .dispatch("missing", "echo", Value::Null)
98 .await
99 .unwrap_err();
100 assert!(err.to_string().contains("unknown service"));
101
102 assert_eq!(registry.statuses().await.len(), 1);
104 registry.shutdown_all().await;
105 }
106
107 #[test]
108 fn duplicate_registration_is_ignored() {
109 let mut registry = ServiceRegistry::new();
110 registry.register(Arc::new(EchoService));
111 registry.register(Arc::new(EchoService));
112 assert_eq!(registry.services().len(), 1);
115 }
116}