kiteconnect_async_wasm/models/common/
errors.rs1use thiserror::Error;
8
9#[derive(Debug, Error)]
11pub enum KiteError {
12 #[error("HTTP request failed: {0}")]
14 Http(#[from] reqwest::Error),
15
16 #[error("JSON parsing failed: {0}")]
18 Json(#[from] serde_json::Error),
19
20 #[error("Token exception: {0}")]
25 TokenException(String),
26
27 #[error("User exception: {0}")]
29 UserException(String),
30
31 #[error("Order exception: {0}")]
33 OrderException(String),
34
35 #[error("Input exception: {0}")]
37 InputException(String),
38
39 #[error("Margin exception: {0}")]
41 MarginException(String),
42
43 #[error("Holding exception: {0}")]
45 HoldingException(String),
46
47 #[error("Network exception: {0}")]
49 NetworkException(String),
50
51 #[error("Data exception: {0}")]
53 DataException(String),
54
55 #[error("General exception: {0}")]
57 GeneralException(String),
58
59 #[error("API error: {status} - {message}")]
63 Api {
64 status: String,
65 message: String,
66 error_type: Option<String>,
67 },
68
69 #[error("Authentication failed: {0}")]
71 Authentication(String),
72
73 #[error("Invalid parameter: {0}")]
75 InvalidParameter(String),
76
77 #[cfg(feature = "native")]
79 #[error("CSV parsing failed: {0}")]
80 CsvParsing(#[from] csv::Error),
81
82 #[error("Date/time parsing failed: {0}")]
84 DateTimeParsing(#[from] chrono::ParseError),
85
86 #[error("URL parsing failed: {0}")]
88 UrlParsing(#[from] url::ParseError),
89
90 #[error("KiteConnect error: {0}")]
92 General(String),
93
94 #[error("Legacy error: {0}")]
96 Legacy(#[from] anyhow::Error),
97}
98
99pub type KiteResult<T> = Result<T, KiteError>;
101
102impl KiteError {
103 pub fn from_api_response(
106 status_code: u16,
107 status: impl Into<String>,
108 message: impl Into<String>,
109 error_type: Option<String>,
110 ) -> Self {
111 let message = message.into();
112
113 if let Some(error_type) = error_type.as_ref() {
115 return match error_type.as_str() {
116 "TokenException" => Self::TokenException(message),
117 "UserException" => Self::UserException(message),
118 "OrderException" => Self::OrderException(message),
119 "InputException" => Self::InputException(message),
120 "MarginException" => Self::MarginException(message),
121 "HoldingException" => Self::HoldingException(message),
122 "NetworkException" => Self::NetworkException(message),
123 "DataException" => Self::DataException(message),
124 "GeneralException" => Self::GeneralException(message),
125 _ => Self::Api {
126 status: status.into(),
127 message,
128 error_type: Some(error_type.clone()),
129 }
130 };
131 }
132
133 match status_code {
135 400 => Self::InputException(message), 403 => Self::TokenException(message), 404 => Self::Api {
138 status: status.into(),
139 message,
140 error_type: Some("ResourceNotFound".to_string()), },
142 405 => Self::Api {
143 status: status.into(),
144 message,
145 error_type: Some("MethodNotAllowed".to_string()), },
147 410 => Self::Api {
148 status: status.into(),
149 message,
150 error_type: Some("ResourceGone".to_string()), },
152 429 => Self::Api {
153 status: status.into(),
154 message,
155 error_type: Some("RateLimited".to_string()), },
157 500 => Self::GeneralException(message), 502 => Self::NetworkException(message), 503 => Self::NetworkException(message), 504 => Self::NetworkException(message), _ => Self::Api {
162 status: status.into(),
163 message,
164 error_type,
165 }
166 }
167 }
168
169 pub fn api_error(status: impl Into<String>, message: impl Into<String>) -> Self {
171 Self::Api {
172 status: status.into(),
173 message: message.into(),
174 error_type: None,
175 }
176 }
177
178 pub fn api_error_with_type(
180 status: impl Into<String>,
181 message: impl Into<String>,
182 error_type: impl Into<String>,
183 ) -> Self {
184 Self::Api {
185 status: status.into(),
186 message: message.into(),
187 error_type: Some(error_type.into()),
188 }
189 }
190
191 pub fn auth_error(message: impl Into<String>) -> Self {
193 Self::Authentication(message.into())
194 }
195
196 pub fn invalid_param(message: impl Into<String>) -> Self {
198 Self::InvalidParameter(message.into())
199 }
200
201 pub fn general(message: impl Into<String>) -> Self {
203 Self::General(message.into())
204 }
205
206 pub fn token_exception(message: impl Into<String>) -> Self {
210 Self::TokenException(message.into())
211 }
212
213 pub fn user_exception(message: impl Into<String>) -> Self {
215 Self::UserException(message.into())
216 }
217
218 pub fn order_exception(message: impl Into<String>) -> Self {
220 Self::OrderException(message.into())
221 }
222
223 pub fn input_exception(message: impl Into<String>) -> Self {
225 Self::InputException(message.into())
226 }
227
228 pub fn margin_exception(message: impl Into<String>) -> Self {
230 Self::MarginException(message.into())
231 }
232
233 pub fn holding_exception(message: impl Into<String>) -> Self {
235 Self::HoldingException(message.into())
236 }
237
238 pub fn network_exception(message: impl Into<String>) -> Self {
240 Self::NetworkException(message.into())
241 }
242
243 pub fn data_exception(message: impl Into<String>) -> Self {
245 Self::DataException(message.into())
246 }
247
248 pub fn general_exception(message: impl Into<String>) -> Self {
250 Self::GeneralException(message.into())
251 }
252
253 pub fn requires_reauth(&self) -> bool {
255 matches!(self, Self::TokenException(_) | Self::Authentication(_))
256 }
257
258 pub fn is_client_error(&self) -> bool {
260 match self {
261 Self::TokenException(_) | Self::InputException(_) | Self::InvalidParameter(_) => true,
262 Self::Api { status, .. } => status.starts_with('4'),
263 _ => false,
264 }
265 }
266
267 pub fn is_server_error(&self) -> bool {
269 match self {
270 Self::NetworkException(_) | Self::DataException(_) | Self::GeneralException(_) => true,
271 Self::Api { status, .. } => status.starts_with('5'),
272 _ => false,
273 }
274 }
275
276 pub fn is_retryable(&self) -> bool {
278 match self {
279 Self::NetworkException(_) | Self::Http(_) => true, Self::Api { status, .. } => matches!(status.as_str(), "429"), _ => false,
282 }
283 }
284}