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