1use curl;
2use rustc_serialize::json::{Json, ParserError};
3use std::convert::From;
4use std::error::Error as StdError;
5use std::fmt;
6use std::str::Utf8Error;
7
8pub enum ErrorKind {
9 InvalidRequestError,
10 APIError,
11 CardError,
12 ConnectionError,
13 AuthentificationError,
14}
15
16pub enum ErrorCode {
17 IncorrectNumber,
18 InvalidNumber,
19 InvalidExpiryMonth,
20 InvalidExpiryYear,
21 InvalidCVC,
22 ExpiredCard,
23 IncorrectCVC,
24 IncorrectZIP,
25 CardDeclined,
26 Missing,
27 ProcessingError,
28 RateLimit,
29 Unknown,
30}
31
32pub struct Error {
33 kind: ErrorKind,
34 code: Option<ErrorCode>,
35 param: Option<String>,
36 message: Option<String>,
37}
38
39impl Error {
40 pub fn new(kind: ErrorKind, message: &str) -> Self {
41 Error { kind: kind, code: None, param: None, message: Some(message.to_string()) }
42 }
43
44 pub fn from_json(obj: &Json, http_status: u32) -> Self {
45 let kind = match http_status {
46 401 => ErrorKind::AuthentificationError,
47 _ => obj.find("type").map_or(ErrorKind::APIError, |t|
48 match &*t.to_string() {
49 "invalid_request_error" => ErrorKind::InvalidRequestError,
50 "card_error" => ErrorKind::CardError,
51 "api_error" | _ => ErrorKind::APIError,
52 }
53 ),
54 };
55 let code = obj.find("code").and_then(|c|
56 Some(match &*c.to_string() {
57 "incorrect_number" => ErrorCode::IncorrectNumber,
58 "invalid_number" => ErrorCode::InvalidNumber,
59 "invalid_expiry_month" => ErrorCode::InvalidExpiryMonth,
60 "invalid_expiry_year" => ErrorCode::InvalidExpiryYear,
61 "invalid_cvc" => ErrorCode::InvalidCVC,
62 "expired_card" => ErrorCode::ExpiredCard,
63 "incorrect_cvc" => ErrorCode::IncorrectCVC,
64 "incorrect_zip" => ErrorCode::IncorrectZIP,
65 "card_declined" => ErrorCode::CardDeclined,
66 "missing" => ErrorCode::Missing,
67 "processing_error" => ErrorCode::ProcessingError,
68 "rate_limit" => ErrorCode::RateLimit,
69 _ => ErrorCode::Unknown
70 })
71 );
72 let param = obj.find("param").and_then(|p| Some(p.to_string()));
73 let message = obj.find("message").and_then(|m| Some(m.to_string()));
74 Error { kind: kind, code: code, param: param, message: message }
75 }
76}
77
78impl StdError for Error {
79 fn description(&self) -> &str {
80 self.message.as_ref().map_or("Stripe error", |m| &m)
81 }
82}
83
84impl fmt::Debug for Error {
85 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
86 self.description().fmt(f)
87 }
88}
89
90impl fmt::Display for Error {
91 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
92 fmt::Debug::fmt(&self, f)
93 }
94}
95
96impl From<curl::ErrCode> for Error {
97 #[allow(unused_variables)]
98 fn from(err: curl::ErrCode) -> Self {
99 Error::new(ErrorKind::ConnectionError, "Network communication failed")
100 }
101}
102
103impl From<Utf8Error> for Error {
104 #[allow(unused_variables)]
105 fn from(err: Utf8Error) -> Self {
106 Error::new(ErrorKind::APIError, "Response is not valid UTF-8")
107 }
108}
109
110impl From<ParserError> for Error {
111 #[allow(unused_variables)]
112 fn from(err: ParserError) -> Self {
113 Error::new(ErrorKind::APIError, "Response is not valid JSON")
114 }
115}