Rust · 2630 bytes Raw Blame History
1 //! IPC adapter for garfield (file explorer)
2
3 use crate::ipc::client::{IpcClient, StandardResponse};
4 use crate::ipc::discovery::socket_path_for;
5 use crate::panels::Component;
6 use anyhow::Result;
7 use serde::{Deserialize, Serialize};
8 use serde_json::Value;
9 use std::path::PathBuf;
10
11 /// Commands for garfield
12 #[derive(Debug, Serialize)]
13 #[serde(tag = "command", rename_all = "snake_case")]
14 enum GarfieldCommand {
15 Status,
16 CurrentDir,
17 Open { path: String },
18 }
19
20 /// Adapter for garfield file explorer
21 pub struct GarfieldAdapter {
22 client: IpcClient,
23 }
24
25 impl GarfieldAdapter {
26 pub fn new() -> Self {
27 use std::time::Duration;
28 Self {
29 client: IpcClient::new().with_timeout(Duration::from_secs(5)),
30 }
31 }
32
33 pub fn socket_path(&self) -> PathBuf {
34 socket_path_for(Component::Garfield)
35 }
36
37 pub fn connect(&mut self) -> Result<()> {
38 self.client.connect(&self.socket_path())
39 }
40
41 /// Attempt reconnection with exponential backoff
42 pub fn reconnect(&mut self) -> Result<()> {
43 self.client.reconnect()
44 }
45
46 /// Check if we should attempt reconnection
47 pub fn should_reconnect(&self) -> bool {
48 self.client.should_attempt_reconnect()
49 }
50
51 /// Reset backoff state
52 pub fn reset_backoff(&mut self) {
53 self.client.reset_backoff();
54 }
55
56 pub fn disconnect(&mut self) {
57 self.client.disconnect();
58 }
59
60 pub fn is_connected(&self) -> bool {
61 self.client.is_connected()
62 }
63
64 fn send_command(&mut self, command: GarfieldCommand) -> Result<Option<Value>> {
65 let response: StandardResponse = self.client.send_receive(&command)?;
66 response.into_result()
67 }
68
69 pub fn status(&mut self) -> Result<GarfieldStatus> {
70 let data = self.send_command(GarfieldCommand::Status)?;
71 if let Some(data) = data {
72 Ok(serde_json::from_value(data)?)
73 } else {
74 Ok(GarfieldStatus::default())
75 }
76 }
77
78 pub fn current_dir(&mut self) -> Result<Option<String>> {
79 let data = self.send_command(GarfieldCommand::CurrentDir)?;
80 Ok(data.and_then(|v| v.as_str().map(String::from)))
81 }
82
83 pub fn open(&mut self, path: &str) -> Result<()> {
84 self.send_command(GarfieldCommand::Open {
85 path: path.to_string(),
86 })?;
87 Ok(())
88 }
89 }
90
91 impl Default for GarfieldAdapter {
92 fn default() -> Self {
93 Self::new()
94 }
95 }
96
97 #[derive(Debug, Clone, Default, Deserialize)]
98 pub struct GarfieldStatus {
99 #[serde(default)]
100 pub running: bool,
101 #[serde(default)]
102 pub current_dir: Option<String>,
103 }
104