libqaul_types/
error.rs

1//! Error and Result handling
2//!
3//! `libqaul` spans over a large abstraction surface, from drivers all
4//! the way to "business logic" functions in the service API. This
5//! makes communicating errors challenging at times. Generally, no
6//! lower layer `Error` objects are wrapped here, to avoid introducing
7//! new dependencies in service code.
8//!
9//! Instead, `Error` attempts to provide a comprehensive set of
10//! failures modes, that can be returned to communicate a failure,
11//! that then needs tobe interpreted and addressed by an implementing
12//! application. This way, it becomes easier for _your_ service to
13//! wrap errors, or to enumerate them more easily.
14//!
15//! On an `Error` enum, it is also possible to call `help()` to
16//! get a plain text error description of what went wrong, and what it
17//! probably means. These are meant to simplify front-end development
18//! and avoid having applications return arbitrary codes.
19
20use serde::{Deserialize, Serialize};
21use std::{
22    error::Error as StdError,
23    fmt::{self, Display, Formatter},
24    result::Result as StdResult,
25};
26
27/// `libqaul` specific Result with embedded Error
28///
29/// The returned `Error` can sometimes be considered non-fatal. Check
30/// the `Error` documentation for the specific returned variant to
31/// see, what level of fatality it should be interpreted as. Crashing
32/// on every returned `Err(_)` however is a bad idea.
33pub type Result<T> = StdResult<T, Error>;
34
35/// `libqaul` service API error states
36///
37/// All errors that can occur in interaction with the API are encoded
38/// as variants on this enum. In most cases, no additional metadata is
39/// provided and needs to be inferred from whatever context or
40/// function call emitted the error. Check the variant doc comments
41/// for a broad overview, as well as detailed usage instructions.
42///
43/// ## A note on language
44///
45/// Most variants of this enum use either an `Invalid` or `No`
46/// prefix. Invalid data is data that was either not expected or badly
47/// formatted. `No` in this case takes the place of `Unknown`, meaning
48/// that a query could not be fulfilled.
49#[derive(Serialize, Deserialize, Copy, Clone, Debug, PartialEq, Eq)]
50pub enum Error {
51    /// Not authorised to perform this action
52    NotAuthorised,
53    /// The desired user was not known
54    NoUser,
55    /// The provided contact already exists
56    ContactExists,
57    /// The desired contact does not exist
58    NoContact,
59    /// Invalid search query
60    InvalidQuery,
61    /// No data was returned for the provided query
62    NoData,
63    /// Invalid payload (probably too big)
64    InvalidPayload,
65    /// A function callback timed out
66    CallbackTimeout,
67    /// Signature with an unknown public key
68    NoSign,
69    /// Fraudulent signature for a known public key
70    BadSign,
71    /// A generic networking error occured
72    NetworkFault,
73    /// Failed to find a route to this user
74    NoRoute,
75    /// Some serialisation action failed
76    BadSerialise,
77    /// No such service was found
78    NoService,
79    /// A sevice with this name already exists
80    ServiceExists,
81    /// Some internal components failed to communicate
82    CommFault,
83}
84
85impl Error {
86    pub fn help(&self) -> String {
87        match std::env::var("QAUL_LANG").as_ref().map(|s| s.as_str()) {
88            Ok("ar") => "حدث خطأ غير معروف",
89            Ok("de") => "Ein unbekannter Fehler ist aufgetreten",
90            _ => "An unknown Error occured",
91        }
92        .into()
93    }
94}
95
96impl Display for Error {
97    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
98        let msg = match self {
99            Self::NotAuthorised => "Not authorised to perform this action",
100            Self::NoUser => "The desired user was not known",
101            Self::ContactExists => "The provided contact already exists",
102            Self::NoContact => "The desired contact does not exist",
103            Self::InvalidQuery => "Invalid search query",
104            Self::NoData => "No data was returned for the provided query",
105            Self::InvalidPayload => "Invalid payload (probably too big)",
106            Self::CallbackTimeout => "A function callback timed out",
107            Self::NoSign => "Signature with an unknown public key",
108            Self::BadSign => "Fraudulent signature for a known public key",
109            Self::NetworkFault => "A generic networking error occured",
110            Self::NoRoute => "Failed to find a route to this user",
111            Self::BadSerialise => "Some serialisation action failed",
112            Self::NoService => "No such service was found",
113            Self::ServiceExists => "A sevice with this name already exists",
114            Self::CommFault => "Some internal components failed to communicate",
115        };
116        write!(f, "{}", msg)
117    }
118}
119
120impl StdError for Error {}