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