Development Documentation (main branch) - For stable release docs, see docs.rs/eidetica

eidetica/sync/
error.rs

1//! Error types for the synchronization module.
2
3use thiserror::Error;
4
5use super::peer_types::Address;
6use crate::{auth::Permission, entry::ID};
7
8/// Errors that can occur during synchronization operations.
9#[derive(Debug, Error)]
10#[non_exhaustive]
11pub enum SyncError {
12    /// No transport has been enabled for network operations.
13    #[error("No transport enabled. Call enable_http_transport() first")]
14    NoTransportEnabled,
15
16    /// Attempted to start a server when one is already running.
17    #[error("Server already running on {address}")]
18    ServerAlreadyRunning { address: String },
19
20    /// Attempted to stop a server when none is running.
21    #[error("Server not running")]
22    ServerNotRunning,
23
24    /// Unexpected response type received from peer.
25    #[error("Unexpected response type: expected {expected}, got {actual}")]
26    UnexpectedResponse {
27        expected: &'static str,
28        actual: String,
29    },
30
31    /// Network communication error.
32    #[error("Network error: {0}")]
33    Network(String),
34
35    /// Command channel send error.
36    #[error("Failed to send command to background sync: {0}")]
37    CommandSendError(String),
38
39    /// Transport initialization error.
40    #[error("Failed to initialize transport: {0}")]
41    TransportInit(String),
42
43    /// Runtime creation error for async operations.
44    #[error("Failed to create async runtime: {0}")]
45    RuntimeCreation(String),
46
47    /// Server bind error.
48    #[error("Failed to bind server to {address}: {reason}")]
49    ServerBind { address: String, reason: String },
50
51    /// Client connection error.
52    #[error("Failed to connect to {address}: {reason}")]
53    ConnectionFailed { address: String, reason: String },
54
55    /// Device key not found in backend storage.
56    #[error("Device key '{key_name}' not found in backend storage")]
57    DeviceKeyNotFound { key_name: String },
58
59    /// Transport type not supported by this transport implementation.
60    #[error("Transport type '{transport_type}' not supported")]
61    UnsupportedTransport { transport_type: String },
62
63    /// Invalid address format.
64    #[error("Invalid address: {0}")]
65    InvalidAddress(String),
66
67    /// Peer not found.
68    #[error("Peer not found: {0}")]
69    PeerNotFound(String),
70
71    /// Peer already exists.
72    #[error("Peer already exists: {0}")]
73    PeerAlreadyExists(String),
74
75    /// Serialization error.
76    #[error("Serialization error: {0}")]
77    SerializationError(String),
78
79    /// Protocol version mismatch.
80    #[error("Protocol version mismatch: expected {expected}, received {received}")]
81    ProtocolMismatch { expected: u32, received: u32 },
82
83    /// Handshake failed.
84    #[error("Handshake failed: {0}")]
85    HandshakeFailed(String),
86
87    /// Entry not found in backend storage.
88    #[error("Entry not found: {0}")]
89    EntryNotFound(ID),
90
91    /// Invalid entry received (validation failed).
92    #[error("Invalid entry: {0}")]
93    InvalidEntry(String),
94
95    /// Sync protocol error.
96    #[error("Sync protocol error: {0}")]
97    SyncProtocolError(String),
98
99    /// Backend storage error.
100    #[error("Backend error: {0}")]
101    BackendError(String),
102
103    /// Bootstrap request not found.
104    #[error("Bootstrap request not found: {0}")]
105    RequestNotFound(String),
106
107    /// Bootstrap request already exists.
108    #[error("Bootstrap request already exists: {0}")]
109    RequestAlreadyExists(String),
110
111    /// Invalid bootstrap request state.
112    #[error(
113        "Invalid request state for '{request_id}': expected {expected_status}, found {current_status}"
114    )]
115    InvalidRequestState {
116        request_id: String,
117        current_status: String,
118        expected_status: String,
119    },
120
121    /// Invalid data format in stored bootstrap request.
122    #[error("Invalid data: {0}")]
123    InvalidData(String),
124
125    /// Insufficient permission for the requested operation.
126    #[error(
127        "Insufficient permission for request '{request_id}': required {required_permission}, but key has {actual_permission:?}"
128    )]
129    InsufficientPermission {
130        request_id: String,
131        required_permission: String,
132        actual_permission: Permission,
133    },
134
135    /// Invalid public key provided.
136    #[error("Invalid public key: {reason}")]
137    InvalidPublicKey { reason: String },
138
139    /// Invalid key name provided.
140    #[error("Invalid key name: {reason}")]
141    InvalidKeyName { reason: String },
142
143    /// Instance has been dropped and is no longer available.
144    #[error("Instance has been dropped")]
145    InstanceDropped,
146
147    /// Bootstrap request is pending manual approval.
148    #[error("Bootstrap request pending approval (request_id: {request_id}): {message}")]
149    BootstrapPending { request_id: String, message: String },
150
151    /// Transport configuration type mismatch.
152    #[error("Transport config type mismatch for '{name}': expected '{expected}', found '{found}'")]
153    TransportTypeMismatch {
154        name: String,
155        expected: String,
156        found: String,
157    },
158
159    /// Transport not found by name.
160    #[error("Transport not found: {name}")]
161    TransportNotFound { name: String },
162
163    /// No transport can handle the given address.
164    #[error("No transport can handle address: {address:?}")]
165    NoTransportForAddress { address: Address },
166
167    /// Multiple transport operations failed.
168    #[error("Multiple transport errors: {}", errors.join(", "))]
169    MultipleTransportErrors { errors: Vec<String> },
170}
171
172impl SyncError {
173    /// Check if this is a configuration error (no transport enabled).
174    pub fn is_configuration_error(&self) -> bool {
175        matches!(self, SyncError::NoTransportEnabled)
176    }
177
178    /// Check if this is a server lifecycle error.
179    pub fn is_server_error(&self) -> bool {
180        matches!(
181            self,
182            SyncError::ServerAlreadyRunning { .. }
183                | SyncError::ServerNotRunning
184                | SyncError::ServerBind { .. }
185        )
186    }
187
188    /// Check if this is a network/connection error.
189    pub fn is_network_error(&self) -> bool {
190        matches!(
191            self,
192            SyncError::Network(_) | SyncError::ConnectionFailed { .. }
193        )
194    }
195
196    /// Check if this is a protocol error (unexpected response).
197    pub fn is_protocol_error(&self) -> bool {
198        matches!(self, SyncError::UnexpectedResponse { .. })
199    }
200
201    /// Check if this is a not found error.
202    pub fn is_not_found(&self) -> bool {
203        matches!(
204            self,
205            SyncError::PeerNotFound(_) | SyncError::EntryNotFound(_)
206        )
207    }
208
209    /// Check if this is a validation error.
210    pub fn is_validation_error(&self) -> bool {
211        matches!(
212            self,
213            SyncError::InvalidEntry(_)
214                | SyncError::InvalidPublicKey { .. }
215                | SyncError::InvalidKeyName { .. }
216        )
217    }
218
219    /// Check if this is a backend error.
220    pub fn is_backend_error(&self) -> bool {
221        matches!(self, SyncError::BackendError(_))
222    }
223}