use failure::{Error, Fail};
use serde::{Serialize, Deserialize};
#[derive(Serialize, Deserialize, Clone, Debug)]
pub enum ApiErrorReason {
BadCollapseId,
BadDeviceToken,
BadExpirationDate,
BadMessageId,
BadPriority,
BadTopic,
DeviceTokenNotForTopic,
DuplicateHeaders,
IdleTimeout,
MissingDeviceToken,
MissingTopic,
PayloadEmpty,
TopicDisallowed,
BadCertificate,
BadCertificateEnvironment,
ExpiredProviderToken,
Forbidden,
InvalidProviderToken,
MissingProviderToken,
BadPath,
MethodNotAllowed,
Unregistered,
PayloadTooLarge,
TooManyProviderTokenUpdates,
TooManyRequests,
InternalServerError,
ServiceUnavailable,
Shutdown,
Other(String),
}
impl ApiErrorReason {
fn from_str(value: &str) -> Self {
use self::ApiErrorReason::*;
match value {
"BadCollapseId" => BadCollapseId,
"BadDeviceToken" => BadDeviceToken,
"BadExpirationDate" => BadExpirationDate,
"BadMessageId" => BadMessageId,
"BadPriority" => BadPriority,
"BadTopic" => BadTopic,
"DeviceTokenNotForTopic" => DeviceTokenNotForTopic,
"DuplicateHeaders" => DuplicateHeaders,
"IdleTimeout" => IdleTimeout,
"MissingDeviceToken" => MissingDeviceToken,
"MissingTopic" => MissingTopic,
"PayloadEmpty" => PayloadEmpty,
"TopicDisallowed" => TopicDisallowed,
"BadCertificate" => BadCertificate,
"BadCertificateEnvironment" => BadCertificateEnvironment,
"ExpiredProviderToken" => ExpiredProviderToken,
"Forbidden" => Forbidden,
"InvalidProviderToken" => InvalidProviderToken,
"MissingProviderToken" => MissingProviderToken,
"BadPath" => BadPath,
"MethodNotAllowed" => MethodNotAllowed,
"Unregistered" => Unregistered,
"PayloadTooLarge" => PayloadTooLarge,
"TooManyProviderTokenUpdates" => TooManyProviderTokenUpdates,
"TooManyRequests" => TooManyRequests,
"InternalServerError" => InternalServerError,
"ServiceUnavailable" => ServiceUnavailable,
"Shutdown" => Shutdown,
x => Other(x.to_string()),
}
}
fn to_str(&self) -> &str {
use self::ApiErrorReason::*;
match self {
&BadCollapseId => "BadCollapseId",
&BadDeviceToken => "BadDeviceToken",
&BadExpirationDate => "BadExpirationDate",
&BadMessageId => "BadMessageId",
&BadPriority => "BadPriority",
&BadTopic => "BadTopic",
&DeviceTokenNotForTopic => "DeviceTokenNotForTopic",
&DuplicateHeaders => "DuplicateHeaders",
&IdleTimeout => "IdleTimeout",
&MissingDeviceToken => "MissingDeviceToken",
&MissingTopic => "MissingTopic",
&PayloadEmpty => "PayloadEmpty",
&TopicDisallowed => "TopicDisallowed",
&BadCertificate => "BadCertificate",
&BadCertificateEnvironment => "BadCertificateEnvironment",
&ExpiredProviderToken => "ExpiredProviderToken",
&Forbidden => "Forbidden",
&InvalidProviderToken => "InvalidProviderToken",
&MissingProviderToken => "MissingProviderToken",
&BadPath => "BadPath",
&MethodNotAllowed => "MethodNotAllowed",
&Unregistered => "Unregistered",
&PayloadTooLarge => "PayloadTooLarge",
&TooManyProviderTokenUpdates => "TooManyProviderTokenUpdates",
&TooManyRequests => "TooManyRequests",
&InternalServerError => "InternalServerError",
&ServiceUnavailable => "ServiceUnavailable",
&Shutdown => "Shutdown",
&Other(ref val) => val,
}
}
pub fn is_bad_device_token(&self) -> bool {
match self {
&ApiErrorReason::BadDeviceToken => true,
_ => false,
}
}
}
impl ::std::fmt::Display for ApiErrorReason {
fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
write!(f, "{}", self.to_str())
}
}
#[derive(Fail, Serialize, Deserialize, Clone, Debug)]
#[fail(display = "{} (status: {}", reason, status)]
pub struct ApiError {
pub status: u32,
pub reason: ApiErrorReason,
}
impl ApiError {
pub fn is_bad_device_token(&self) -> bool {
return self.reason.is_bad_device_token();
}
}
#[derive(Serialize, Deserialize, Clone, Debug)]
pub(crate) struct ErrorResponse {
pub reason: String,
}
impl ErrorResponse {
pub fn parse_payload(data: &[u8]) -> ApiErrorReason {
match ::serde_json::from_slice::<ErrorResponse>(data) {
Ok(response) => ApiErrorReason::from_str(&response.reason),
Err(_) => {
let msg = format!("Unknown API response: {:?}", data);
ApiErrorReason::Other(msg)
}
}
}
}
#[derive(Fail, Debug)]
pub enum SendError {
#[fail(display = "{}", _0)]
Api(ApiError),
#[fail(display = "{}", _0)]
Other(Error),
}
impl SendError {
pub fn as_api_error(&self) -> Option<&ApiError> {
match self {
&SendError::Api(ref e) => Some(e),
_ => None,
}
}
pub fn is_bad_device_token(&self) -> bool {
match self {
&SendError::Api(ref e) => e.is_bad_device_token(),
_ => false,
}
}
}
impl From<::curl::Error> for SendError {
fn from(e: ::curl::Error) -> Self {
SendError::Other(e.into())
}
}
impl From<::serde_json::Error> for SendError {
fn from(e: ::serde_json::Error) -> Self {
SendError::Other(e.into())
}
}
impl From<ApiError> for SendError {
fn from(e: ApiError) -> Self {
SendError::Api(e)
}
}