Skip to main content

pitchfork_cli/ipc/
mod.rs

1use crate::Result;
2use crate::daemon::{Daemon, RunOptions};
3use crate::env;
4use interprocess::local_socket::{GenericFilePath, Name, ToFsName};
5use miette::{Context, IntoDiagnostic};
6use std::path::PathBuf;
7
8pub(crate) mod batch;
9pub(crate) mod client;
10pub(crate) mod server;
11
12// #[derive(Debug, Clone, serde::Serialize, serde::Deserialize, strum::Display, strum::EnumIs)]
13// pub enum IpcMessage {
14//     Connect(String),
15//     ConnectOK,
16//     Run(String, Vec<String>),
17//     Stop(String),
18//     DaemonAlreadyRunning(String),
19//     DaemonAlreadyStopped(String),
20//     DaemonStart(Daemon),
21//     DaemonStop { name: String },
22//     DaemonFailed { name: String, error: String },
23//     Response(String),
24// }
25
26#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, strum::Display, strum::EnumIs)]
27#[allow(clippy::large_enum_variant)]
28pub enum IpcRequest {
29    Connect,
30    Clean,
31    Stop {
32        id: String,
33    },
34    GetActiveDaemons,
35    GetDisabledDaemons,
36    Run(RunOptions),
37    Enable {
38        id: String,
39    },
40    Disable {
41        id: String,
42    },
43    UpdateShellDir {
44        shell_pid: u32,
45        dir: PathBuf,
46    },
47    GetNotifications,
48    /// Invalid request (failed to deserialize)
49    #[serde(skip)]
50    Invalid {
51        error: String,
52    },
53}
54
55#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, strum::Display, strum::EnumIs)]
56pub enum IpcResponse {
57    Ok,
58    Yes,
59    No,
60    Error(String),
61    Notifications(Vec<(log::LevelFilter, String)>),
62    ActiveDaemons(Vec<Daemon>),
63    DisabledDaemons(Vec<String>),
64    DaemonAlreadyRunning,
65    DaemonStart {
66        daemon: Daemon,
67    },
68    DaemonFailed {
69        error: String,
70    },
71    DaemonReady {
72        daemon: Daemon,
73    },
74    DaemonFailedWithCode {
75        exit_code: Option<i32>,
76    },
77    /// Process was not running but had a PID record (unexpected exit)
78    DaemonWasNotRunning,
79    /// Failed to kill the process (still running)
80    DaemonStopFailed {
81        error: String,
82    },
83    /// Daemon exists but is not running (no PID)
84    DaemonNotRunning,
85    DaemonNotFound,
86}
87fn fs_name(name: &str) -> Result<Name<'_>> {
88    let path = env::IPC_SOCK_DIR.join(name).with_extension("sock");
89    let fs_name = path.to_fs_name::<GenericFilePath>().into_diagnostic()?;
90    Ok(fs_name)
91}
92
93fn serialize<T: serde::Serialize>(msg: &T) -> Result<Vec<u8>> {
94    if *env::IPC_JSON {
95        serde_json::to_vec(msg)
96            .into_diagnostic()
97            .wrap_err("failed to serialize IPC message as JSON")
98    } else {
99        rmp_serde::to_vec(msg)
100            .into_diagnostic()
101            .wrap_err("failed to serialize IPC message as MessagePack")
102    }
103}
104
105fn deserialize<T: serde::de::DeserializeOwned>(bytes: &[u8]) -> Result<T> {
106    let mut bytes = bytes.to_vec();
107    bytes.pop();
108    let preview = std::str::from_utf8(&bytes).unwrap_or("<binary>");
109    trace!("msg: {preview:?}");
110    if *env::IPC_JSON {
111        serde_json::from_slice(&bytes)
112            .into_diagnostic()
113            .wrap_err("failed to deserialize IPC JSON response")
114    } else {
115        rmp_serde::from_slice(&bytes)
116            .into_diagnostic()
117            .wrap_err("failed to deserialize IPC MessagePack response")
118    }
119}