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
133impl 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 "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}