omni_dev/daemon/services/
echo.rs1use anyhow::{bail, Result};
6use async_trait::async_trait;
7use serde_json::Value;
8
9use crate::daemon::service::{DaemonService, MenuItem, MenuSnapshot, ServiceStatus};
10
11#[derive(Debug, Clone, Copy, Default)]
13pub struct EchoService;
14
15#[async_trait]
16impl DaemonService for EchoService {
17 fn name(&self) -> &'static str {
18 "echo"
19 }
20
21 async fn handle(&self, op: &str, payload: Value) -> Result<Value> {
22 match op {
23 "echo" => Ok(payload),
24 other => bail!("unknown echo op: {other}"),
25 }
26 }
27
28 fn menu(&self) -> MenuSnapshot {
29 MenuSnapshot {
30 title: "Echo".to_string(),
31 items: vec![MenuItem::Label("ready".to_string())],
32 }
33 }
34
35 async fn menu_action(&self, _action_id: &str) -> Result<()> {
36 Ok(())
37 }
38
39 async fn status(&self) -> ServiceStatus {
40 ServiceStatus {
41 name: self.name().to_string(),
42 healthy: true,
43 summary: "ready".to_string(),
44 detail: Value::Null,
45 }
46 }
47
48 async fn shutdown(&self) {}
49}
50
51#[cfg(test)]
52#[allow(clippy::unwrap_used, clippy::expect_used)]
53mod tests {
54 use super::*;
55 use serde_json::json;
56
57 #[tokio::test]
58 async fn echo_service_round_trips_and_reports() {
59 let svc = EchoService;
60 assert_eq!(svc.name(), "echo");
61 assert_eq!(
63 svc.handle("echo", json!({ "a": 1 })).await.unwrap(),
64 json!({ "a": 1 })
65 );
66 assert!(svc.handle("nope", Value::Null).await.is_err());
67 assert_eq!(svc.menu().title, "Echo");
69 svc.menu_action("anything").await.unwrap();
70 let status = svc.status().await;
71 assert_eq!(status.name, "echo");
72 assert!(status.healthy);
73 svc.shutdown().await;
74 }
75}