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 #[cfg(feature = "aio_tokio")]
32 HyperClientError(hyper_util::client::legacy::Error),
33
34 #[cfg(feature = "aio_async_std")]
36 SurfError(surf::Error),
37
38 #[cfg(any(feature = "aio_tokio", feature = "aio_async_std"))]
39 HttpError(http::Error),
41
42 #[cfg(any(feature = "aio_tokio", feature = "aio_async_std"))]
43 Utf8Error(FromUtf8Error),
45}
46
47impl From<attohttpc::Error> for RequestError {
48 fn from(err: attohttpc::Error) -> RequestError {
49 RequestError::AttoHttpError(err)
50 }
51}
52
53impl From<io::Error> for RequestError {
54 fn from(err: io::Error) -> RequestError {
55 RequestError::IoError(err)
56 }
57}
58
59#[cfg(any(feature = "aio_tokio", feature = "aio_async_std"))]
60impl From<http::Error> for RequestError {
61 fn from(err: http::Error) -> RequestError {
62 RequestError::HttpError(err)
63 }
64}
65
66#[cfg(feature = "aio_async_std")]
67impl From<surf::Error> for RequestError {
68 fn from(err: surf::Error) -> RequestError {
69 RequestError::SurfError(err)
70 }
71}
72
73#[cfg(feature = "aio_tokio")]
74impl From<hyper::Error> for RequestError {
75 fn from(err: hyper::Error) -> RequestError {
76 RequestError::HyperError(err)
77 }
78}
79
80#[cfg(any(feature = "aio_tokio", feature = "aio_async_std"))]
81impl From<FromUtf8Error> for RequestError {
82 fn from(err: FromUtf8Error) -> RequestError {
83 RequestError::Utf8Error(err)
84 }
85}
86
87#[cfg(feature = "aio_async_std")]
88impl From<TimeoutError> for RequestError {
89 fn from(_err: TimeoutError) -> RequestError {
90 RequestError::IoError(io::Error::new(io::ErrorKind::TimedOut, "timer failed"))
91 }
92}
93
94#[cfg(feature = "aio_tokio")]
95impl From<Elapsed> for RequestError {
96 fn from(_err: Elapsed) -> RequestError {
97 RequestError::IoError(io::Error::new(io::ErrorKind::TimedOut, "timer failed"))
98 }
99}
100
101#[cfg(feature = "aio_tokio")]
102impl From<hyper_util::client::legacy::Error> for RequestError {
103 fn from(err: hyper_util::client::legacy::Error) -> Self {
104 RequestError::HyperClientError(err)
105 }
106}
107
108impl fmt::Display for RequestError {
109 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
110 match *self {
111 RequestError::AttoHttpError(ref e) => write!(f, "HTTP error {e}"),
112 RequestError::InvalidResponse(ref e) => write!(f, "Invalid response from gateway: {e}"),
113 RequestError::IoError(ref e) => write!(f, "IO error. {e}"),
114 RequestError::ErrorCode(n, ref e) => write!(f, "Gateway response error {n}: {e}"),
115 RequestError::UnsupportedAction(ref e) => write!(f, "Gateway does not support action: {e}"),
116 #[cfg(feature = "aio_async_std")]
117 RequestError::SurfError(ref e) => write!(f, "Surf Error: {e}"),
118 #[cfg(feature = "aio_tokio")]
119 RequestError::HyperError(ref e) => write!(f, "Hyper Error: {e}"),
120 #[cfg(feature = "aio_tokio")]
121 RequestError::HyperClientError(ref e) => write!(f, "Hyper Client Error: {e}"),
122 #[cfg(any(feature = "aio_tokio", feature = "aio_async_std"))]
123 RequestError::HttpError(ref e) => write!(f, "Http Error: {e}"),
124 #[cfg(any(feature = "aio_tokio", feature = "aio_async_std"))]
125 RequestError::Utf8Error(ref e) => write!(f, "Utf8Error Error: {e}"),
126 }
127 }
128}
129
130impl std::error::Error for RequestError {
131 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
132 match *self {
133 RequestError::AttoHttpError(ref e) => Some(e),
134 RequestError::InvalidResponse(..) => None,
135 RequestError::IoError(ref e) => Some(e),
136 RequestError::ErrorCode(..) => None,
137 RequestError::UnsupportedAction(..) => None,
138 #[cfg(feature = "aio_async_std")]
139 RequestError::SurfError(ref e) => Some(e.as_ref()),
140 #[cfg(feature = "aio_tokio")]
141 RequestError::HyperError(ref e) => Some(e),
142 #[cfg(feature = "aio_tokio")]
143 RequestError::HyperClientError(ref e) => Some(e),
144 #[cfg(any(feature = "aio_tokio", feature = "aio_async_std"))]
145 RequestError::HttpError(ref e) => Some(e),
146 #[cfg(any(feature = "aio_tokio", feature = "aio_async_std"))]
147 RequestError::Utf8Error(ref e) => Some(e),
148 }
149 }
150}
151
152#[derive(Debug)]
154pub enum GetExternalIpError {
155 ActionNotAuthorized,
157 RequestError(RequestError),
159}
160
161#[derive(Debug)]
163pub enum RemovePortError {
164 ActionNotAuthorized,
166 NoSuchPortMapping,
168 RequestError(RequestError),
170}
171
172#[derive(Debug)]
174pub enum AddAnyPortError {
175 ActionNotAuthorized,
177 InternalPortZeroInvalid,
179 NoPortsAvailable,
181 ExternalPortInUse,
184 OnlyPermanentLeasesSupported,
186 DescriptionTooLong,
188 RequestError(RequestError),
190}
191
192impl From<RequestError> for AddAnyPortError {
193 fn from(err: RequestError) -> AddAnyPortError {
194 AddAnyPortError::RequestError(err)
195 }
196}
197
198impl From<GetExternalIpError> for AddAnyPortError {
199 fn from(err: GetExternalIpError) -> AddAnyPortError {
200 match err {
201 GetExternalIpError::ActionNotAuthorized => AddAnyPortError::ActionNotAuthorized,
202 GetExternalIpError::RequestError(e) => AddAnyPortError::RequestError(e),
203 }
204 }
205}
206
207#[derive(Debug)]
209pub enum AddPortError {
210 ActionNotAuthorized,
212 InternalPortZeroInvalid,
214 ExternalPortZeroInvalid,
216 PortInUse,
218 SamePortValuesRequired,
220 OnlyPermanentLeasesSupported,
222 DescriptionTooLong,
224 RequestError(RequestError),
226}
227
228impl fmt::Display for GetExternalIpError {
229 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
230 match *self {
231 GetExternalIpError::ActionNotAuthorized => write!(f, "The client is not authorized to remove the port"),
232 GetExternalIpError::RequestError(ref e) => write!(f, "Request Error. {e}"),
233 }
234 }
235}
236
237impl From<io::Error> for GetExternalIpError {
238 fn from(err: io::Error) -> GetExternalIpError {
239 GetExternalIpError::RequestError(RequestError::from(err))
240 }
241}
242
243impl std::error::Error for GetExternalIpError {
244 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
245 None
246 }
247}
248
249impl fmt::Display for RemovePortError {
250 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
251 match *self {
252 RemovePortError::ActionNotAuthorized => write!(f, "The client is not authorized to remove the port"),
253 RemovePortError::NoSuchPortMapping => write!(f, "The port was not mapped"),
254 RemovePortError::RequestError(ref e) => write!(f, "Request error. {e}"),
255 }
256 }
257}
258
259impl std::error::Error for RemovePortError {
260 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
261 None
262 }
263}
264
265impl fmt::Display for AddAnyPortError {
266 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
267 match *self {
268 AddAnyPortError::ActionNotAuthorized => {
269 write!(f, "The client is not authorized to remove the port")
270 }
271 AddAnyPortError::InternalPortZeroInvalid => {
272 write!(f, "Can not add a mapping for local port 0")
273 }
274 AddAnyPortError::NoPortsAvailable => {
275 write!(f, "The gateway does not have any free ports")
276 }
277 AddAnyPortError::OnlyPermanentLeasesSupported => {
278 write!(
279 f,
280 "The gateway only supports permanent leases (ie. a `lease_duration` of 0),"
281 )
282 }
283 AddAnyPortError::ExternalPortInUse => {
284 write!(
285 f,
286 "The gateway can only map internal ports to same-numbered external ports and this external port is in use."
287 )
288 }
289 AddAnyPortError::DescriptionTooLong => {
290 write!(f, "The description was too long for the gateway to handle.")
291 }
292 AddAnyPortError::RequestError(ref e) => write!(f, "Request error. {e}"),
293 }
294 }
295}
296
297impl std::error::Error for AddAnyPortError {
298 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
299 None
300 }
301}
302
303impl fmt::Display for AddPortError {
304 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
305 match *self {
306 AddPortError::ActionNotAuthorized => write!(f, "The client is not authorized to map this port."),
307 AddPortError::InternalPortZeroInvalid => write!(f, "Can not add a mapping for local port 0"),
308 AddPortError::ExternalPortZeroInvalid => write!(
309 f,
310 "External port number 0 (any port) is considered invalid by the gateway."
311 ),
312 AddPortError::PortInUse => write!(
313 f,
314 "The requested mapping conflicts with a mapping assigned to another client."
315 ),
316 AddPortError::SamePortValuesRequired => write!(
317 f,
318 "The gateway requires that the requested internal and external ports are the same."
319 ),
320 AddPortError::OnlyPermanentLeasesSupported => write!(
321 f,
322 "The gateway only supports permanent leases (ie. a `lease_duration` of 0),"
323 ),
324 AddPortError::DescriptionTooLong => write!(f, "The description was too long for the gateway to handle."),
325 AddPortError::RequestError(ref e) => write!(f, "Request error. {e}"),
326 }
327 }
328}
329
330impl std::error::Error for AddPortError {
331 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
332 None
333 }
334}
335
336#[derive(Debug)]
338pub enum SearchError {
339 HttpError(attohttpc::Error),
341 InvalidResponse,
343 NoResponseWithinTimeout,
345 IoError(io::Error),
347 Utf8Error(str::Utf8Error),
349 XmlError(xmltree::ParseError),
351 #[cfg(feature = "aio_async_std")]
353 SurfError(surf::Error),
354 #[cfg(feature = "aio_tokio")]
356 HyperError(hyper::Error),
357 #[cfg(feature = "aio_tokio")]
359 HyperClientError(hyper_util::client::legacy::Error),
360 #[cfg(feature = "aio_tokio")]
362 InvalidUri(hyper::http::uri::InvalidUri),
363}
364
365impl From<attohttpc::Error> for SearchError {
366 fn from(err: attohttpc::Error) -> SearchError {
367 SearchError::HttpError(err)
368 }
369}
370
371impl From<io::Error> for SearchError {
372 fn from(err: io::Error) -> SearchError {
373 SearchError::IoError(err)
374 }
375}
376
377impl From<str::Utf8Error> for SearchError {
378 fn from(err: str::Utf8Error) -> SearchError {
379 SearchError::Utf8Error(err)
380 }
381}
382
383impl From<xmltree::ParseError> for SearchError {
384 fn from(err: xmltree::ParseError) -> SearchError {
385 SearchError::XmlError(err)
386 }
387}
388
389#[cfg(feature = "aio_async_std")]
390impl From<surf::Error> for SearchError {
391 fn from(err: surf::Error) -> SearchError {
392 SearchError::SurfError(err)
393 }
394}
395
396#[cfg(feature = "aio_tokio")]
397impl From<hyper::Error> for SearchError {
398 fn from(err: hyper::Error) -> SearchError {
399 SearchError::HyperError(err)
400 }
401}
402
403#[cfg(feature = "aio_tokio")]
404impl From<hyper::http::uri::InvalidUri> for SearchError {
405 fn from(err: hyper::http::uri::InvalidUri) -> SearchError {
406 SearchError::InvalidUri(err)
407 }
408}
409
410#[cfg(feature = "aio_async_std")]
411impl From<TimeoutError> for SearchError {
412 fn from(_err: TimeoutError) -> SearchError {
413 SearchError::IoError(io::Error::new(io::ErrorKind::TimedOut, "timer failed"))
414 }
415}
416
417#[cfg(feature = "aio_tokio")]
418impl From<Elapsed> for SearchError {
419 fn from(_err: Elapsed) -> SearchError {
420 SearchError::IoError(io::Error::new(io::ErrorKind::TimedOut, "search timed out"))
421 }
422}
423
424#[cfg(feature = "aio_tokio")]
425impl From<hyper_util::client::legacy::Error> for SearchError {
426 fn from(err: hyper_util::client::legacy::Error) -> Self {
427 SearchError::HyperClientError(err)
428 }
429}
430
431impl fmt::Display for SearchError {
432 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
433 match *self {
434 SearchError::HttpError(ref e) => write!(f, "HTTP error {e}"),
435 SearchError::InvalidResponse => write!(f, "Invalid response"),
436 SearchError::NoResponseWithinTimeout => write!(f, "No response within timeout"),
437 SearchError::IoError(ref e) => write!(f, "IO error: {e}"),
438 SearchError::Utf8Error(ref e) => write!(f, "UTF-8 error: {e}"),
439 SearchError::XmlError(ref e) => write!(f, "XML error: {e}"),
440 #[cfg(feature = "aio_async_std")]
441 SearchError::SurfError(ref e) => write!(f, "Surf Error: {e}"),
442 #[cfg(feature = "aio_tokio")]
443 SearchError::HyperError(ref e) => write!(f, "Hyper Error: {e}"),
444 #[cfg(feature = "aio_tokio")]
445 SearchError::HyperClientError(ref e) => write!(f, "Hyper Client Error: {e}"),
446 #[cfg(feature = "aio_tokio")]
447 SearchError::InvalidUri(ref e) => write!(f, "InvalidUri Error: {e}"),
448 }
449 }
450}
451
452impl error::Error for SearchError {
453 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
454 match *self {
455 SearchError::HttpError(ref e) => Some(e),
456 SearchError::InvalidResponse => None,
457 SearchError::NoResponseWithinTimeout => None,
458 SearchError::IoError(ref e) => Some(e),
459 SearchError::Utf8Error(ref e) => Some(e),
460 SearchError::XmlError(ref e) => Some(e),
461 #[cfg(feature = "aio_async_std")]
462 SearchError::SurfError(ref e) => Some(e.as_ref()),
463 #[cfg(feature = "aio_tokio")]
464 SearchError::HyperError(ref e) => Some(e),
465 #[cfg(feature = "aio_tokio")]
466 SearchError::HyperClientError(ref e) => Some(e),
467 #[cfg(feature = "aio_tokio")]
468 SearchError::InvalidUri(ref e) => Some(e),
469 }
470 }
471}
472
473#[derive(Debug)]
475pub enum GetGenericPortMappingEntryError {
476 ActionNotAuthorized,
478 SpecifiedArrayIndexInvalid,
480 RequestError(RequestError),
482}
483
484impl From<RequestError> for GetGenericPortMappingEntryError {
485 fn from(err: RequestError) -> GetGenericPortMappingEntryError {
486 match err {
487 RequestError::ErrorCode(606, _) => GetGenericPortMappingEntryError::ActionNotAuthorized,
488 RequestError::ErrorCode(713, _) => GetGenericPortMappingEntryError::SpecifiedArrayIndexInvalid,
489 other => GetGenericPortMappingEntryError::RequestError(other),
490 }
491 }
492}
493
494impl fmt::Display for GetGenericPortMappingEntryError {
495 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
496 match *self {
497 GetGenericPortMappingEntryError::ActionNotAuthorized => {
498 write!(f, "The client is not authorized to look up port mappings.")
499 }
500 GetGenericPortMappingEntryError::SpecifiedArrayIndexInvalid => {
501 write!(f, "The provided index into the port mapping list is invalid.")
502 }
503 GetGenericPortMappingEntryError::RequestError(ref e) => e.fmt(f),
504 }
505 }
506}
507
508impl std::error::Error for GetGenericPortMappingEntryError {}
509
510#[derive(Debug)]
512pub enum Error {
513 AddAnyPortError(AddAnyPortError),
515 AddPortError(AddPortError),
517 GetExternalIpError(GetExternalIpError),
519 RemovePortError(RemovePortError),
521 RequestError(RequestError),
523 SearchError(SearchError),
525}
526
527pub type Result<T = ()> = std::result::Result<T, Error>;
529
530impl fmt::Display for Error {
531 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
532 match *self {
533 Error::AddAnyPortError(ref e) => e.fmt(f),
534 Error::AddPortError(ref e) => e.fmt(f),
535 Error::GetExternalIpError(ref e) => e.fmt(f),
536 Error::RemovePortError(ref e) => e.fmt(f),
537 Error::RequestError(ref e) => e.fmt(f),
538 Error::SearchError(ref e) => e.fmt(f),
539 }
540 }
541}
542
543impl error::Error for Error {
544 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
545 match *self {
546 Error::AddAnyPortError(ref e) => Some(e),
547 Error::AddPortError(ref e) => Some(e),
548 Error::GetExternalIpError(ref e) => Some(e),
549 Error::RemovePortError(ref e) => Some(e),
550 Error::RequestError(ref e) => Some(e),
551 Error::SearchError(ref e) => Some(e),
552 }
553 }
554}
555
556impl From<AddAnyPortError> for Error {
557 fn from(err: AddAnyPortError) -> Error {
558 Error::AddAnyPortError(err)
559 }
560}
561
562impl From<AddPortError> for Error {
563 fn from(err: AddPortError) -> Error {
564 Error::AddPortError(err)
565 }
566}
567
568impl From<GetExternalIpError> for Error {
569 fn from(err: GetExternalIpError) -> Error {
570 Error::GetExternalIpError(err)
571 }
572}
573
574impl From<RemovePortError> for Error {
575 fn from(err: RemovePortError) -> Error {
576 Error::RemovePortError(err)
577 }
578}
579
580impl From<RequestError> for Error {
581 fn from(err: RequestError) -> Error {
582 Error::RequestError(err)
583 }
584}
585
586impl From<SearchError> for Error {
587 fn from(err: SearchError) -> Error {
588 Error::SearchError(err)
589 }
590}