Skip to main content

veilid_core/veilid_api/
error.rs

1use super::*;
2
3/// Return early with a [VeilidAPIError::NotInitialized] error.
4#[macro_export]
5macro_rules! apibail_not_initialized {
6    () => {
7        return Err(VeilidAPIError::not_initialized())
8    };
9}
10
11/// Return early with a [VeilidAPIError::Timeout] error.
12#[macro_export]
13macro_rules! apibail_timeout {
14    () => {
15        return Err(VeilidAPIError::timeout())
16    };
17}
18
19/// Return early with a [VeilidAPIError::TryAgain] error carrying the given message.
20#[macro_export]
21macro_rules! apibail_try_again {
22    ($x:expr) => {
23        return Err(VeilidAPIError::try_again($x))
24    };
25    ($fmt:literal, $($args:tt)*) => {
26        return Err(VeilidAPIError::try_again( format!($fmt, $($args)*) ))
27    };
28}
29
30/// Return early with a [VeilidAPIError::Generic] error carrying the given message.
31#[macro_export]
32macro_rules! apibail_generic {
33    ($x:expr) => {
34        return Err(VeilidAPIError::generic($x))
35    };
36    ($fmt:literal, $($args:tt)*) => {
37        return Err(VeilidAPIError::generic( format!($fmt, $($args)*) ))
38    };
39}
40
41/// Return early with a [VeilidAPIError::Internal] error carrying the given message.
42#[macro_export]
43macro_rules! apibail_internal {
44    ($x:expr) => {
45        return Err(VeilidAPIError::internal($x))
46    };
47    ($fmt:literal, $($args:tt)*) => {
48        return Err(VeilidAPIError::internal( format!($fmt, $($args)*) ))
49    };
50}
51
52/// Return early with a [VeilidAPIError::ParseError] error carrying the given message and value.
53#[macro_export]
54macro_rules! apibail_parse_error {
55    ($x:expr, $y:expr) => {
56        return Err(VeilidAPIError::parse_error($x, $y))
57    };
58}
59
60/// Return early with a [VeilidAPIError::MissingArgument] error naming the calling context and the missing argument.
61#[macro_export]
62macro_rules! apibail_missing_argument {
63    ($x:expr, $y:expr) => {
64        return Err(VeilidAPIError::missing_argument($x, $y))
65    };
66}
67
68/// Return early with a [VeilidAPIError::InvalidArgument] error naming the calling context, the argument, and its rejected value.
69#[macro_export]
70macro_rules! apibail_invalid_argument {
71    ($x:expr, $y:expr, $z:expr) => {
72        return Err(VeilidAPIError::invalid_argument($x, $y, $z))
73    };
74}
75
76/// Return early with a [VeilidAPIError::NoConnection] error carrying the given message.
77#[macro_export]
78macro_rules! apibail_no_connection {
79    ($x:expr) => {
80        return Err(VeilidAPIError::no_connection($x))
81    };
82    ($fmt:literal, $($args: tt)* ) => {
83        return Err(VeilidAPIError::no_connection( format!($fmt, arg $($args)*) ))
84    };
85
86}
87
88/// Return early with a [VeilidAPIError::KeyNotFound] error carrying the missing record key.
89#[macro_export]
90macro_rules! apibail_key_not_found {
91    ($x:expr) => {
92        return Err(VeilidAPIError::key_not_found($x))
93    };
94}
95
96/// Return early with a [VeilidAPIError::InvalidTarget] error carrying the given message.
97#[macro_export]
98macro_rules! apibail_invalid_target {
99    ($x:expr) => {
100        return Err(VeilidAPIError::invalid_target($x))
101    };
102}
103
104/// Return early with a [VeilidAPIError::TransactionNotFound] error carrying the given message.
105#[macro_export]
106macro_rules! apibail_transaction_not_found {
107    ($x:expr) => {
108        return Err(VeilidAPIError::transaction_not_found($x))
109    };
110    ($fmt:literal, $($args:tt)*) => {
111        return Err(VeilidAPIError::transaction_not_found( format!($fmt, $($args)*) ))
112    };
113}
114
115/// Return early with a [VeilidAPIError::AlreadyInitialized] error.
116#[macro_export]
117macro_rules! apibail_already_initialized {
118    () => {
119        return Err(VeilidAPIError::already_initialized())
120    };
121}
122
123/// Error type returned by all fallible Veilid API operations.
124#[apply(api_data_enum!)]
125#[api(eq, ord, ts(into_wasm_abi))]
126#[derive(ThisError)]
127#[serde(tag = "kind")]
128pub enum VeilidAPIError {
129    /// The API was used before [VeilidAPI](crate::VeilidAPI) was attached, or after it was detached.
130    #[error("Not initialized")]
131    NotInitialized,
132    /// An attempt was made to initialize Veilid while it was already running.
133    #[error("Already initialized")]
134    AlreadyInitialized,
135    /// The operation did not complete within its time budget.
136    #[error("Timeout")]
137    Timeout,
138    /// The operation could not be completed yet and should be retried later.
139    #[error("TryAgain: {message}")]
140    TryAgain {
141        /// Why the operation could not complete this time.
142        message: String,
143    },
144    /// The destination for an operation could not be reached or is malformed.
145    #[error("Invalid target: {message}")]
146    InvalidTarget {
147        /// Details about the unreachable or malformed target.
148        message: String,
149    },
150    /// No network connection could be established to carry out the operation.
151    #[error("No connection: {message}")]
152    NoConnection {
153        /// Details about the connection failure.
154        message: String,
155    },
156    /// The API is shutting down and can no longer service requests.
157    #[error("Shutdown")]
158    Shutdown,
159    /// The requested DHT record key is not present in local storage.
160    #[error("Key not found: {key}")]
161    KeyNotFound {
162        /// The record key that was not found.
163        #[cfg_attr(feature = "schemars", schemars(with = "String"))]
164        key: OpaqueRecordKey,
165    },
166    /// An internal invariant was violated; indicates a bug in Veilid itself.
167    #[error("Internal: {message}")]
168    Internal {
169        /// Details about the internal failure.
170        message: String,
171    },
172    /// The requested feature exists in the API surface but is not yet implemented on this platform or build.
173    #[error("Unimplemented: {message}")]
174    Unimplemented {
175        /// Which functionality is unimplemented.
176        message: String,
177    },
178    /// A value could not be parsed into its expected form.
179    #[error("Parse error: '{message}' with value '{value}'")]
180    ParseError {
181        /// What went wrong while parsing.
182        message: String,
183        /// The input value that failed to parse.
184        value: String,
185    },
186    /// An argument was supplied but its value was rejected.
187    #[error("Invalid argument: '{context}' for '{argument}' with value '{value}'")]
188    InvalidArgument {
189        /// The calling context that rejected the argument.
190        context: String,
191        /// The name of the offending argument.
192        argument: String,
193        /// The rejected value.
194        value: String,
195    },
196    /// A required argument was not supplied.
197    #[error("Missing argument: '{context}' for '{argument}'")]
198    MissingArgument {
199        /// The calling context that required the argument.
200        context: String,
201        /// The name of the missing argument.
202        argument: String,
203    },
204    /// A failure that does not fit any more specific category.
205    #[error("Generic: {message}")]
206    Generic {
207        /// Details about the failure.
208        message: String,
209    },
210    /// The referenced DHT transaction does not exist, having expired or never been opened.
211    #[error("Transaction not found: {message}")]
212    TransactionNotFound {
213        /// Details about the missing transaction.
214        message: String,
215    },
216}
217
218impl VeilidAPIError {
219    /// Construct a [VeilidAPIError::NotInitialized] error.
220    pub fn not_initialized() -> Self {
221        Self::NotInitialized
222    }
223    /// Construct a [VeilidAPIError::AlreadyInitialized] error.
224    pub fn already_initialized() -> Self {
225        Self::AlreadyInitialized
226    }
227    /// Construct a [VeilidAPIError::Timeout] error.
228    pub fn timeout() -> Self {
229        Self::Timeout
230    }
231    /// Construct a [VeilidAPIError::TryAgain] error with the given message.
232    pub fn try_again<T: ToVeilidAPIErrorArgument>(msg: T) -> Self {
233        Self::TryAgain {
234            message: msg.to_veilid_api_error_argument(),
235        }
236    }
237    /// Construct a [VeilidAPIError::Shutdown] error.
238    pub fn shutdown() -> Self {
239        Self::Shutdown
240    }
241    /// Construct a [VeilidAPIError::InvalidTarget] error with the given message.
242    pub fn invalid_target<T: ToVeilidAPIErrorArgument>(msg: T) -> Self {
243        Self::InvalidTarget {
244            message: msg.to_veilid_api_error_argument(),
245        }
246    }
247    /// Construct a [VeilidAPIError::NoConnection] error with the given message.
248    pub fn no_connection<T: ToVeilidAPIErrorArgument>(msg: T) -> Self {
249        Self::NoConnection {
250            message: msg.to_veilid_api_error_argument(),
251        }
252    }
253    /// Construct a [VeilidAPIError::KeyNotFound] error for the given record key.
254    pub fn key_not_found(key: OpaqueRecordKey) -> Self {
255        Self::KeyNotFound { key }
256    }
257    /// Construct a [VeilidAPIError::ParseError] error with the given message and offending value.
258    pub fn parse_error<T: ToVeilidAPIErrorArgument, S: ToVeilidAPIErrorArgument>(
259        msg: T,
260        value: S,
261    ) -> Self {
262        Self::ParseError {
263            message: msg.to_veilid_api_error_argument(),
264            value: value.to_veilid_api_error_argument(),
265        }
266    }
267    /// Construct a [VeilidAPIError::InvalidArgument] error naming the context, argument, and rejected value.
268    pub fn invalid_argument<
269        T: ToVeilidAPIErrorArgument,
270        S: ToVeilidAPIErrorArgument,
271        R: ToVeilidAPIErrorArgument,
272    >(
273        context: T,
274        argument: S,
275        value: R,
276    ) -> Self {
277        Self::InvalidArgument {
278            context: context.to_veilid_api_error_argument(),
279            argument: argument.to_veilid_api_error_argument(),
280            value: value.to_veilid_api_error_argument(),
281        }
282    }
283    /// Construct a [VeilidAPIError::MissingArgument] error naming the context and the missing argument.
284    pub fn missing_argument<T: ToVeilidAPIErrorArgument, S: ToVeilidAPIErrorArgument>(
285        context: T,
286        argument: S,
287    ) -> Self {
288        Self::MissingArgument {
289            context: context.to_veilid_api_error_argument(),
290            argument: argument.to_veilid_api_error_argument(),
291        }
292    }
293    /// Construct a [VeilidAPIError::Generic] error with the given message.
294    pub fn generic<T: ToVeilidAPIErrorArgument>(msg: T) -> Self {
295        Self::Generic {
296            message: msg.to_veilid_api_error_argument(),
297        }
298    }
299    pub(crate) fn transaction_not_found<T: ToVeilidAPIErrorArgument>(msg: T) -> Self {
300        Self::TransactionNotFound {
301            message: msg.to_veilid_api_error_argument(),
302        }
303    }
304
305    /// Convert a [NetworkResult] into a [VeilidAPIResult], mapping each non-value outcome to the matching error variant.
306    pub fn from_network_result<T>(nr: NetworkResult<T>) -> Result<T, Self> {
307        match nr {
308            NetworkResult::Timeout => Err(VeilidAPIError::timeout()),
309            NetworkResult::ServiceUnavailable(m) => Err(VeilidAPIError::invalid_target(m)),
310            NetworkResult::NoConnection(m) => Err(VeilidAPIError::no_connection(m.to_string())),
311            NetworkResult::AlreadyExists(m) => Err(VeilidAPIError::no_connection(format!(
312                "Already exists: {}",
313                m
314            ))),
315            NetworkResult::InvalidMessage(m) => {
316                Err(VeilidAPIError::parse_error("Invalid message", m))
317            }
318            NetworkResult::Value(v) => Ok(v),
319        }
320    }
321
322    /// The [tracing] log level at which this error should be reported.
323    pub fn log_level(&self) -> Level {
324        match self {
325            VeilidAPIError::NotInitialized
326            | VeilidAPIError::AlreadyInitialized
327            | VeilidAPIError::InvalidTarget { message: _ }
328            | VeilidAPIError::Internal { message: _ }
329            | VeilidAPIError::Generic { message: _ }
330            | VeilidAPIError::ParseError {
331                message: _,
332                value: _,
333            }
334            | VeilidAPIError::InvalidArgument {
335                context: _,
336                argument: _,
337                value: _,
338            }
339            | VeilidAPIError::MissingArgument {
340                context: _,
341                argument: _,
342            }
343            | VeilidAPIError::Shutdown => Level::ERROR,
344
345            VeilidAPIError::NoConnection { message: _ }
346            | VeilidAPIError::KeyNotFound { key: _ }
347            | VeilidAPIError::Unimplemented { message: _ } => Level::WARN,
348
349            VeilidAPIError::Timeout
350            | VeilidAPIError::TryAgain { message: _ }
351            | VeilidAPIError::TransactionNotFound { message: _ } => Level::DEBUG,
352        }
353    }
354
355    /// Construct a [VeilidAPIError::Internal] error with the given message. Constructing one signals a bug in Veilid.
356    pub fn internal<T: ToString>(msg: T) -> Self {
357        let message = msg.to_string();
358        // Constructing an internal error should get logged because it must be a programming error on our part
359        // veilid_log!(acc error "Internal error: {}", &message);
360        Self::Internal { message }
361    }
362    /// Construct a [VeilidAPIError::Unimplemented] error with the given message.
363    pub fn unimplemented<T: ToString>(msg: T) -> Self {
364        let message = msg.to_string();
365        // Constructing an unimplemented error should get logged because it must be a programming error on our part
366        // veilid_log!(acc error "Unimplemented: {}", &message);
367        Self::Unimplemented { message }
368    }
369}
370
371/////////////////////////////////////////////////////////////////////////////////////////
372
373/// Trait for types that can be directly converted into parameters for VeilidAPIError
374pub trait ToVeilidAPIErrorArgument {
375    /// Render this value as a string for inclusion in a [VeilidAPIError] message field.
376    fn to_veilid_api_error_argument(&self) -> String;
377}
378
379impl ToVeilidAPIErrorArgument for String {
380    fn to_veilid_api_error_argument(&self) -> String {
381        self.clone()
382    }
383}
384impl ToVeilidAPIErrorArgument for str {
385    fn to_veilid_api_error_argument(&self) -> String {
386        self.to_string()
387    }
388}
389impl ToVeilidAPIErrorArgument for [u8] {
390    fn to_veilid_api_error_argument(&self) -> String {
391        hex::encode(self)
392    }
393}
394impl ToVeilidAPIErrorArgument for Vec<u8> {
395    fn to_veilid_api_error_argument(&self) -> String {
396        hex::encode(self)
397    }
398}
399
400impl ToVeilidAPIErrorArgument for usize {
401    fn to_veilid_api_error_argument(&self) -> String {
402        self.to_string()
403    }
404}
405impl ToVeilidAPIErrorArgument for u64 {
406    fn to_veilid_api_error_argument(&self) -> String {
407        self.to_string()
408    }
409}
410impl ToVeilidAPIErrorArgument for u32 {
411    fn to_veilid_api_error_argument(&self) -> String {
412        self.to_string()
413    }
414}
415impl ToVeilidAPIErrorArgument for u16 {
416    fn to_veilid_api_error_argument(&self) -> String {
417        self.to_string()
418    }
419}
420impl ToVeilidAPIErrorArgument for u8 {
421    fn to_veilid_api_error_argument(&self) -> String {
422        self.to_string()
423    }
424}
425impl ToVeilidAPIErrorArgument for isize {
426    fn to_veilid_api_error_argument(&self) -> String {
427        self.to_string()
428    }
429}
430impl ToVeilidAPIErrorArgument for i64 {
431    fn to_veilid_api_error_argument(&self) -> String {
432        self.to_string()
433    }
434}
435impl ToVeilidAPIErrorArgument for i32 {
436    fn to_veilid_api_error_argument(&self) -> String {
437        self.to_string()
438    }
439}
440impl ToVeilidAPIErrorArgument for i16 {
441    fn to_veilid_api_error_argument(&self) -> String {
442        self.to_string()
443    }
444}
445impl ToVeilidAPIErrorArgument for i8 {
446    fn to_veilid_api_error_argument(&self) -> String {
447        self.to_string()
448    }
449}
450impl ToVeilidAPIErrorArgument for f64 {
451    fn to_veilid_api_error_argument(&self) -> String {
452        self.to_string()
453    }
454}
455impl ToVeilidAPIErrorArgument for f32 {
456    fn to_veilid_api_error_argument(&self) -> String {
457        self.to_string()
458    }
459}
460
461impl<T: ToVeilidAPIErrorArgument> ToVeilidAPIErrorArgument for core::ops::Range<T> {
462    fn to_veilid_api_error_argument(&self) -> String {
463        format!(
464            "{}..{}",
465            self.start.to_veilid_api_error_argument(),
466            self.end.to_veilid_api_error_argument()
467        )
468    }
469}
470
471impl ToVeilidAPIErrorArgument for Timestamp {
472    fn to_veilid_api_error_argument(&self) -> String {
473        self.to_string()
474    }
475}
476impl ToVeilidAPIErrorArgument for TimestampDuration {
477    fn to_veilid_api_error_argument(&self) -> String {
478        self.to_string()
479    }
480}
481impl ToVeilidAPIErrorArgument for ValueSeqNum {
482    fn to_veilid_api_error_argument(&self) -> String {
483        self.to_string()
484    }
485}
486impl ToVeilidAPIErrorArgument for ValueSubkeyRangeSet {
487    fn to_veilid_api_error_argument(&self) -> String {
488        self.to_string()
489    }
490}
491impl ToVeilidAPIErrorArgument for CryptoKind {
492    fn to_veilid_api_error_argument(&self) -> String {
493        self.to_string()
494    }
495}
496impl ToVeilidAPIErrorArgument for VeilidCapability {
497    fn to_veilid_api_error_argument(&self) -> String {
498        self.to_string()
499    }
500}
501
502impl ToVeilidAPIErrorArgument for RouteId {
503    fn to_veilid_api_error_argument(&self) -> String {
504        self.to_string()
505    }
506}
507impl ToVeilidAPIErrorArgument for NodeId {
508    fn to_veilid_api_error_argument(&self) -> String {
509        self.to_string()
510    }
511}
512impl ToVeilidAPIErrorArgument for PublicKey {
513    fn to_veilid_api_error_argument(&self) -> String {
514        self.to_string()
515    }
516}
517impl ToVeilidAPIErrorArgument for SecretKey {
518    fn to_veilid_api_error_argument(&self) -> String {
519        format!(
520            "{}:{}",
521            self.kind(),
522            self.ref_value().to_veilid_api_error_argument()
523        )
524    }
525}
526impl ToVeilidAPIErrorArgument for SharedSecret {
527    fn to_veilid_api_error_argument(&self) -> String {
528        format!(
529            "{}:{}",
530            self.kind(),
531            self.ref_value().to_veilid_api_error_argument()
532        )
533    }
534}
535impl ToVeilidAPIErrorArgument for Signature {
536    fn to_veilid_api_error_argument(&self) -> String {
537        format!(
538            "{}:{}",
539            self.kind(),
540            self.ref_value().to_veilid_api_error_argument()
541        )
542    }
543}
544impl ToVeilidAPIErrorArgument for HashDigest {
545    fn to_veilid_api_error_argument(&self) -> String {
546        format!(
547            "{}:{}",
548            self.kind(),
549            self.ref_value().to_veilid_api_error_argument()
550        )
551    }
552}
553impl ToVeilidAPIErrorArgument for KeyPair {
554    fn to_veilid_api_error_argument(&self) -> String {
555        format!(
556            "{}:{}",
557            self.kind(),
558            self.ref_value().to_veilid_api_error_argument(),
559        )
560    }
561}
562impl ToVeilidAPIErrorArgument for RecordKey {
563    fn to_veilid_api_error_argument(&self) -> String {
564        format!(
565            "{}:{}",
566            self.kind(),
567            self.value().to_veilid_api_error_argument()
568        )
569    }
570}
571impl ToVeilidAPIErrorArgument for MemberId {
572    fn to_veilid_api_error_argument(&self) -> String {
573        self.to_string()
574    }
575}
576impl ToVeilidAPIErrorArgument for OpaqueRecordKey {
577    fn to_veilid_api_error_argument(&self) -> String {
578        format!(
579            "{}:{}",
580            self.kind(),
581            self.ref_value().to_veilid_api_error_argument()
582        )
583    }
584}
585impl ToVeilidAPIErrorArgument for BareRecordKey {
586    fn to_veilid_api_error_argument(&self) -> String {
587        format!(
588            "{}{}",
589            self.ref_key(),
590            self.ref_encryption_key()
591                .map(|ek| ek.to_veilid_api_error_argument())
592                .unwrap_or("".to_string())
593        )
594    }
595}
596impl ToVeilidAPIErrorArgument for BareKeyPair {
597    fn to_veilid_api_error_argument(&self) -> String {
598        format!(
599            "{}:{}",
600            self.ref_key().to_veilid_api_error_argument(),
601            self.ref_secret().to_veilid_api_error_argument()
602        )
603    }
604}
605impl ToVeilidAPIErrorArgument for BarePublicKey {
606    fn to_veilid_api_error_argument(&self) -> String {
607        self.to_string()
608    }
609}
610impl ToVeilidAPIErrorArgument for BareSecretKey {
611    fn to_veilid_api_error_argument(&self) -> String {
612        "*".repeat(self.to_string().len())
613    }
614}
615impl ToVeilidAPIErrorArgument for BareSharedSecret {
616    fn to_veilid_api_error_argument(&self) -> String {
617        "*".repeat(self.to_string().len())
618    }
619}
620impl ToVeilidAPIErrorArgument for BareSignature {
621    fn to_veilid_api_error_argument(&self) -> String {
622        self.to_string()
623    }
624}
625impl ToVeilidAPIErrorArgument for BareHashDigest {
626    fn to_veilid_api_error_argument(&self) -> String {
627        self.to_string()
628    }
629}
630impl ToVeilidAPIErrorArgument for BareOpaqueRecordKey {
631    fn to_veilid_api_error_argument(&self) -> String {
632        self.to_string()
633    }
634}
635impl ToVeilidAPIErrorArgument for BareMemberId {
636    fn to_veilid_api_error_argument(&self) -> String {
637        self.to_string()
638    }
639}
640
641impl ToVeilidAPIErrorArgument for serde_json::Error {
642    fn to_veilid_api_error_argument(&self) -> String {
643        self.to_string()
644    }
645}
646
647impl<T: ToVeilidAPIErrorArgument + ?Sized> ToVeilidAPIErrorArgument for &T {
648    fn to_veilid_api_error_argument(&self) -> String {
649        (**self).to_veilid_api_error_argument()
650    }
651}
652
653/////////////////////////////////////////////////////////////////////////////////////////
654
655/// Result type for public Veilid API errors
656pub type VeilidAPIResult<T> = Result<T, VeilidAPIError>;
657
658/// Extension methods for turning recoverable [VeilidAPIError] outcomes into `Ok(None)`.
659pub trait OkVeilidAPIResult<T> {
660    /// Map a [VeilidAPIError::TryAgain] error to `Ok(None)`, passing through other results unchanged.
661    fn ok_try_again(self) -> VeilidAPIResult<Option<T>>;
662    /// Map a [VeilidAPIError::TryAgain] or [VeilidAPIError::Timeout] error to `Ok(None)`, passing through other results unchanged.
663    fn ok_try_again_timeout(self) -> VeilidAPIResult<Option<T>>;
664}
665
666impl<T> OkVeilidAPIResult<T> for VeilidAPIResult<Option<T>> {
667    fn ok_try_again(self) -> VeilidAPIResult<Option<T>> {
668        match self {
669            Ok(v) => Ok(v),
670            Err(VeilidAPIError::TryAgain { message: _ }) => Ok(None),
671            Err(e) => Err(e),
672        }
673    }
674    fn ok_try_again_timeout(self) -> VeilidAPIResult<Option<T>> {
675        match self {
676            Ok(v) => Ok(v),
677            Err(VeilidAPIError::TryAgain { message: _ }) => Ok(None),
678            Err(VeilidAPIError::Timeout) => Ok(None),
679            Err(e) => Err(e),
680        }
681    }
682}
683
684impl From<std::io::Error> for VeilidAPIError {
685    fn from(e: std::io::Error) -> Self {
686        match e.kind() {
687            std::io::ErrorKind::TimedOut => VeilidAPIError::timeout(),
688            std::io::ErrorKind::ConnectionRefused => VeilidAPIError::no_connection(e.to_string()),
689            std::io::ErrorKind::ConnectionReset => VeilidAPIError::no_connection(e.to_string()),
690            // #[cfg(feature = "io_error_more")]
691            // std::io::ErrorKind::HostUnreachable => VeilidAPIError::no_connection(e.to_string()),
692            // #[cfg(feature = "io_error_more")]
693            // std::io::ErrorKind::NetworkUnreachable => VeilidAPIError::no_connection(e.to_string()),
694            std::io::ErrorKind::ConnectionAborted => VeilidAPIError::no_connection(e.to_string()),
695            std::io::ErrorKind::NotConnected => VeilidAPIError::no_connection(e.to_string()),
696            std::io::ErrorKind::AddrInUse => VeilidAPIError::no_connection(e.to_string()),
697            std::io::ErrorKind::AddrNotAvailable => VeilidAPIError::no_connection(e.to_string()),
698            // #[cfg(feature = "io_error_more")]
699            // std::io::ErrorKind::NetworkDown => VeilidAPIError::no_connection(e.to_string()),
700            // #[cfg(feature = "io_error_more")]
701            // std::io::ErrorKind::ReadOnlyFilesystem => VeilidAPIError::internal(e.to_string()),
702            // #[cfg(feature = "io_error_more")]
703            // std::io::ErrorKind::NotSeekable => VeilidAPIError::internal(e.to_string()),
704            // #[cfg(feature = "io_error_more")]
705            // std::io::ErrorKind::FilesystemQuotaExceeded => VeilidAPIError::internal(e.to_string()),
706            // #[cfg(feature = "io_error_more")]
707            // std::io::ErrorKind::Deadlock => VeilidAPIError::internal(e.to_string()),
708            std::io::ErrorKind::Unsupported => VeilidAPIError::internal(e.to_string()),
709            std::io::ErrorKind::OutOfMemory => VeilidAPIError::internal(e.to_string()),
710            _ => VeilidAPIError::generic(e.to_string()),
711        }
712    }
713}