extern crate hyper;
extern crate serde_json as json;
extern crate serde_qs as qs;
use params::to_snakecase;
use std::error;
use std::fmt;
use std::io;
use std::num::ParseIntError;
#[derive(Debug)]
pub enum Error {
Stripe(RequestError),
Http(hyper::Error),
Io(io::Error),
Conversion(Box<error::Error + Send>),
}
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.write_str(error::Error::description(self))?;
match *self {
Error::Stripe(ref err) => write!(f, ": {}", err),
Error::Http(ref err) => write!(f, ": {}", err),
Error::Io(ref err) => write!(f, ": {}", err),
Error::Conversion(ref err) => write!(f, ": {}", err),
}
}
}
impl error::Error for Error {
fn description(&self) -> &str {
match *self {
Error::Stripe(_) => "error reported by stripe",
Error::Http(_) => "error communicating with stripe",
Error::Io(_) => "error reading response from stripe",
Error::Conversion(_) => "error converting between wire format and Rust types",
}
}
fn cause(&self) -> Option<&error::Error> {
match *self {
Error::Stripe(ref err) => Some(err),
Error::Http(ref err) => Some(err),
Error::Io(ref err) => Some(err),
Error::Conversion(ref err) => Some(&**err),
}
}
}
impl From<RequestError> for Error {
fn from(err: RequestError) -> Error {
Error::Stripe(err)
}
}
impl From<hyper::Error> for Error {
fn from(err: hyper::Error) -> Error {
Error::Http(err)
}
}
impl From<io::Error> for Error {
fn from(err: io::Error) -> Error {
Error::Io(err)
}
}
impl From<qs::Error> for Error {
fn from(err: qs::Error) -> Error {
Error::Conversion(Box::new(err))
}
}
impl From<json::Error> for Error {
fn from(err: json::Error) -> Error {
Error::Conversion(Box::new(err))
}
}
#[derive(Debug, PartialEq, Deserialize)]
pub enum ErrorType {
#[serde(skip_deserializing)]
Unknown,
#[serde(rename = "api_error")]
Api,
#[serde(rename = "api_connection_error")]
Connection,
#[serde(rename = "authentication_error")]
Authentication,
#[serde(rename = "card_error")]
Card,
#[serde(rename = "invalid_request_error")]
InvalidRequest,
#[serde(rename = "rate_limit_error")]
RateLimit,
#[serde(rename = "validation_error")]
Validation,
}
impl Default for ErrorType {
fn default() -> Self {
ErrorType::Unknown
}
}
impl fmt::Display for ErrorType {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", to_snakecase(&format!("{:?}Error", self)))
}
}
#[derive(Debug, PartialEq, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum ErrorCode {
InvalidNumber,
InvalidExpiryMonth,
InvalidExpiryYear,
InvalidCvc,
InvalidSwipeData,
IncorrectNumber,
ExpiredCard,
IncorrectCvc,
IncorrectZip,
CardDeclined,
Missing,
ProcessingError,
}
impl fmt::Display for ErrorCode {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", to_snakecase(&format!("{:?}", self)))
}
}
#[derive(Debug, Default, Deserialize)]
pub struct RequestError {
#[serde(skip_deserializing)]
pub http_status: u16,
#[serde(rename = "type")]
pub error_type: ErrorType,
#[serde(default)]
pub message: Option<String>,
pub code: Option<ErrorCode>,
pub decline_code: Option<String>,
pub charge: Option<String>,
}
impl fmt::Display for RequestError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}({})", self.error_type, self.http_status)?;
if let Some(ref message) = self.message {
write!(f, ": {}", message)?;
}
Ok(())
}
}
impl error::Error for RequestError {
fn description(&self) -> &str {
self.message.as_ref().map(|s| s.as_str()).unwrap_or(
"request error",
)
}
}
#[doc(hidden)]
#[derive(Deserialize)]
pub struct ErrorObject {
pub error: RequestError,
}
#[derive(Debug)]
pub enum WebhookError {
BadHeader(ParseIntError),
BadSignature,
BadTimestamp(i64),
BadParse(json::Error),
}
impl fmt::Display for WebhookError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.write_str(error::Error::description(self))?;
match *self {
WebhookError::BadHeader(ref err) => write!(f, ": {}", err),
WebhookError::BadSignature => write!(f, "Signatures do not match"),
WebhookError::BadTimestamp(ref err) => write!(f, ": {}", err),
WebhookError::BadParse(ref err) => write!(f, ": {}", err),
}
}
}
impl error::Error for WebhookError {
fn description(&self) -> &str {
match *self {
WebhookError::BadHeader(_) => "error parsing timestamp",
WebhookError::BadSignature => "error comparing signatures",
WebhookError::BadTimestamp(_) => "error comparing timestamps - over tolerance",
WebhookError::BadParse(_) => "error parsing event object",
}
}
fn cause(&self) -> Option<&error::Error> {
match *self {
WebhookError::BadHeader(ref err) => Some(err),
WebhookError::BadSignature => None,
WebhookError::BadTimestamp(_) => None,
WebhookError::BadParse(ref err) => Some(err),
}
}
}