omni_dev/daemon/
registry.rs1use std::sync::Arc;
4
5use anyhow::{anyhow, Result};
6use serde_json::Value;
7
8use super::service::{DaemonService, ServiceStatus, ServiceStream};
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 fn subscribe(
60 &self,
61 service: &str,
62 op: &str,
63 payload: &Value,
64 ) -> Option<Box<dyn ServiceStream>> {
65 self.get(service)?.subscribe(op, payload)
66 }
67
68 pub async fn statuses(&self) -> Vec<ServiceStatus> {
70 let mut out = Vec::with_capacity(self.services.len());
71 for svc in &self.services {
72 out.push(svc.status().await);
73 }
74 out
75 }
76
77 pub async fn shutdown_all(&self) {
79 for svc in &self.services {
80 svc.shutdown().await;
81 }
82 }
83}
84
85#[cfg(test)]
86#[allow(clippy::unwrap_used, clippy::expect_used)]
87mod tests {
88 use super::*;
89 use crate::daemon::services::echo::EchoService;
90 use serde_json::json;
91
92 #[tokio::test]
93 async fn routes_known_service_and_rejects_unknown() {
94 let mut registry = ServiceRegistry::new();
95 assert!(registry.services().is_empty());
96 registry.register(Arc::new(EchoService));
97
98 assert!(registry.get("echo").is_some());
99 assert!(registry.get("missing").is_none());
100
101 assert_eq!(
103 registry
104 .dispatch("echo", "echo", json!({ "x": 1 }))
105 .await
106 .unwrap(),
107 json!({ "x": 1 })
108 );
109 let err = registry
110 .dispatch("missing", "echo", Value::Null)
111 .await
112 .unwrap_err();
113 assert!(err.to_string().contains("unknown service"));
114
115 assert_eq!(registry.statuses().await.len(), 1);
117 registry.shutdown_all().await;
118 }
119
120 #[test]
121 fn duplicate_registration_is_ignored() {
122 let mut registry = ServiceRegistry::new();
123 registry.register(Arc::new(EchoService));
124 registry.register(Arc::new(EchoService));
125 assert_eq!(registry.services().len(), 1);
128 }
129}