use base64::DecodeError;
use chrono;
use http::uri::InvalidUri;
use native_tls;
use openssl::error::ErrorStack;
use ring::error;
use serde_json::error::Error as JsonError;
use std::string::FromUtf8Error;
use std::time::{Duration, SystemTime};
use std::{convert::From, error::Error, fmt, io::Error as IoError};
#[derive(PartialEq, Debug)]
pub enum WebPushError {
Unspecified,
Unauthorized,
BadRequest(Option<String>),
ServerError(Option<Duration>),
NotImplemented,
InvalidUri,
EndpointNotValid,
EndpointNotFound,
PayloadTooLarge,
TlsError,
SslError,
IoError,
InvalidPackageName,
InvalidTtl,
MissingCryptoKeys,
InvalidCryptoKeys,
InvalidResponse,
Other(String),
}
impl From<JsonError> for WebPushError {
fn from(_: JsonError) -> WebPushError {
WebPushError::InvalidResponse
}
}
impl From<FromUtf8Error> for WebPushError {
fn from(_: FromUtf8Error) -> WebPushError {
WebPushError::InvalidResponse
}
}
impl From<InvalidUri> for WebPushError {
fn from(_: InvalidUri) -> WebPushError {
WebPushError::InvalidUri
}
}
impl From<error::Unspecified> for WebPushError {
fn from(_: error::Unspecified) -> WebPushError {
WebPushError::Unspecified
}
}
impl From<hyper::error::Error> for WebPushError {
fn from(_: hyper::error::Error) -> Self {
Self::Unspecified
}
}
impl From<native_tls::Error> for WebPushError {
fn from(_: native_tls::Error) -> WebPushError {
WebPushError::TlsError
}
}
impl From<IoError> for WebPushError {
fn from(_: IoError) -> WebPushError {
WebPushError::IoError
}
}
impl From<ErrorStack> for WebPushError {
fn from(_: ErrorStack) -> WebPushError {
WebPushError::SslError
}
}
impl From<DecodeError> for WebPushError {
fn from(_: DecodeError) -> WebPushError {
WebPushError::InvalidCryptoKeys
}
}
impl WebPushError {
pub fn short_description(&self) -> &'static str {
match *self {
WebPushError::Unspecified => "unspecified",
WebPushError::Unauthorized => "unauthorized",
WebPushError::BadRequest(_) => "bad_request",
WebPushError::ServerError(_) => "server_error",
WebPushError::NotImplemented => "not_implemented",
WebPushError::InvalidUri => "invalid_uri",
WebPushError::EndpointNotValid => "endpoint_not_valid",
WebPushError::EndpointNotFound => "endpoint_not_found",
WebPushError::PayloadTooLarge => "payload_too_large",
WebPushError::TlsError => "tls_error",
WebPushError::InvalidPackageName => "invalid_package_name",
WebPushError::InvalidTtl => "invalid_ttl",
WebPushError::InvalidResponse => "invalid_response",
WebPushError::MissingCryptoKeys => "missing_crypto_keys",
WebPushError::InvalidCryptoKeys => "invalid_crypto_keys",
WebPushError::SslError => "ssl_error",
WebPushError::IoError => "io_error",
WebPushError::Other(_) => "other",
}
}
}
impl Error for WebPushError {
fn description(&self) -> &str {
match *self {
WebPushError::Unspecified =>
"An unknown error happened encrypting the message",
WebPushError::Unauthorized =>
"Please provide valid credentials to send the notification",
WebPushError::BadRequest(_) =>
"Request was badly formed",
WebPushError::ServerError(_) =>
"Server was unable to process the request, please try again later",
WebPushError::PayloadTooLarge =>
"Maximum allowed payload size is 3070 characters",
WebPushError::InvalidUri =>
"The provided URI is invalid",
WebPushError::NotImplemented =>
"The feature is not implemented yet",
WebPushError::EndpointNotValid =>
"The URL specified is no longer valid and should no longer be used",
WebPushError::EndpointNotFound =>
"The URL specified is invalid and should not be used again",
WebPushError::TlsError =>
"Could not initialize a TLS connection",
WebPushError::SslError =>
"Error signing with SSL",
WebPushError::IoError =>
"Error opening a file",
WebPushError::InvalidPackageName =>
"Make sure the message was addressed to a registration token whose package name matches the value passed in the request.",
WebPushError::InvalidTtl => "The TTL value provided was not valid or was not provided",
WebPushError::InvalidResponse => "The response data couldn't be parses",
WebPushError::MissingCryptoKeys => "The request is missing cryptographic keys",
WebPushError::InvalidCryptoKeys => "The request is having invalid cryptographic keys",
WebPushError::Other(_) => "An unknown error when connecting the notification service",
}
}
fn cause(&self) -> Option<&dyn Error> {
None
}
}
impl fmt::Display for WebPushError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self.description())
}
}
pub struct RetryAfter;
impl RetryAfter {
pub fn from_str(header_value: &str) -> Option<Duration> {
if let Ok(seconds) = header_value.parse::<u64>() {
Some(Duration::from_secs(seconds))
} else {
chrono::DateTime::parse_from_rfc2822(header_value)
.map(|date_time| {
let systime: SystemTime = date_time.into();
systime
.duration_since(SystemTime::now())
.unwrap_or_else(|_| Duration::new(0, 0))
})
.ok()
}
}
}