rustot/shadows/
error.rs

1use core::convert::TryFrom;
2use core::fmt::Display;
3use core::str::FromStr;
4
5use heapless::String;
6use mqttrust::MqttError;
7
8use super::data_types::ErrorResponse;
9
10#[derive(Debug, Clone)]
11#[cfg_attr(feature = "defmt", derive(defmt::Format))]
12pub enum Error {
13    Overflow,
14    NoPersistance,
15    DaoRead,
16    DaoWrite,
17    InvalidPayload,
18    WrongShadowName,
19    Mqtt(MqttError),
20    ShadowError(ShadowError),
21}
22
23impl From<MqttError> for Error {
24    fn from(e: MqttError) -> Self {
25        Self::Mqtt(e)
26    }
27}
28
29impl From<ShadowError> for Error {
30    fn from(e: ShadowError) -> Self {
31        Self::ShadowError(e)
32    }
33}
34
35#[derive(Debug, Clone, PartialEq, Eq)]
36#[cfg_attr(feature = "defmt", derive(defmt::Format))]
37pub enum ShadowError {
38    InvalidJson,
39    MissingState,
40    MalformedState,
41    MalformedDesired,
42    MalformedReported,
43    InvalidVersion,
44    InvalidClientToken,
45    JsonTooDeep,
46    InvalidStateNode,
47    Unauthorized,
48    Forbidden,
49    NotFound,
50    NoNamedShadow(String<64>),
51    VersionConflict,
52    PayloadTooLarge,
53    UnsupportedEncoding,
54    TooManyRequests,
55    InternalServerError,
56}
57
58impl ShadowError {
59    pub fn http_code(&self) -> u16 {
60        match self {
61            ShadowError::InvalidJson
62            | ShadowError::MissingState
63            | ShadowError::MalformedState
64            | ShadowError::MalformedDesired
65            | ShadowError::MalformedReported
66            | ShadowError::InvalidVersion
67            | ShadowError::InvalidClientToken
68            | ShadowError::JsonTooDeep
69            | ShadowError::InvalidStateNode => 400,
70
71            ShadowError::Unauthorized => 401,
72            ShadowError::Forbidden => 403,
73            ShadowError::NotFound | ShadowError::NoNamedShadow(_) => 404,
74            ShadowError::VersionConflict => 409,
75            ShadowError::PayloadTooLarge => 413,
76            ShadowError::UnsupportedEncoding => 415,
77            ShadowError::TooManyRequests => 429,
78            ShadowError::InternalServerError => 500,
79        }
80    }
81}
82
83impl<'a> TryFrom<ErrorResponse<'a>> for ShadowError {
84    type Error = ();
85
86    fn try_from(e: ErrorResponse<'a>) -> Result<Self, Self::Error> {
87        Ok(match e.code {
88            400 | 404 => Self::from_str(e.message)?,
89            401 => ShadowError::Unauthorized,
90            403 => ShadowError::Forbidden,
91            409 => ShadowError::VersionConflict,
92            413 => ShadowError::PayloadTooLarge,
93            415 => ShadowError::UnsupportedEncoding,
94            429 => ShadowError::TooManyRequests,
95            500 => ShadowError::InternalServerError,
96            _ => return Err(()),
97        })
98    }
99}
100
101impl Display for ShadowError {
102    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
103        match self {
104            Self::InvalidJson => write!(f, "Invalid JSON"),
105            Self::MissingState => write!(f, "Missing required node: state"),
106            Self::MalformedState => write!(f, "State node must be an object"),
107            Self::MalformedDesired => write!(f, "Desired node must be an object"),
108            Self::MalformedReported => write!(f, "Reported node must be an object"),
109            Self::InvalidVersion => write!(f, "Invalid version"),
110            Self::InvalidClientToken => write!(f, "Invalid clientToken"),
111            Self::JsonTooDeep => {
112                write!(f, "JSON contains too many levels of nesting; maximum is 6")
113            }
114            Self::InvalidStateNode => write!(f, "State contains an invalid node"),
115            Self::Unauthorized => write!(f, "Unauthorized"),
116            Self::Forbidden => write!(f, "Forbidden"),
117            Self::NotFound => write!(f, "Thing not found"),
118            Self::NoNamedShadow(shadow_name) => {
119                write!(f, "No shadow exists with name: {}", shadow_name)
120            }
121            Self::VersionConflict => write!(f, "Version conflict"),
122            Self::PayloadTooLarge => write!(f, "The payload exceeds the maximum size allowed"),
123            Self::UnsupportedEncoding => write!(
124                f,
125                "Unsupported documented encoding; supported encoding is UTF-8"
126            ),
127            Self::TooManyRequests => write!(f, "The Device Shadow service will generate this error message when there are more than 10 in-flight requests on a single connection"),
128            Self::InternalServerError => write!(f, "Internal service failure"),
129        }
130    }
131}
132
133// TODO: This seems like an extremely brittle way of doing this??!
134impl FromStr for ShadowError {
135    type Err = ();
136
137    fn from_str(s: &str) -> Result<Self, Self::Err> {
138        Ok(match s.trim() {
139            "Invalid JSON" => Self::InvalidJson,
140            "Missing required node: state" => Self::MissingState,
141            "State node must be an object" => Self::MalformedState,
142            "Desired node must be an object" => Self::MalformedDesired,
143            "Reported node must be an object" => Self::MalformedReported,
144            "Invalid version" => Self::InvalidVersion,
145            "Invalid clientToken" => Self::InvalidClientToken,
146            "JSON contains too many levels of nesting; maximum is 6" => Self::JsonTooDeep,
147            "State contains an invalid node" => Self::InvalidStateNode,
148            "Unauthorized" => Self::Unauthorized,
149            "Forbidden" => Self::Forbidden,
150            "Thing not found" => Self::NotFound,
151            // TODO:
152            "No shadow exists with name: " => Self::NoNamedShadow(String::new()),
153            "Version conflict" => Self::VersionConflict,
154            "The payload exceeds the maximum size allowed" => Self::PayloadTooLarge,
155            "Unsupported documented encoding; supported encoding is UTF-8" => {
156                Self::UnsupportedEncoding
157            }
158            "The Device Shadow service will generate this error message when there are more than 10 in-flight requests on a single connection" => Self::TooManyRequests,
159            "Internal service failure" => Self::InternalServerError,
160            _ => return Err(()),
161        })
162    }
163}