1use std::error;
2use std::fmt;
3use std::io;
4use std::str;
5#[cfg(feature = "aio_tokio")]
6use std::string::FromUtf8Error;
7
8#[cfg(feature = "aio_tokio")]
9use tokio::time::error::Elapsed;
10
11
12#[derive(Debug)]
14pub enum RequestError {
15 AttoHttpError(attohttpc::Error),
17 IoError(io::Error),
19 InvalidResponse(String),
21 ErrorCode(u16, String),
23 UnsupportedAction(String),
25 #[cfg(feature = "aio_tokio")]
27 HyperError(hyper::Error),
28 #[cfg(feature = "aio_tokio")]
30 HyperClientError(hyper_util::client::legacy::Error),
31
32 #[cfg(feature = "aio_tokio")]
33 HttpError(http::Error),
35
36 #[cfg(feature = "aio_tokio")]
37 Utf8Error(FromUtf8Error),
39}
40
41impl From<attohttpc::Error> for RequestError {
42 fn from(err: attohttpc::Error) -> RequestError {
43 RequestError::AttoHttpError(err)
44 }
45}
46
47impl From<io::Error> for RequestError {
48 fn from(err: io::Error) -> RequestError {
49 RequestError::IoError(err)
50 }
51}
52
53#[cfg(feature = "aio_tokio")]
54impl From<http::Error> for RequestError {
55 fn from(err: http::Error) -> RequestError {
56 RequestError::HttpError(err)
57 }
58}
59
60#[cfg(feature = "aio_tokio")]
61impl From<hyper::Error> for RequestError {
62 fn from(err: hyper::Error) -> RequestError {
63 RequestError::HyperError(err)
64 }
65}
66
67#[cfg(feature = "aio_tokio")]
68impl From<FromUtf8Error> for RequestError {
69 fn from(err: FromUtf8Error) -> RequestError {
70 RequestError::Utf8Error(err)
71 }
72}
73
74#[cfg(feature = "aio_tokio")]
75impl From<Elapsed> for RequestError {
76 fn from(_err: Elapsed) -> RequestError {
77 RequestError::IoError(io::Error::new(io::ErrorKind::TimedOut, "timer failed"))
78 }
79}
80
81#[cfg(feature = "aio_tokio")]
82impl From<hyper_util::client::legacy::Error> for RequestError {
83 fn from(err: hyper_util::client::legacy::Error) -> Self {
84 RequestError::HyperClientError(err)
85 }
86}
87
88impl fmt::Display for RequestError {
89 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
90 match *self {
91 RequestError::AttoHttpError(ref e) => write!(f, "HTTP error {e}"),
92 RequestError::InvalidResponse(ref e) => write!(f, "Invalid response from gateway: {e}"),
93 RequestError::IoError(ref e) => write!(f, "IO error. {e}"),
94 RequestError::ErrorCode(n, ref e) => write!(f, "Gateway response error {n}: {e}"),
95 RequestError::UnsupportedAction(ref e) => write!(f, "Gateway does not support action: {e}"),
96 #[cfg(feature = "aio_tokio")]
97 RequestError::HyperError(ref e) => write!(f, "Hyper Error: {e}"),
98 #[cfg(feature = "aio_tokio")]
99 RequestError::HyperClientError(ref e) => write!(f, "Hyper Client Error: {e}"),
100 #[cfg(feature = "aio_tokio")]
101 RequestError::HttpError(ref e) => write!(f, "Http Error: {e}"),
102 #[cfg(feature = "aio_tokio")]
103 RequestError::Utf8Error(ref e) => write!(f, "Utf8Error Error: {e}"),
104 }
105 }
106}
107
108impl std::error::Error for RequestError {
109 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
110 match *self {
111 RequestError::AttoHttpError(ref e) => Some(e),
112 RequestError::InvalidResponse(..) => None,
113 RequestError::IoError(ref e) => Some(e),
114 RequestError::ErrorCode(..) => None,
115 RequestError::UnsupportedAction(..) => None,
116 #[cfg(feature = "aio_tokio")]
117 RequestError::HyperError(ref e) => Some(e),
118 #[cfg(feature = "aio_tokio")]
119 RequestError::HyperClientError(ref e) => Some(e),
120 #[cfg(feature = "aio_tokio")]
121 RequestError::HttpError(ref e) => Some(e),
122 #[cfg(feature = "aio_tokio")]
123 RequestError::Utf8Error(ref e) => Some(e),
124 }
125 }
126}
127
128#[derive(Debug)]
130pub enum GetExternalIpError {
131 ActionNotAuthorized,
133 RequestError(RequestError),
135}
136
137#[derive(Debug)]
139pub enum RemovePortError {
140 ActionNotAuthorized,
142 NoSuchPortMapping,
144 RequestError(RequestError),
146}
147
148#[derive(Debug)]
150pub enum AddAnyPortError {
151 ActionNotAuthorized,
153 InternalPortZeroInvalid,
155 NoPortsAvailable,
157 ExternalPortInUse,
160 OnlyPermanentLeasesSupported,
162 DescriptionTooLong,
164 RequestError(RequestError),
166}
167
168impl From<RequestError> for AddAnyPortError {
169 fn from(err: RequestError) -> AddAnyPortError {
170 AddAnyPortError::RequestError(err)
171 }
172}
173
174impl From<GetExternalIpError> for AddAnyPortError {
175 fn from(err: GetExternalIpError) -> AddAnyPortError {
176 match err {
177 GetExternalIpError::ActionNotAuthorized => AddAnyPortError::ActionNotAuthorized,
178 GetExternalIpError::RequestError(e) => AddAnyPortError::RequestError(e),
179 }
180 }
181}
182
183#[derive(Debug)]
185pub enum AddPortError {
186 ActionNotAuthorized,
188 InternalPortZeroInvalid,
190 ExternalPortZeroInvalid,
192 PortInUse,
194 SamePortValuesRequired,
196 OnlyPermanentLeasesSupported,
198 DescriptionTooLong,
200 RequestError(RequestError),
202}
203
204impl fmt::Display for GetExternalIpError {
205 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
206 match *self {
207 GetExternalIpError::ActionNotAuthorized => write!(f, "The client is not authorized to remove the port"),
208 GetExternalIpError::RequestError(ref e) => write!(f, "Request Error. {e}"),
209 }
210 }
211}
212
213impl From<io::Error> for GetExternalIpError {
214 fn from(err: io::Error) -> GetExternalIpError {
215 GetExternalIpError::RequestError(RequestError::from(err))
216 }
217}
218
219impl std::error::Error for GetExternalIpError {
220 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
221 None
222 }
223}
224
225impl fmt::Display for RemovePortError {
226 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
227 match *self {
228 RemovePortError::ActionNotAuthorized => write!(f, "The client is not authorized to remove the port"),
229 RemovePortError::NoSuchPortMapping => write!(f, "The port was not mapped"),
230 RemovePortError::RequestError(ref e) => write!(f, "Request error. {e}"),
231 }
232 }
233}
234
235impl std::error::Error for RemovePortError {
236 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
237 None
238 }
239}
240
241impl fmt::Display for AddAnyPortError {
242 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
243 match *self {
244 AddAnyPortError::ActionNotAuthorized => {
245 write!(f, "The client is not authorized to remove the port")
246 }
247 AddAnyPortError::InternalPortZeroInvalid => {
248 write!(f, "Can not add a mapping for local port 0")
249 }
250 AddAnyPortError::NoPortsAvailable => {
251 write!(f, "The gateway does not have any free ports")
252 }
253 AddAnyPortError::OnlyPermanentLeasesSupported => {
254 write!(
255 f,
256 "The gateway only supports permanent leases (ie. a `lease_duration` of 0),"
257 )
258 }
259 AddAnyPortError::ExternalPortInUse => {
260 write!(
261 f,
262 "The gateway can only map internal ports to same-numbered external ports and this external port is in use."
263 )
264 }
265 AddAnyPortError::DescriptionTooLong => {
266 write!(f, "The description was too long for the gateway to handle.")
267 }
268 AddAnyPortError::RequestError(ref e) => write!(f, "Request error. {e}"),
269 }
270 }
271}
272
273impl std::error::Error for AddAnyPortError {
274 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
275 None
276 }
277}
278
279impl fmt::Display for AddPortError {
280 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
281 match *self {
282 AddPortError::ActionNotAuthorized => write!(f, "The client is not authorized to map this port."),
283 AddPortError::InternalPortZeroInvalid => write!(f, "Can not add a mapping for local port 0"),
284 AddPortError::ExternalPortZeroInvalid => write!(
285 f,
286 "External port number 0 (any port) is considered invalid by the gateway."
287 ),
288 AddPortError::PortInUse => write!(
289 f,
290 "The requested mapping conflicts with a mapping assigned to another client."
291 ),
292 AddPortError::SamePortValuesRequired => write!(
293 f,
294 "The gateway requires that the requested internal and external ports are the same."
295 ),
296 AddPortError::OnlyPermanentLeasesSupported => write!(
297 f,
298 "The gateway only supports permanent leases (ie. a `lease_duration` of 0),"
299 ),
300 AddPortError::DescriptionTooLong => write!(f, "The description was too long for the gateway to handle."),
301 AddPortError::RequestError(ref e) => write!(f, "Request error. {e}"),
302 }
303 }
304}
305
306impl std::error::Error for AddPortError {
307 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
308 None
309 }
310}
311
312#[derive(Debug)]
314pub enum SearchError {
315 HttpError(attohttpc::Error),
317 InvalidResponse,
319 NoResponseWithinTimeout,
321 IoError(io::Error),
323 Utf8Error(str::Utf8Error),
325 XmlError(xmltree::ParseError),
327 #[cfg(feature = "aio_tokio")]
329 HyperError(hyper::Error),
330 #[cfg(feature = "aio_tokio")]
332 HyperClientError(hyper_util::client::legacy::Error),
333 #[cfg(feature = "aio_tokio")]
335 InvalidUri(hyper::http::uri::InvalidUri),
336}
337
338impl From<attohttpc::Error> for SearchError {
339 fn from(err: attohttpc::Error) -> SearchError {
340 SearchError::HttpError(err)
341 }
342}
343
344impl From<io::Error> for SearchError {
345 fn from(err: io::Error) -> SearchError {
346 SearchError::IoError(err)
347 }
348}
349
350impl From<str::Utf8Error> for SearchError {
351 fn from(err: str::Utf8Error) -> SearchError {
352 SearchError::Utf8Error(err)
353 }
354}
355
356impl From<xmltree::ParseError> for SearchError {
357 fn from(err: xmltree::ParseError) -> SearchError {
358 SearchError::XmlError(err)
359 }
360}
361
362#[cfg(feature = "aio_tokio")]
363impl From<hyper::Error> for SearchError {
364 fn from(err: hyper::Error) -> SearchError {
365 SearchError::HyperError(err)
366 }
367}
368
369#[cfg(feature = "aio_tokio")]
370impl From<hyper::http::uri::InvalidUri> for SearchError {
371 fn from(err: hyper::http::uri::InvalidUri) -> SearchError {
372 SearchError::InvalidUri(err)
373 }
374}
375
376#[cfg(feature = "aio_tokio")]
377impl From<Elapsed> for SearchError {
378 fn from(_err: Elapsed) -> SearchError {
379 SearchError::IoError(io::Error::new(io::ErrorKind::TimedOut, "search timed out"))
380 }
381}
382
383#[cfg(feature = "aio_tokio")]
384impl From<hyper_util::client::legacy::Error> for SearchError {
385 fn from(err: hyper_util::client::legacy::Error) -> Self {
386 SearchError::HyperClientError(err)
387 }
388}
389
390impl fmt::Display for SearchError {
391 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
392 match *self {
393 SearchError::HttpError(ref e) => write!(f, "HTTP error {e}"),
394 SearchError::InvalidResponse => write!(f, "Invalid response"),
395 SearchError::NoResponseWithinTimeout => write!(f, "No response within timeout"),
396 SearchError::IoError(ref e) => write!(f, "IO error: {e}"),
397 SearchError::Utf8Error(ref e) => write!(f, "UTF-8 error: {e}"),
398 SearchError::XmlError(ref e) => write!(f, "XML error: {e}"),
399 #[cfg(feature = "aio_tokio")]
400 SearchError::HyperError(ref e) => write!(f, "Hyper Error: {e}"),
401 #[cfg(feature = "aio_tokio")]
402 SearchError::HyperClientError(ref e) => write!(f, "Hyper Client Error: {e}"),
403 #[cfg(feature = "aio_tokio")]
404 SearchError::InvalidUri(ref e) => write!(f, "InvalidUri Error: {e}"),
405 }
406 }
407}
408
409impl error::Error for SearchError {
410 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
411 match *self {
412 SearchError::HttpError(ref e) => Some(e),
413 SearchError::InvalidResponse => None,
414 SearchError::NoResponseWithinTimeout => None,
415 SearchError::IoError(ref e) => Some(e),
416 SearchError::Utf8Error(ref e) => Some(e),
417 SearchError::XmlError(ref e) => Some(e),
418 #[cfg(feature = "aio_tokio")]
419 SearchError::HyperError(ref e) => Some(e),
420 #[cfg(feature = "aio_tokio")]
421 SearchError::HyperClientError(ref e) => Some(e),
422 #[cfg(feature = "aio_tokio")]
423 SearchError::InvalidUri(ref e) => Some(e),
424 }
425 }
426}
427
428#[derive(Debug)]
430pub enum GetGenericPortMappingEntryError {
431 ActionNotAuthorized,
433 SpecifiedArrayIndexInvalid,
435 RequestError(RequestError),
437}
438
439impl From<RequestError> for GetGenericPortMappingEntryError {
440 fn from(err: RequestError) -> GetGenericPortMappingEntryError {
441 match err {
442 RequestError::ErrorCode(606, _) => GetGenericPortMappingEntryError::ActionNotAuthorized,
443 RequestError::ErrorCode(713, _) => GetGenericPortMappingEntryError::SpecifiedArrayIndexInvalid,
444 other => GetGenericPortMappingEntryError::RequestError(other),
445 }
446 }
447}
448
449impl fmt::Display for GetGenericPortMappingEntryError {
450 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
451 match *self {
452 GetGenericPortMappingEntryError::ActionNotAuthorized => {
453 write!(f, "The client is not authorized to look up port mappings.")
454 }
455 GetGenericPortMappingEntryError::SpecifiedArrayIndexInvalid => {
456 write!(f, "The provided index into the port mapping list is invalid.")
457 }
458 GetGenericPortMappingEntryError::RequestError(ref e) => e.fmt(f),
459 }
460 }
461}
462
463impl std::error::Error for GetGenericPortMappingEntryError {}
464
465#[derive(Debug)]
467pub enum Error {
468 AddAnyPortError(AddAnyPortError),
470 AddPortError(AddPortError),
472 GetExternalIpError(GetExternalIpError),
474 RemovePortError(RemovePortError),
476 RequestError(RequestError),
478 SearchError(SearchError),
480}
481
482pub type Result<T = ()> = std::result::Result<T, Error>;
484
485impl fmt::Display for Error {
486 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
487 match *self {
488 Error::AddAnyPortError(ref e) => e.fmt(f),
489 Error::AddPortError(ref e) => e.fmt(f),
490 Error::GetExternalIpError(ref e) => e.fmt(f),
491 Error::RemovePortError(ref e) => e.fmt(f),
492 Error::RequestError(ref e) => e.fmt(f),
493 Error::SearchError(ref e) => e.fmt(f),
494 }
495 }
496}
497
498impl error::Error for Error {
499 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
500 match *self {
501 Error::AddAnyPortError(ref e) => Some(e),
502 Error::AddPortError(ref e) => Some(e),
503 Error::GetExternalIpError(ref e) => Some(e),
504 Error::RemovePortError(ref e) => Some(e),
505 Error::RequestError(ref e) => Some(e),
506 Error::SearchError(ref e) => Some(e),
507 }
508 }
509}
510
511impl From<AddAnyPortError> for Error {
512 fn from(err: AddAnyPortError) -> Error {
513 Error::AddAnyPortError(err)
514 }
515}
516
517impl From<AddPortError> for Error {
518 fn from(err: AddPortError) -> Error {
519 Error::AddPortError(err)
520 }
521}
522
523impl From<GetExternalIpError> for Error {
524 fn from(err: GetExternalIpError) -> Error {
525 Error::GetExternalIpError(err)
526 }
527}
528
529impl From<RemovePortError> for Error {
530 fn from(err: RemovePortError) -> Error {
531 Error::RemovePortError(err)
532 }
533}
534
535impl From<RequestError> for Error {
536 fn from(err: RequestError) -> Error {
537 Error::RequestError(err)
538 }
539}
540
541impl From<SearchError> for Error {
542 fn from(err: SearchError) -> Error {
543 Error::SearchError(err)
544 }
545}