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

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