Skip to main content

ibtwsapi/core/
errors.rs

1//! Error types
2use std::num::{ParseFloatError, ParseIntError};
3use std::sync::mpsc::{RecvError, RecvTimeoutError, TryRecvError};
4use std::{error, fmt, io};
5
6const ALREADY_CONNECTED: (i32, &str) = (501, "Already connected.");
7const CONNECT_FAIL: (i32, &str) = (502, "Couldn't connect to TWS. Confirm that \"Enable ActiveX and Socket EClients\"
8                                            is enabled and connection port is the same as \"Socket Port\" on the
9                                            TWS \"Edit->Global Configuration...->API->Settings\" menu. Live Trading ports:
10                                            TWS: 7496; IB Gateway: 4001. Simulated Trading ports for new installations
11                                            of version 954.1 or newer:  TWS: 7497; IB Gateway: 4002");
12const UPDATE_TWS: (i32, &str) = (503, "The TWS is out of date and must be upgraded.");
13const NOT_CONNECTED: (i32, &str) = (504, "Not connected.");
14const UNKNOWN_ID: (i32, &str) = (505, "Fatal TwsError: Unknown message id.");
15const UNSUPPORTED: (i32, &str) = (506, "UNSUPPORTED version");
16const BAD_LENGTH: (i32, &str) = (507, "Bad message length.");
17const BAD_MESSAGE: (i32, &str) = (508, "Bad message.");
18const SOCKET_EXCEPTION: (i32, &str) = (509, "Exception caught while reading socket.");
19const FAIL_CREATE_SOCK: (i32, &str) = (520, "Failed to create socket.");
20const SSL_FAIL: (i32, &str) = (530, "SSL specific TwsError.");
21
22#[derive(Clone, Debug)]
23pub enum TwsError {
24    AlreadyConnected,
25    ConnectFail,
26    UpdateTws,
27    NotConnected,
28    UnknownId,
29    Unsupported,
30    BadLength,
31    BadMessage,
32    SocketException,
33    FailCreateSock,
34    SslFail,
35}
36
37impl TwsError {
38    pub fn code(&self) -> i32 {
39        match *self {
40            TwsError::AlreadyConnected => ALREADY_CONNECTED.0,
41            TwsError::ConnectFail => CONNECT_FAIL.0,
42            TwsError::UpdateTws => UPDATE_TWS.0,
43            TwsError::NotConnected => NOT_CONNECTED.0,
44            TwsError::UnknownId => UNKNOWN_ID.0,
45            TwsError::Unsupported => UNSUPPORTED.0,
46            TwsError::BadLength => BAD_LENGTH.0,
47            TwsError::BadMessage => BAD_MESSAGE.0,
48            TwsError::SocketException => SOCKET_EXCEPTION.0,
49            TwsError::FailCreateSock => FAIL_CREATE_SOCK.0,
50            TwsError::SslFail => SSL_FAIL.0,
51        }
52    }
53    pub fn message(&self) -> &'static str {
54        match *self {
55            TwsError::AlreadyConnected => ALREADY_CONNECTED.1,
56            TwsError::ConnectFail => CONNECT_FAIL.1,
57            TwsError::UpdateTws => UPDATE_TWS.1,
58            TwsError::NotConnected => NOT_CONNECTED.1,
59            TwsError::UnknownId => UNKNOWN_ID.1,
60            TwsError::Unsupported => UNSUPPORTED.1,
61            TwsError::BadLength => BAD_LENGTH.1,
62            TwsError::BadMessage => BAD_MESSAGE.1,
63            TwsError::SocketException => SOCKET_EXCEPTION.1,
64            TwsError::FailCreateSock => FAIL_CREATE_SOCK.1,
65            TwsError::SslFail => SSL_FAIL.1,
66        }
67    }
68}
69
70impl error::Error for TwsError {}
71
72impl fmt::Display for TwsError {
73    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
74        write!(fmt, "Code: {}, Message: {}", self.code(), self.message())
75    }
76}
77
78// #[derive(Debug)]
79pub enum IBKRApiLibError {
80    Io(io::Error),
81    ParseFloat(ParseFloatError),
82    ParseInt(ParseIntError),
83    RecvError(RecvError),
84    TryRecvError(TryRecvError),
85    RecvTimeoutError(RecvTimeoutError),
86    ApiError(TwsApiReportableError),
87}
88
89impl fmt::Display for IBKRApiLibError {
90    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
91        match self {
92            // Both underlying errors already impl `Display`, so we defer to
93            // their implementations.
94            IBKRApiLibError::Io(ref err) => write!(f, "IO error: {}", err),
95            IBKRApiLibError::ParseFloat(ref err) => write!(f, "Parse error: {}", err),
96            IBKRApiLibError::ParseInt(ref err) => write!(f, "Parse error: {}", err),
97            IBKRApiLibError::RecvError(ref err) => write!(f, "Recieve error: {}", err),
98            IBKRApiLibError::TryRecvError(ref err) => write!(f, "TryRecieve error: {}", err),
99            IBKRApiLibError::RecvTimeoutError(ref err) => write!(f, "Reader Send error {}", err),
100            IBKRApiLibError::ApiError(ref err) => write!(f, "TWS Error: {}", err),
101        }
102    }
103}
104
105impl fmt::Debug for IBKRApiLibError {
106    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
107        match self {
108            // Both underlying errors already impl `Display`, so we defer to
109            // their implementations.
110            IBKRApiLibError::Io(ref err) => write!(f, "IO error: {}", err),
111            IBKRApiLibError::ParseFloat(ref err) => write!(f, "Parse error: {}", err),
112            IBKRApiLibError::ParseInt(ref err) => write!(f, "Parse error: {}", err),
113            IBKRApiLibError::RecvError(ref err) => write!(f, "Receive error: {}", err),
114            IBKRApiLibError::TryRecvError(ref err) => write!(f, "TryReceive error {}", err),
115            IBKRApiLibError::RecvTimeoutError(ref err) => write!(f, "Reader Send error {}", err),
116            IBKRApiLibError::ApiError(ref err) => write!(f, "TWS Error: {}", err),
117        }
118    }
119}
120
121impl error::Error for IBKRApiLibError {
122    fn cause(&self) -> Option<&dyn error::Error> {
123        match self {
124            // N.B. Both of these implicitly cast `err` from their concrete
125            // types (either `&io::Error` or `&num::ParseIntError`)
126            // to a trait object `&Error`. This works because both error types
127            // implement `Error`.
128            IBKRApiLibError::Io(ref err) => Some(err),
129            IBKRApiLibError::ParseFloat(ref err) => Some(err),
130            IBKRApiLibError::ParseInt(ref err) => Some(err),
131            IBKRApiLibError::RecvError(ref err) => Some(err),
132            IBKRApiLibError::TryRecvError(ref err) => Some(err),
133            IBKRApiLibError::RecvTimeoutError(ref err) => Some(err),
134            IBKRApiLibError::ApiError(ref err) => Some(err),
135        }
136    }
137}
138
139impl From<io::Error> for IBKRApiLibError {
140    fn from(err: io::Error) -> IBKRApiLibError {
141        IBKRApiLibError::Io(err)
142    }
143}
144
145impl From<ParseIntError> for IBKRApiLibError {
146    fn from(err: ParseIntError) -> IBKRApiLibError {
147        IBKRApiLibError::ParseInt(err)
148    }
149}
150
151impl From<ParseFloatError> for IBKRApiLibError {
152    fn from(err: ParseFloatError) -> IBKRApiLibError {
153        IBKRApiLibError::ParseFloat(err)
154    }
155}
156
157impl From<RecvError> for IBKRApiLibError {
158    fn from(err: RecvError) -> IBKRApiLibError {
159        IBKRApiLibError::RecvError(err)
160    }
161}
162
163impl From<RecvTimeoutError> for IBKRApiLibError {
164    fn from(err: RecvTimeoutError) -> IBKRApiLibError {
165        IBKRApiLibError::RecvTimeoutError(err)
166    }
167}
168
169impl From<TwsApiReportableError> for IBKRApiLibError {
170    fn from(err: TwsApiReportableError) -> IBKRApiLibError {
171        IBKRApiLibError::ApiError(err)
172    }
173}
174
175#[derive(Clone, Debug)]
176pub struct TwsApiReportableError {
177    pub req_id: i32,
178    pub code: String,
179    pub description: String,
180}
181
182impl TwsApiReportableError {
183    pub fn new(req_id: i32, code: String, description: String) -> Self {
184        Self {
185            req_id: req_id,
186            code: code,
187            description: description,
188        }
189    }
190}
191
192impl fmt::Display for TwsApiReportableError {
193    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
194        write!(
195            f,
196            "TWS Error: req_id = {}. code = {}. description = {}",
197            self.req_id, self.code, self.description
198        )
199    }
200}
201
202impl error::Error for TwsApiReportableError {}