1use serde::{Deserialize, Serialize};
2use thiserror::Error;
3use ustr::Ustr;
4
5#[derive(Debug, Clone, Error, Copy, Serialize, Deserialize)]
15pub enum Error {
16 #[error("Generic: {0}")]
17 Internal(Ustr),
18
19 #[error("Request failed: {0}")]
20 Request(Ustr),
21
22 #[error("JSON parsing failed: {0}")]
23 JsonParse(Ustr),
24
25 #[error("Type conversion failed: {0}")]
26 TypeConversion(Ustr),
27
28 #[error("Invalid header value: {0}")]
29 HeaderValue(Ustr),
30
31 #[error("Login failed: {source}")]
32 Login {
33 #[source]
34 source: LoginError,
35 },
36
37 #[error("Regex error: {0}")]
38 Regex(Ustr),
39
40 #[error("WebSocket connection failed: {0}")]
41 WebSocket(Ustr),
42
43 #[error("No chart token found")]
44 NoChartTokenFound,
45
46 #[error("No scan data found")]
47 NoScanDataFound,
48
49 #[error("Symbols are not in the same exchange")]
50 SymbolsNotInSameExchange,
51
52 #[error("Exchange not specified")]
53 ExchangeNotSpecified,
54
55 #[error("Invalid exchange")]
56 InvalidExchange,
57
58 #[error("Symbols not specified")]
59 SymbolsNotSpecified,
60
61 #[error("No search data found")]
62 NoSearchDataFound,
63
64 #[error("Indicator not found or unsupported: {0}")]
65 IndicatorDataNotFound(Ustr),
66
67 #[error("Task join failed: {0}")]
68 TokioJoin(Ustr),
69
70 #[error("URL parsing failed: {0}")]
71 UrlParse(Ustr),
72
73 #[error("Date/time parsing failed: {0}")]
74 ChronoParse(Ustr),
75
76 #[error("Date/time out of range: {0}")]
77 ChronoOutOfRange(Ustr),
78
79 #[error("Timeout: {0}")]
80 Timeout(Ustr),
81
82 #[error("I/O error: {0}")]
83 Io(Ustr),
84
85 #[error("TradingView error: {source}")]
86 TradingView {
87 #[source]
88 source: TradingViewError,
89 },
90}
91
92impl From<reqwest::Error> for Error {
94 fn from(err: reqwest::Error) -> Self {
95 Error::Request(err.to_string().into())
96 }
97}
98
99impl From<serde_json::Error> for Error {
100 fn from(err: serde_json::Error) -> Self {
101 Error::JsonParse(err.to_string().into())
102 }
103}
104
105impl From<std::num::ParseIntError> for Error {
106 fn from(err: std::num::ParseIntError) -> Self {
107 Error::TypeConversion(err.to_string().into())
108 }
109}
110
111impl From<reqwest::header::InvalidHeaderValue> for Error {
112 fn from(err: reqwest::header::InvalidHeaderValue) -> Self {
113 Error::HeaderValue(err.to_string().into())
114 }
115}
116
117impl From<LoginError> for Error {
118 fn from(err: LoginError) -> Self {
119 Error::Login { source: err }
120 }
121}
122
123impl From<regex::Error> for Error {
124 fn from(err: regex::Error) -> Self {
125 Error::Regex(err.to_string().into())
126 }
127}
128
129impl From<tokio_tungstenite::tungstenite::Error> for Error {
130 fn from(err: tokio_tungstenite::tungstenite::Error) -> Self {
131 Error::WebSocket(err.to_string().into())
132 }
133}
134
135impl From<tokio::task::JoinError> for Error {
136 fn from(err: tokio::task::JoinError) -> Self {
137 Error::TokioJoin(err.to_string().into())
138 }
139}
140
141impl From<url::ParseError> for Error {
142 fn from(err: url::ParseError) -> Self {
143 Error::UrlParse(err.to_string().into())
144 }
145}
146
147impl From<chrono::ParseError> for Error {
148 fn from(err: chrono::ParseError) -> Self {
149 Error::ChronoParse(err.to_string().into())
150 }
151}
152
153impl From<chrono::OutOfRangeError> for Error {
154 fn from(err: chrono::OutOfRangeError) -> Self {
155 Error::ChronoOutOfRange(err.to_string().into())
156 }
157}
158
159impl From<std::io::Error> for Error {
160 fn from(err: std::io::Error) -> Self {
161 Error::Io(err.to_string().into())
162 }
163}
164
165impl From<TradingViewError> for Error {
166 fn from(err: TradingViewError) -> Self {
167 Error::TradingView { source: err }
168 }
169}
170
171impl From<String> for Error {
172 fn from(err: String) -> Self {
173 Error::Internal(err.into())
174 }
175}
176
177impl From<&str> for Error {
178 fn from(err: &str) -> Self {
179 Error::Internal(Ustr::from(err))
180 }
181}
182
183impl From<Ustr> for Error {
184 fn from(err: Ustr) -> Self {
185 Error::Internal(err)
186 }
187}
188
189#[derive(Debug, Clone, Error, PartialEq, Eq, Hash, Copy, Serialize, Deserialize)]
194pub enum TradingViewError {
195 #[error("Series error")]
196 SeriesError,
197 #[error("Symbol error")]
198 SymbolError,
199 #[error("Critical error")]
200 CriticalError,
201 #[error("Study error")]
202 StudyError,
203 #[error("Protocol error")]
204 ProtocolError,
205 #[error("Quote data status error: {0}")]
206 QuoteDataStatusError(Ustr),
207 #[error("Replay error")]
208 ReplayError,
209 #[error("Configuration error: missing exchange")]
210 MissingExchange,
211 #[error("Configuration error: missing symbol")]
212 MissingSymbol,
213 #[error("Invalid session ID or signature")]
214 InvalidSessionId,
215}
216
217#[derive(Debug, Clone, Error, PartialEq, Eq, Hash, Copy, Serialize, Deserialize)]
219pub enum LoginError {
220 #[error("Username or password is empty")]
221 EmptyCredentials,
222 #[error("Username or password is invalid")]
223 InvalidCredentials,
224 #[error("OTP secret is empty")]
225 OTPSecretNotFound,
226 #[error("OTP secret is invalid")]
227 InvalidOTPSecret,
228 #[error("Wrong or expired session ID/signature")]
229 InvalidSession,
230 #[error("Session ID/signature is empty")]
231 SessionNotFound,
232 #[error("Cannot parse user ID")]
233 ParseIDError,
234 #[error("Cannot parse username")]
235 ParseUsernameError,
236 #[error("Cannot parse session hash")]
237 ParseSessionHashError,
238 #[error("Cannot parse private channel")]
239 ParsePrivateChannelError,
240 #[error("Cannot parse auth token")]
241 ParseAuthTokenError,
242 #[error("Missing auth token")]
243 MissingAuthToken,
244}