gardesk/gartray / 22f9d66

Browse files

Implement IPC client in gartrayctl

Authored by mfwolffe <wolffemf@dukes.jmu.edu>
SHA
22f9d667cd3fd87e6900f99caf6615dab0b8d891
Parents
e97dde5
Tree
1c8a8d1

3 changed files

StatusFile+-
M gartrayctl/Cargo.toml 3 0
A gartrayctl/src/ipc.rs 79 0
M gartrayctl/src/main.rs 3 4
gartrayctl/Cargo.tomlmodified
@@ -19,3 +19,6 @@ clap = { workspace = true }
1919
 
2020
 # Error handling
2121
 anyhow = { workspace = true }
22
+
23
+# System paths
24
+dirs = { workspace = true }
gartrayctl/src/ipc.rsadded
@@ -0,0 +1,79 @@
1
+//! IPC client for communicating with gartray daemon
2
+
3
+use anyhow::{Context, Result};
4
+use serde::{Deserialize, Serialize};
5
+use std::io::{BufRead, BufReader, Write};
6
+use std::os::unix::net::UnixStream;
7
+use std::path::PathBuf;
8
+
9
+/// Get the path to the IPC socket
10
+fn socket_path() -> PathBuf {
11
+    dirs::runtime_dir()
12
+        .unwrap_or_else(|| PathBuf::from("/tmp"))
13
+        .join("gartray.sock")
14
+}
15
+
16
+/// IPC commands (must match daemon)
17
+#[derive(Debug, Clone, Serialize, Deserialize)]
18
+#[serde(tag = "command", rename_all = "snake_case")]
19
+pub enum Command {
20
+    Show,
21
+    Hide,
22
+    Toggle,
23
+    Reload,
24
+    Status,
25
+    Quit,
26
+}
27
+
28
+/// IPC response
29
+#[derive(Debug, Clone, Serialize, Deserialize)]
30
+pub struct Response {
31
+    pub success: bool,
32
+    pub message: Option<String>,
33
+    pub data: Option<serde_json::Value>,
34
+}
35
+
36
+/// Send a command to the running daemon
37
+pub fn send_command(command: &str) -> Result<()> {
38
+    let path = socket_path();
39
+
40
+    if !path.exists() {
41
+        anyhow::bail!("gartray daemon not running (socket not found)");
42
+    }
43
+
44
+    let mut stream = UnixStream::connect(&path)
45
+        .with_context(|| "Failed to connect to gartray daemon")?;
46
+
47
+    let cmd = match command {
48
+        "show" => Command::Show,
49
+        "hide" => Command::Hide,
50
+        "toggle" => Command::Toggle,
51
+        "reload" => Command::Reload,
52
+        "status" => Command::Status,
53
+        "quit" => Command::Quit,
54
+        _ => anyhow::bail!("Unknown command: {}", command),
55
+    };
56
+
57
+    let cmd_json = serde_json::to_string(&cmd)?;
58
+    writeln!(stream, "{}", cmd_json)?;
59
+    stream.flush()?;
60
+
61
+    // Read response
62
+    let mut reader = BufReader::new(stream);
63
+    let mut response_line = String::new();
64
+    reader.read_line(&mut response_line)?;
65
+
66
+    let response: Response = serde_json::from_str(&response_line)?;
67
+    if response.success {
68
+        if let Some(msg) = response.message {
69
+            println!("{}", msg);
70
+        } else {
71
+            println!("OK");
72
+        }
73
+    } else {
74
+        eprintln!("Error: {}", response.message.unwrap_or_default());
75
+        std::process::exit(1);
76
+    }
77
+
78
+    Ok(())
79
+}
gartrayctl/src/main.rsmodified
@@ -3,6 +3,8 @@
33
 use anyhow::Result;
44
 use clap::{Parser, Subcommand};
55
 
6
+mod ipc;
7
+
68
 /// gartrayctl - Control the gartray daemon
79
 #[derive(Parser)]
810
 #[command(name = "gartrayctl")]
@@ -40,8 +42,5 @@ fn main() -> Result<()> {
4042
         Commands::Quit => "quit",
4143
     };
4244
 
43
-    // TODO: Implement Unix socket IPC to daemon
44
-    println!("Would send command: {}", command);
45
-
46
-    Ok(())
45
+    ipc::send_command(command)
4746
 }