1use thiserror::Error;
4
5use super::peer_types::Address;
6use crate::{auth::Permission, entry::ID};
7
8#[derive(Debug, Error)]
10#[non_exhaustive]
11pub enum SyncError {
12 #[error("No transport enabled. Call enable_http_transport() first")]
14 NoTransportEnabled,
15
16 #[error("Sync is not enabled on this Instance. Call Instance::enable_sync() first")]
18 SyncNotEnabled,
19
20 #[error("Server already running on {address}")]
22 ServerAlreadyRunning { address: String },
23
24 #[error("Server not running")]
26 ServerNotRunning,
27
28 #[error("Unexpected response type: expected {expected}, got {actual}")]
30 UnexpectedResponse {
31 expected: &'static str,
32 actual: String,
33 },
34
35 #[error("Network error: {0}")]
37 Network(String),
38
39 #[error("Failed to send command to background sync: {0}")]
41 CommandSendError(String),
42
43 #[error("Failed to initialize transport: {0}")]
45 TransportInit(String),
46
47 #[error("Failed to create async runtime: {0}")]
49 RuntimeCreation(String),
50
51 #[error("Failed to bind server to {address}: {reason}")]
53 ServerBind { address: String, reason: String },
54
55 #[error("Failed to connect to {address}: {reason}")]
57 ConnectionFailed { address: String, reason: String },
58
59 #[error("Device key '{key_name}' not found in backend storage")]
61 DeviceKeyNotFound { key_name: String },
62
63 #[error("Transport type '{transport_type}' not supported")]
65 UnsupportedTransport { transport_type: String },
66
67 #[error("Invalid address: {0}")]
69 InvalidAddress(String),
70
71 #[error("Peer not found: {0}")]
73 PeerNotFound(String),
74
75 #[error("Peer already exists: {0}")]
77 PeerAlreadyExists(String),
78
79 #[error("Serialization error: {0}")]
81 SerializationError(String),
82
83 #[error("Protocol version mismatch: expected {expected}, received {received}")]
85 ProtocolMismatch { expected: u32, received: u32 },
86
87 #[error("Handshake failed: {0}")]
89 HandshakeFailed(String),
90
91 #[error("Entry not found: {0}")]
93 EntryNotFound(ID),
94
95 #[error("Invalid entry: {0}")]
97 InvalidEntry(String),
98
99 #[error("Sync protocol error: {0}")]
101 SyncProtocolError(String),
102
103 #[error("Backend error: {0}")]
105 BackendError(String),
106
107 #[error("Bootstrap request not found: {0}")]
109 RequestNotFound(String),
110
111 #[error("Bootstrap request already exists: {0}")]
113 RequestAlreadyExists(String),
114
115 #[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 #[error("Invalid data: {0}")]
127 InvalidData(String),
128
129 #[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 #[error("Authentication required to read database '{0}'")]
141 AuthenticationRequired(String),
142
143 #[error("Authentication failed: {0}")]
145 AuthenticationFailed(String),
146
147 #[error("Permission denied: {0}")]
149 PermissionDenied(String),
150
151 #[error("Invalid public key: {reason}")]
153 InvalidPublicKey { reason: String },
154
155 #[error("Invalid key name: {reason}")]
157 InvalidKeyName { reason: String },
158
159 #[error("Instance has been dropped")]
161 InstanceDropped,
162
163 #[error("Bootstrap request pending approval (request_id: {request_id}): {message}")]
165 BootstrapPending { request_id: String, message: String },
166
167 #[error("Transport config type mismatch for '{name}': expected '{expected}', found '{found}'")]
169 TransportTypeMismatch {
170 name: String,
171 expected: String,
172 found: String,
173 },
174
175 #[error("Transport not found: {name}")]
177 TransportNotFound { name: String },
178
179 #[error("No transport can handle address: {address:?}")]
181 NoTransportForAddress { address: Address },
182
183 #[error("Multiple transport errors: {}", errors.join(", "))]
185 MultipleTransportErrors { errors: Vec<String> },
186}
187
188impl SyncError {
189 pub fn is_configuration_error(&self) -> bool {
192 matches!(
193 self,
194 SyncError::NoTransportEnabled | SyncError::SyncNotEnabled
195 )
196 }
197
198 pub fn is_server_error(&self) -> bool {
200 matches!(
201 self,
202 SyncError::ServerAlreadyRunning { .. }
203 | SyncError::ServerNotRunning
204 | SyncError::ServerBind { .. }
205 )
206 }
207
208 pub fn is_network_error(&self) -> bool {
210 matches!(
211 self,
212 SyncError::Network(_) | SyncError::ConnectionFailed { .. }
213 )
214 }
215
216 pub fn is_protocol_error(&self) -> bool {
218 matches!(self, SyncError::UnexpectedResponse { .. })
219 }
220
221 pub fn is_not_found(&self) -> bool {
223 matches!(
224 self,
225 SyncError::PeerNotFound(_) | SyncError::EntryNotFound(_)
226 )
227 }
228
229 pub fn is_validation_error(&self) -> bool {
231 matches!(
232 self,
233 SyncError::InvalidEntry(_)
234 | SyncError::InvalidPublicKey { .. }
235 | SyncError::InvalidKeyName { .. }
236 )
237 }
238
239 pub fn is_backend_error(&self) -> bool {
241 matches!(self, SyncError::BackendError(_))
242 }
243}