1use thiserror::Error;
6
7#[derive(Error, Debug)]
9#[non_exhaustive]
10pub enum O2Error {
11 #[error("Internal server error (1000): {0}")]
13 InternalError(String),
14
15 #[error("Invalid request (1001): {0}")]
16 InvalidRequest(String),
17
18 #[error("Parse error (1002): {0}")]
19 ParseError(String),
20
21 #[error("Rate limit exceeded (1003): {0}")]
22 RateLimitExceeded(String),
23
24 #[error("Geo restricted (1004): {0}")]
25 GeoRestricted(String),
26
27 #[error("Market not found (2000): {0}")]
29 MarketNotFound(String),
30
31 #[error("Market paused (2001): {0}")]
32 MarketPaused(String),
33
34 #[error("Market already exists (2002): {0}")]
35 MarketAlreadyExists(String),
36
37 #[error("Order not found (3000): {0}")]
39 OrderNotFound(String),
40
41 #[error("Order not active (3001): {0}")]
42 OrderNotActive(String),
43
44 #[error("Invalid order params (3002): {0}")]
45 InvalidOrderParams(String),
46
47 #[error("Invalid signature (4000): {0}")]
49 InvalidSignature(String),
50
51 #[error("Invalid session (4001): {0}")]
52 InvalidSession(String),
53
54 #[error("Account not found (4002): {0}")]
55 AccountNotFound(String),
56
57 #[error("Whitelist not configured (4003): {0}")]
58 WhitelistNotConfigured(String),
59
60 #[error("Trade not found (5000): {0}")]
62 TradeNotFound(String),
63
64 #[error("Invalid trade count (5001): {0}")]
65 InvalidTradeCount(String),
66
67 #[error("Already subscribed (6000): {0}")]
69 AlreadySubscribed(String),
70
71 #[error("Too many subscriptions (6001): {0}")]
72 TooManySubscriptions(String),
73
74 #[error("Subscription error (6002): {0}")]
75 SubscriptionError(String),
76
77 #[error("Invalid amount (7000): {0}")]
79 InvalidAmount(String),
80
81 #[error("Invalid time range (7001): {0}")]
82 InvalidTimeRange(String),
83
84 #[error("Invalid pagination (7002): {0}")]
85 InvalidPagination(String),
86
87 #[error("No actions provided (7003): {0}")]
88 NoActionsProvided(String),
89
90 #[error("Too many actions (7004): {0}")]
91 TooManyActions(String),
92
93 #[error("Block not found (8000): {0}")]
95 BlockNotFound(String),
96
97 #[error("Events not found (8001): {0}")]
98 EventsNotFound(String),
99
100 #[error("On-chain revert: {message}, reason: {reason}")]
102 OnChainRevert {
103 message: String,
104 reason: String,
105 receipts: Option<serde_json::Value>,
106 },
107
108 #[error("Session expired: {0}")]
110 SessionExpired(String),
111
112 #[error("HTTP error: {0}")]
114 HttpError(String),
115
116 #[error("WebSocket error: {0}")]
117 WebSocketError(String),
118
119 #[error("WebSocket reconnected")]
120 WebSocketReconnected,
121
122 #[error("WebSocket disconnected: {0}")]
123 WebSocketDisconnected(String),
124
125 #[error("JSON error: {0}")]
126 JsonError(String),
127
128 #[error("Crypto error: {0}")]
130 CryptoError(String),
131
132 #[error("{0}")]
134 Other(String),
135}
136
137impl O2Error {
138 pub fn from_code(code: u32, message: String) -> Self {
140 match code {
141 1000 => O2Error::InternalError(message),
142 1001 => O2Error::InvalidRequest(message),
143 1002 => O2Error::ParseError(message),
144 1003 => O2Error::RateLimitExceeded(message),
145 1004 => O2Error::GeoRestricted(message),
146 2000 => O2Error::MarketNotFound(message),
147 2001 => O2Error::MarketPaused(message),
148 2002 => O2Error::MarketAlreadyExists(message),
149 3000 => O2Error::OrderNotFound(message),
150 3001 => O2Error::OrderNotActive(message),
151 3002 => O2Error::InvalidOrderParams(message),
152 4000 => O2Error::InvalidSignature(message),
153 4001 => O2Error::InvalidSession(message),
154 4002 => O2Error::AccountNotFound(message),
155 4003 => O2Error::WhitelistNotConfigured(message),
156 5000 => O2Error::TradeNotFound(message),
157 5001 => O2Error::InvalidTradeCount(message),
158 6000 => O2Error::AlreadySubscribed(message),
159 6001 => O2Error::TooManySubscriptions(message),
160 6002 => O2Error::SubscriptionError(message),
161 7000 => O2Error::InvalidAmount(message),
162 7001 => O2Error::InvalidTimeRange(message),
163 7002 => O2Error::InvalidPagination(message),
164 7003 => O2Error::NoActionsProvided(message),
165 7004 => O2Error::TooManyActions(message),
166 8000 => O2Error::BlockNotFound(message),
167 8001 => O2Error::EventsNotFound(message),
168 _ => O2Error::Other(format!("Unknown error code {code}: {message}")),
169 }
170 }
171
172 pub fn error_code(&self) -> Option<u32> {
174 match self {
175 O2Error::InternalError(_) => Some(1000),
176 O2Error::InvalidRequest(_) => Some(1001),
177 O2Error::ParseError(_) => Some(1002),
178 O2Error::RateLimitExceeded(_) => Some(1003),
179 O2Error::GeoRestricted(_) => Some(1004),
180 O2Error::MarketNotFound(_) => Some(2000),
181 O2Error::MarketPaused(_) => Some(2001),
182 O2Error::MarketAlreadyExists(_) => Some(2002),
183 O2Error::OrderNotFound(_) => Some(3000),
184 O2Error::OrderNotActive(_) => Some(3001),
185 O2Error::InvalidOrderParams(_) => Some(3002),
186 O2Error::InvalidSignature(_) => Some(4000),
187 O2Error::InvalidSession(_) => Some(4001),
188 O2Error::AccountNotFound(_) => Some(4002),
189 O2Error::WhitelistNotConfigured(_) => Some(4003),
190 O2Error::TradeNotFound(_) => Some(5000),
191 O2Error::InvalidTradeCount(_) => Some(5001),
192 O2Error::AlreadySubscribed(_) => Some(6000),
193 O2Error::TooManySubscriptions(_) => Some(6001),
194 O2Error::SubscriptionError(_) => Some(6002),
195 O2Error::InvalidAmount(_) => Some(7000),
196 O2Error::InvalidTimeRange(_) => Some(7001),
197 O2Error::InvalidPagination(_) => Some(7002),
198 O2Error::NoActionsProvided(_) => Some(7003),
199 O2Error::TooManyActions(_) => Some(7004),
200 O2Error::BlockNotFound(_) => Some(8000),
201 O2Error::EventsNotFound(_) => Some(8001),
202 _ => None,
203 }
204 }
205
206 pub fn is_retryable(&self) -> bool {
208 matches!(
209 self,
210 O2Error::InternalError(_) | O2Error::RateLimitExceeded(_)
211 )
212 }
213}
214
215impl From<reqwest::Error> for O2Error {
216 fn from(err: reqwest::Error) -> Self {
217 O2Error::HttpError(err.to_string())
218 }
219}
220
221impl From<serde_json::Error> for O2Error {
222 fn from(err: serde_json::Error) -> Self {
223 O2Error::JsonError(err.to_string())
224 }
225}
226
227impl From<url::ParseError> for O2Error {
228 fn from(err: url::ParseError) -> Self {
229 O2Error::Other(format!("URL parse error: {err}"))
230 }
231}
232
233impl From<tokio_tungstenite::tungstenite::Error> for O2Error {
234 fn from(err: tokio_tungstenite::tungstenite::Error) -> Self {
235 O2Error::WebSocketError(err.to_string())
236 }
237}
238
239impl From<std::convert::Infallible> for O2Error {
240 fn from(_: std::convert::Infallible) -> Self {
241 unreachable!()
242 }
243}