Skip to main content

nika_daemon/
error.rs

1//! Daemon error types.
2
3use std::path::PathBuf;
4
5/// Errors from the nika daemon.
6#[derive(Debug, thiserror::Error)]
7pub enum DaemonError {
8    #[error("daemon not running (socket not found: {path})")]
9    NotRunning { path: PathBuf },
10
11    #[error("connection failed: {0}")]
12    Connection(#[from] std::io::Error),
13
14    #[error("protocol error: {0}")]
15    Protocol(String),
16
17    #[error("serialization error: {0}")]
18    Serialization(#[from] serde_json::Error),
19
20    #[error("request timed out after {timeout_secs}s")]
21    Timeout { timeout_secs: u64 },
22
23    #[error("daemon already running (pid {pid})")]
24    AlreadyRunning { pid: u32 },
25
26    #[error("stale PID file: process {pid} not alive")]
27    StalePid { pid: u32 },
28
29    #[error("daemon responded with error: [{code}] {message}")]
30    RemoteError { code: String, message: String },
31
32    #[error("message too large: {size} bytes (max {max})")]
33    MessageTooLarge { size: usize, max: usize },
34
35    #[error("lifecycle error: {0}")]
36    Lifecycle(String),
37
38    #[error("watch error: {0}")]
39    Watch(String),
40}
41
42/// Result type alias for daemon operations.
43pub type DaemonResult<T> = std::result::Result<T, DaemonError>;
44
45// ═══════════════════════════════════════════════════════════════════════════
46// TESTS
47// ═══════════════════════════════════════════════════════════════════════════
48
49#[cfg(test)]
50mod tests {
51    use super::*;
52
53    #[test]
54    fn watch_error_display() {
55        let err = DaemonError::Watch("directory not found".into());
56        assert_eq!(err.to_string(), "watch error: directory not found");
57    }
58
59    #[test]
60    fn all_variants_are_debug() {
61        let errors: Vec<DaemonError> = vec![
62            DaemonError::NotRunning {
63                path: PathBuf::from("/tmp/test.sock"),
64            },
65            DaemonError::Protocol("bad frame".into()),
66            DaemonError::Timeout { timeout_secs: 5 },
67            DaemonError::AlreadyRunning { pid: 1234 },
68            DaemonError::StalePid { pid: 5678 },
69            DaemonError::RemoteError {
70                code: "E001".into(),
71                message: "fail".into(),
72            },
73            DaemonError::MessageTooLarge { size: 100, max: 50 },
74            DaemonError::Lifecycle("shutdown".into()),
75            DaemonError::Watch("notify error".into()),
76        ];
77        for err in &errors {
78            // Ensure Display and Debug work
79            let _ = format!("{err}");
80            let _ = format!("{err:?}");
81        }
82    }
83}