1use std::{path::PathBuf, process::ExitStatus};
2
3use synd_protocol::CapabilitySet;
4
5use thiserror::Error;
6
7use crate::DaemonLaunchInfo;
8
9pub type Result<T> = std::result::Result<T, Error>;
10
11#[derive(Debug, Error)]
12pub enum Error {
13 #[error(transparent)]
14 Io(#[from] std::io::Error),
15
16 #[error(transparent)]
17 RegistryDb(#[from] synd_registry::RegistryDbError),
18
19 #[error(transparent)]
20 Migration(#[from] synd_persistence::sqlite::MigrationError),
21
22 #[error(transparent)]
23 Api(Box<synd_client::SyndApiError>),
24
25 #[error(transparent)]
26 RuntimeApi(Box<synd_api::Error>),
27
28 #[error(transparent)]
29 Json(#[from] serde_json::Error),
30
31 #[error("{context} endpoint unavailable: {}", endpoint.display())]
32 EndpointUnavailable {
33 context: &'static str,
34 endpoint: PathBuf,
35 },
36
37 #[error("{context} transport unsupported")]
38 UnsupportedTransport { context: &'static str },
39
40 #[error(
41 "runtime daemon at {} is missing required session capabilities: {missing_capabilities}",
42 endpoint.display()
43 )]
44 MissingSessionCapabilities {
45 endpoint: PathBuf,
46 missing_capabilities: CapabilitySet,
47 },
48
49 #[error("refusing to remove non-socket runtime endpoint {}", path.display())]
50 NonSocketEndpoint { path: PathBuf },
51
52 #[error(
53 "daemon exited before endpoint became ready: {status}; daemon log: {}",
54 launch.log().display()
55 )]
56 DaemonExitedBeforeReady {
57 status: ExitStatus,
58 launch: DaemonLaunchInfo,
59 },
60
61 #[error(
62 "timed out waiting for launched daemon endpoint {} to become ready; daemon log: {}",
63 endpoint.display(),
64 launch.log().display()
65 )]
66 DaemonEndpointReadyTimeout {
67 endpoint: PathBuf,
68 launch: DaemonLaunchInfo,
69 },
70
71 #[error("timed out waiting for daemon endpoint {} to become ready", endpoint.display())]
72 EndpointReadyTimeout { endpoint: PathBuf },
73
74 #[error("timed out waiting for daemon endpoint {} to stop", endpoint.display())]
75 EndpointStopTimeout { endpoint: PathBuf },
76
77 #[error("daemon claim lock is already held at {}", path.display())]
78 DaemonClaimLockAlreadyHeld { path: PathBuf },
79
80 #[error("refusing force shutdown: {reason}")]
81 ForceShutdownRefused { reason: String },
82
83 #[error("timed out force stopping daemon process {pid}")]
84 ForceShutdownTimeout { pid: u32 },
85
86 #[error("runtime daemon is incompatible at {}; {suggestion}", endpoint.display())]
87 IncompatibleRuntimeDaemon {
88 endpoint: PathBuf,
89 suggestion: String,
90 },
91
92 #[error("failed to stop incompatible runtime daemon at {}; {suggestion}", endpoint.display())]
93 IncompatibleRuntimeDaemonShutdown {
94 endpoint: PathBuf,
95 suggestion: String,
96 #[source]
97 source: Box<synd_client::SyndApiError>,
98 },
99
100 #[error("timed out stopping incompatible runtime daemon at {}; {suggestion}", endpoint.display())]
101 IncompatibleRuntimeDaemonStopTimeout {
102 endpoint: PathBuf,
103 suggestion: String,
104 },
105}
106
107impl From<synd_client::SyndApiError> for Error {
108 fn from(source: synd_client::SyndApiError) -> Self {
109 Self::Api(Box::new(source))
110 }
111}
112
113impl From<synd_api::Error> for Error {
114 fn from(source: synd_api::Error) -> Self {
115 Self::RuntimeApi(Box::new(source))
116 }
117}