1use super::*;
2
3#[allow(unused_macros)]
4#[macro_export]
5macro_rules! apibail_not_initialized {
6 () => {
7 return Err(VeilidAPIError::not_initialized())
8 };
9}
10
11#[allow(unused_macros)]
12#[macro_export]
13macro_rules! apibail_timeout {
14 () => {
15 return Err(VeilidAPIError::timeout())
16 };
17}
18
19#[allow(unused_macros)]
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#[allow(unused_macros)]
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#[allow(unused_macros)]
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#[allow(unused_macros)]
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#[allow(unused_macros)]
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#[allow(unused_macros)]
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#[allow(unused_macros)]
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#[allow(unused_macros)]
89#[macro_export]
90macro_rules! apibail_key_not_found {
91 ($x:expr) => {
92 return Err(VeilidAPIError::key_not_found($x))
93 };
94}
95
96#[allow(unused_macros)]
97#[macro_export]
98macro_rules! apibail_invalid_target {
99 ($x:expr) => {
100 return Err(VeilidAPIError::invalid_target($x))
101 };
102}
103
104#[allow(unused_macros)]
105#[macro_export]
106macro_rules! apibail_route_not_found {
107 ($x:expr) => {
108 return Err(VeilidAPIError::route_not_found($x))
109 };
110}
111
112#[allow(unused_macros)]
113#[macro_export]
114macro_rules! apibail_already_initialized {
115 () => {
116 return Err(VeilidAPIError::already_initialized())
117 };
118}
119
120#[derive(
121 ThisError, Clone, Debug, PartialOrd, PartialEq, Eq, Ord, Serialize, Deserialize, JsonSchema,
122)]
123#[cfg_attr(
124 all(target_arch = "wasm32", target_os = "unknown"),
125 derive(Tsify),
126 tsify(into_wasm_abi)
127)]
128#[serde(tag = "kind")]
129#[must_use]
130pub enum VeilidAPIError {
131 #[error("Not initialized")]
132 NotInitialized,
133 #[error("Already initialized")]
134 AlreadyInitialized,
135 #[error("Timeout")]
136 Timeout,
137 #[error("TryAgain: {message}")]
138 TryAgain { message: String },
139 #[error("Shutdown")]
140 Shutdown,
141 #[error("Invalid target: {message}")]
142 InvalidTarget { message: String },
143 #[error("No connection: {message}")]
144 NoConnection { message: String },
145 #[error("Key not found: {key}")]
146 KeyNotFound {
147 #[schemars(with = "String")]
148 key: OpaqueRecordKey,
149 },
150 #[error("Internal: {message}")]
151 Internal { message: String },
152 #[error("Unimplemented: {message}")]
153 Unimplemented { message: String },
154 #[error("Parse error: '{message}' with value '{value}'")]
155 ParseError { message: String, value: String },
156 #[error("Invalid argument: '{context}' for '{argument}' with value '{value}'")]
157 InvalidArgument {
158 context: String,
159 argument: String,
160 value: String,
161 },
162 #[error("Missing argument: '{context}' for '{argument}'")]
163 MissingArgument { context: String, argument: String },
164 #[error("Generic: {message}")]
165 Generic { message: String },
166}
167
168impl VeilidAPIError {
169 pub fn not_initialized() -> Self {
170 Self::NotInitialized
171 }
172 pub fn already_initialized() -> Self {
173 Self::AlreadyInitialized
174 }
175 pub fn timeout() -> Self {
176 Self::Timeout
177 }
178 pub fn try_again<T: ToString>(msg: T) -> Self {
179 Self::TryAgain {
180 message: msg.to_string(),
181 }
182 }
183 pub fn shutdown() -> Self {
184 Self::Shutdown
185 }
186 pub fn invalid_target<T: ToString>(msg: T) -> Self {
187 Self::InvalidTarget {
188 message: msg.to_string(),
189 }
190 }
191 pub fn no_connection<T: ToString>(msg: T) -> Self {
192 Self::NoConnection {
193 message: msg.to_string(),
194 }
195 }
196 pub fn key_not_found(key: OpaqueRecordKey) -> Self {
197 Self::KeyNotFound { key }
198 }
199 pub fn internal<T: ToString>(msg: T) -> Self {
200 Self::Internal {
201 message: msg.to_string(),
202 }
203 }
204 pub fn unimplemented<T: ToString>(msg: T) -> Self {
205 Self::Unimplemented {
206 message: msg.to_string(),
207 }
208 }
209 pub fn parse_error<T: ToString, S: ToString>(msg: T, value: S) -> Self {
210 Self::ParseError {
211 message: msg.to_string(),
212 value: value.to_string(),
213 }
214 }
215 pub fn invalid_argument<T: ToString, S: ToString, R: ToString>(
216 context: T,
217 argument: S,
218 value: R,
219 ) -> Self {
220 Self::InvalidArgument {
221 context: context.to_string(),
222 argument: argument.to_string(),
223 value: value.to_string(),
224 }
225 }
226 pub fn missing_argument<T: ToString, S: ToString>(context: T, argument: S) -> Self {
227 Self::MissingArgument {
228 context: context.to_string(),
229 argument: argument.to_string(),
230 }
231 }
232 pub fn generic<T: ToString>(msg: T) -> Self {
233 Self::Generic {
234 message: msg.to_string(),
235 }
236 }
237
238 pub(crate) fn from_network_result<T>(nr: NetworkResult<T>) -> Result<T, Self> {
239 match nr {
240 NetworkResult::Timeout => Err(VeilidAPIError::timeout()),
241 NetworkResult::ServiceUnavailable(m) => Err(VeilidAPIError::invalid_target(m)),
242 NetworkResult::NoConnection(m) => Err(VeilidAPIError::no_connection(m)),
243 NetworkResult::AlreadyExists(m) => {
244 Err(VeilidAPIError::generic(format!("Already exists: {}", m)))
245 }
246 NetworkResult::InvalidMessage(m) => {
247 Err(VeilidAPIError::parse_error("Invalid message", m))
248 }
249 NetworkResult::Value(v) => Ok(v),
250 }
251 }
252
253 pub(crate) fn log_level(&self) -> Level {
254 match self {
255 VeilidAPIError::NotInitialized
256 | VeilidAPIError::AlreadyInitialized
257 | VeilidAPIError::InvalidTarget { message: _ }
258 | VeilidAPIError::Internal { message: _ }
259 | VeilidAPIError::Generic { message: _ }
260 | VeilidAPIError::ParseError {
261 message: _,
262 value: _,
263 }
264 | VeilidAPIError::InvalidArgument {
265 context: _,
266 argument: _,
267 value: _,
268 }
269 | VeilidAPIError::MissingArgument {
270 context: _,
271 argument: _,
272 }
273 | VeilidAPIError::Shutdown => Level::ERROR,
274
275 VeilidAPIError::NoConnection { message: _ }
276 | VeilidAPIError::KeyNotFound { key: _ }
277 | VeilidAPIError::Unimplemented { message: _ } => Level::WARN,
278
279 VeilidAPIError::Timeout | VeilidAPIError::TryAgain { message: _ } => Level::DEBUG,
280 }
281 }
282}
283
284pub type VeilidAPIResult<T> = Result<T, VeilidAPIError>;
285
286pub trait OkVeilidAPIResult<T> {
287 fn ok_try_again(self) -> VeilidAPIResult<Option<T>>;
288 fn ok_try_again_timeout(self) -> VeilidAPIResult<Option<T>>;
289}
290
291impl<T> OkVeilidAPIResult<T> for VeilidAPIResult<Option<T>> {
292 fn ok_try_again(self) -> VeilidAPIResult<Option<T>> {
293 match self {
294 Ok(v) => Ok(v),
295 Err(VeilidAPIError::TryAgain { message: _ }) => Ok(None),
296 Err(e) => Err(e),
297 }
298 }
299 fn ok_try_again_timeout(self) -> VeilidAPIResult<Option<T>> {
300 match self {
301 Ok(v) => Ok(v),
302 Err(VeilidAPIError::TryAgain { message: _ }) => Ok(None),
303 Err(VeilidAPIError::Timeout) => Ok(None),
304 Err(e) => Err(e),
305 }
306 }
307}
308
309impl From<std::io::Error> for VeilidAPIError {
310 fn from(e: std::io::Error) -> Self {
311 match e.kind() {
312 std::io::ErrorKind::TimedOut => VeilidAPIError::timeout(),
313 std::io::ErrorKind::ConnectionRefused => VeilidAPIError::no_connection(e.to_string()),
314 std::io::ErrorKind::ConnectionReset => VeilidAPIError::no_connection(e.to_string()),
315 std::io::ErrorKind::ConnectionAborted => VeilidAPIError::no_connection(e.to_string()),
320 std::io::ErrorKind::NotConnected => VeilidAPIError::no_connection(e.to_string()),
321 std::io::ErrorKind::AddrInUse => VeilidAPIError::no_connection(e.to_string()),
322 std::io::ErrorKind::AddrNotAvailable => VeilidAPIError::no_connection(e.to_string()),
323 std::io::ErrorKind::Unsupported => VeilidAPIError::internal(e.to_string()),
334 std::io::ErrorKind::OutOfMemory => VeilidAPIError::internal(e.to_string()),
335 _ => VeilidAPIError::generic(e.to_string()),
336 }
337 }
338}