taiga_plugin_api/daemon/
client.rs1use super::ipc::{receive_message, send_message, spawn_daemon_process, DaemonSpawnConfig};
6use super::socket;
7use crate::PluginError;
8use serde::{Deserialize, Serialize};
9use std::time::Duration;
10
11#[derive(Debug, Clone)]
13pub struct DaemonClientConfig {
14 pub socket_path: String,
16 pub daemon_spawn: DaemonSpawnConfig,
18 pub startup_wait_ms: u64,
20 pub buffer_size: usize,
22}
23
24impl DaemonClientConfig {
25 pub fn new(
27 socket_path: impl Into<String>,
28 daemon_spawn: DaemonSpawnConfig,
29 ) -> Self {
30 Self {
31 socket_path: socket_path.into(),
32 daemon_spawn,
33 startup_wait_ms: 500,
34 buffer_size: 1024,
35 }
36 }
37
38 pub fn with_startup_wait(mut self, wait_ms: u64) -> Self {
40 self.startup_wait_ms = wait_ms;
41 self
42 }
43
44 pub fn with_buffer_size(mut self, size: usize) -> Self {
46 self.buffer_size = size;
47 self
48 }
49}
50
51pub async fn send_command_with_autospawn<Cmd, Resp>(
70 config: &DaemonClientConfig,
71 command: &Cmd,
72) -> Result<Resp, PluginError>
73where
74 Cmd: Serialize,
75 Resp: for<'de> Deserialize<'de>,
76{
77 let stream_result = socket::connect(&config.socket_path).await;
78
79 let mut stream = match stream_result {
80 Ok(s) => s,
81 Err(conn_err) => {
82 println!("Daemon not running. Starting it...");
84 spawn_daemon_process(&config.daemon_spawn)
85 .map_err(PluginError::daemon_not_running_with_source)?;
86
87 tokio::time::sleep(Duration::from_millis(config.startup_wait_ms)).await;
89
90 socket::connect(&config.socket_path).await.map_err(|_| {
92 PluginError::ipc_connection_with_source(
94 "Failed to connect after starting daemon",
95 conn_err,
96 )
97 })?
98 }
99 };
100
101 send_message(&mut stream, command).await?;
103 let resp: Resp = receive_message(&mut stream, config.buffer_size).await?;
104
105 Ok(resp)
106}
107
108#[cfg(test)]
109mod tests {
110 use super::*;
111
112 #[test]
113 fn test_daemon_client_config_creation() {
114 let spawn_config = DaemonSpawnConfig::new("test", "daemon");
115 let client_config = DaemonClientConfig::new("/tmp/test.sock", spawn_config);
116 assert_eq!(client_config.socket_path, "/tmp/test.sock");
117 assert_eq!(client_config.startup_wait_ms, 500);
118 assert_eq!(client_config.buffer_size, 1024);
119 }
120
121 #[test]
122 fn test_daemon_client_config_with_options() {
123 let spawn_config = DaemonSpawnConfig::new("test", "daemon");
124 let client_config = DaemonClientConfig::new("/tmp/test.sock", spawn_config)
125 .with_startup_wait(1000)
126 .with_buffer_size(2048);
127 assert_eq!(client_config.startup_wait_ms, 1000);
128 assert_eq!(client_config.buffer_size, 2048);
129 }
130}