1#![allow(unused)]
2use serde::{Deserialize, Serialize};
3use std::error::Error as StdError;
4use std::fmt;
5use std::num::ParseIntError;
6use std::str::ParseBoolError;
7use thiserror::Error;
8use mocra_proxy::ProxyError;
11pub type BoxError = Box<dyn StdError + Send + Sync + 'static>;
13
14pub type Result<T> = std::result::Result<T, Error>;
15
16#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
17pub enum ErrorKind {
18 Request,
19 Response,
20 Command,
21 Service,
22 Proxy,
23 Download,
24 Queue,
25 Orm,
26 Task,
27 Module,
28 RateLimit,
29 ProcessorChain,
30 Parser,
31 DataMiddleware,
32 DataStore,
33 DynamicLibrary,
34 CacheService,
35}
36
37impl fmt::Display for ErrorKind {
38 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
39 match self {
40 ErrorKind::Request => write!(f, "request"),
41 ErrorKind::Response => write!(f, "response"),
42 ErrorKind::Command => write!(f, "command"),
43 ErrorKind::Service => write!(f, "service"),
44 ErrorKind::Proxy => write!(f, "proxy"),
45 ErrorKind::Download => write!(f, "download"),
46 ErrorKind::Queue => write!(f, "queue"),
47 ErrorKind::Orm => write!(f, "orm"),
48 ErrorKind::Module => write!(f, "task"),
49 ErrorKind::RateLimit => write!(f, "rate limit"),
50 ErrorKind::ProcessorChain => write!(f, "processor chain"),
51 ErrorKind::Parser => write!(f, "parser"),
52 ErrorKind::DataMiddleware => write!(f, "data middleware"),
53 ErrorKind::DataStore => write!(f, "data store"),
54 ErrorKind::Task => write!(f, "task"),
55 ErrorKind::DynamicLibrary => write!(f, "dynamic library"),
56 ErrorKind::CacheService => write!(f, "cache service"),
57 }
58 }
59}
60
61pub struct ErrorInner {
62 pub kind: ErrorKind,
63 pub source: Option<BoxError>,
64 pub message: Option<String>,
65}
66
67pub struct Error {
68 pub inner: Box<ErrorInner>,
69}
70
71impl Error {
72 pub fn new<E>(kind: ErrorKind, source: Option<E>) -> Error
73 where
74 E: Into<BoxError>,
75 {
76 Error {
77 inner: Box::new(ErrorInner {
78 kind,
79 source: source.map(Into::into),
80 message: None,
81 }),
82 }
83 }
84
85 pub(crate) fn with_message<E>(kind: ErrorKind, message: String, source: Option<E>) -> Error
86 where
87 E: Into<BoxError>,
88 {
89 Error {
90 inner: Box::new(ErrorInner {
91 kind,
92 source: source.map(Into::into),
93 message: Some(message),
94 }),
95 }
96 }
97
98 pub fn kind(&self) -> &ErrorKind {
99 &self.inner.kind
100 }
101
102 pub fn is_request(&self) -> bool {
103 matches!(self.inner.kind, ErrorKind::Request)
104 }
105
106 pub fn is_response(&self) -> bool {
107 matches!(self.inner.kind, ErrorKind::Response)
108 }
109
110 pub fn is_command(&self) -> bool {
111 matches!(self.inner.kind, ErrorKind::Command)
112 }
113
114 pub fn is_service(&self) -> bool {
115 matches!(self.inner.kind, ErrorKind::Service)
116 }
117
118 pub fn is_proxy(&self) -> bool {
119 matches!(self.inner.kind, ErrorKind::Proxy)
120 }
121
122 pub fn is_download(&self) -> bool {
123 matches!(self.inner.kind, ErrorKind::Download)
124 }
125 pub fn is_queue(&self) -> bool {
126 matches!(self.inner.kind, ErrorKind::Queue)
127 }
128 pub fn is_timeout(&self) -> bool {
129 if let Some(source) = &self.inner.source {
130 source.to_string().to_lowercase().contains("timeout")
132 } else {
133 false
134 }
135 }
136
137 pub fn is_connect(&self) -> bool {
138 if let Some(source) = &self.inner.source {
139 let msg = source.to_string().to_lowercase();
140 msg.contains("connect") || msg.contains("connection")
141 } else {
142 false
143 }
144 }
145}
146
147impl fmt::Debug for Error {
148 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
149 let mut f = f.debug_struct("mocra::Error");
150 f.field("kind", &self.inner.kind);
151 if let Some(ref message) = self.inner.message {
152 f.field("message", message);
153 }
154 if let Some(ref source) = self.inner.source {
155 f.field("source", source);
156 }
157 f.finish()
158 }
159}
160
161impl fmt::Display for Error {
162 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
163 if let Some(ref message) = self.inner.message {
164 write!(f, "{} error: {}", self.inner.kind, message)?;
165 } else {
166 write!(f, "{} error", self.inner.kind)?;
167 }
168
169 if let Some(ref source) = self.inner.source {
170 write!(f, ": {source}")?;
171 }
172
173 Ok(())
174 }
175}
176
177impl StdError for Error {
178 fn source(&self) -> Option<&(dyn StdError + 'static)> {
179 self.inner
180 .source
181 .as_ref()
182 .map(|e| &**e as &(dyn StdError + 'static))
183 }
184}
185
186macro_rules! error {
188 ($kind:ident) => {
189 Error::new(ErrorKind::$kind, None::<BoxError>)
190 };
191 ($kind:ident, $src:expr) => {
192 Error::new(ErrorKind::$kind, Some($src))
193 };
194 ($kind:ident, $msg:expr, $src:expr) => {
195 Error::with_message(ErrorKind::$kind, $msg.to_string(), Some($src))
196 };
197}
198
199pub(crate) use error;
200
201impl From<RequestError> for Error {
203 fn from(err: RequestError) -> Self {
204 Error::new(ErrorKind::Request, Some(err))
205 }
206}
207
208impl From<ResponseError> for Error {
209 fn from(err: ResponseError) -> Self {
210 Error::new(ErrorKind::Response, Some(err))
211 }
212}
213
214impl From<CommandError> for Error {
215 fn from(err: CommandError) -> Self {
216 Error::new(ErrorKind::Command, Some(err))
217 }
218}
219
220impl From<ServiceError> for Error {
221 fn from(err: ServiceError) -> Self {
222 Error::new(ErrorKind::Service, Some(err))
223 }
224}
225
226impl From<ProxyError> for Error {
227 fn from(err: ProxyError) -> Self {
228 Error::new(ErrorKind::Proxy, Some(err))
229 }
230}
231
232impl From<CookieError> for Error {
233 fn from(err: CookieError) -> Self {
234 Error::new(ErrorKind::Request, Some(err))
235 }
236}
237
238impl From<DownloadError> for Error {
239 fn from(err: DownloadError) -> Self {
240 Error::new(ErrorKind::Download, Some(err))
241 }
242}
243impl From<QueueError> for Error {
244 fn from(err: QueueError) -> Self {
245 Error::new(ErrorKind::Queue, Some(err))
246 }
247}
248impl From<OrmError> for Error {
249 fn from(err: OrmError) -> Self {
250 Error::new(ErrorKind::Orm, Some(err))
251 }
252}
253
254impl From<ModuleError> for Error {
255 fn from(err: ModuleError) -> Self {
256 Error::new(ErrorKind::Module, Some(err))
257 }
258}
259
260impl From<HeaderError> for Error {
261 fn from(err: HeaderError) -> Self {
262 Error::new(ErrorKind::Request, Some(err))
263 }
264}
265impl From<RateLimitError> for Error {
266 fn from(err: RateLimitError) -> Self {
267 Error::new(ErrorKind::RateLimit, Some(err))
268 }
269}
270impl From<SyncError> for Error {
271 fn from(err: SyncError) -> Self {
272 Error::new(ErrorKind::CacheService, Some(err))
273 }
274}
275impl From<ProcessorChainError> for Error {
276 fn from(err: ProcessorChainError) -> Self {
277 Error::new(ErrorKind::ProcessorChain, Some(err))
278 }
279}
280impl From<ParserError> for Error {
281 fn from(value: ParserError) -> Self {
282 Error::new(ErrorKind::Parser, Some(value))
283 }
284}
285impl From<DataMiddlewareError> for Error {
286 fn from(value: DataMiddlewareError) -> Self {
287 Error::new(ErrorKind::DataMiddleware, Some(value))
288 }
289}
290
291impl From<DataStoreError> for Error {
292 fn from(value: DataStoreError) -> Self {
293 Error::new(ErrorKind::DataStore, Some(value))
294 }
295}
296impl From<TaskError> for Error {
297 fn from(value: TaskError) -> Self {
298 Error::new(ErrorKind::Task, Some(value))
299 }
300}
301
302impl From<DynLibError> for Error {
303 fn from(value: DynLibError) -> Self {
304 Error::new(ErrorKind::DynamicLibrary, Some(value))
305 }
306}
307
308#[derive(Debug, Error)]
310pub enum RequestError {
311 #[error("invalid method")]
312 InvalidMethod(#[source] BoxError),
313 #[error("build failed")]
314 BuildFailed(#[source] BoxError),
315 #[error("bad request")]
316 BadRequest,
317 #[error("unauthorized")]
318 Unauthorized,
319 #[error("forbidden")]
320 Forbidden,
321 #[error("not found")]
322 NotFound,
323 #[error("timeout")]
324 Timeout,
325 #[error("invalid url: {0}")]
326 InvalidUrl(String),
327 #[error("invalid header: {0}")]
328 InvalidHeader(String),
329 #[error("invalid body: {0}")]
330 InvalidBody(String),
331 #[error("{0}")]
332 InvalidParams(#[source] BoxError),
333 #[error("{0}")]
334 NotLogin(#[source] BoxError),
335 #[error("{0}")]
336 NotImplemented(#[source] BoxError),
337 #[error("{0}")]
338 InvalidMetaForRemote(#[source] BoxError),
339}
340
341#[derive(Debug, Error)]
342pub enum ResponseError {
343 #[error("invalid format")]
344 InvalidFormat,
345 #[error("{0}")]
346 ParseError(BoxError),
347 #[error("empty response")]
348 EmptyResponse,
349 #[error("invalid status: {0}")]
350 InvalidStatus(u16),
351 #[error("body too large: {0} bytes")]
352 BodyTooLarge(usize),
353 #[error("decode error: {0}")]
354 DecodeError(String),
355}
356
357#[derive(Debug, Error)]
358pub enum CommandError {
359 #[error("invalid command")]
360 InvalidCommand,
361 #[error("execution failed")]
362 ExecutionFailed,
363 #[error("permission denied")]
364 PermissionDenied,
365 #[error("command not found: {0}")]
366 CommandNotFound(String),
367 #[error("invalid argument: {0}")]
368 InvalidArgument(String),
369}
370
371#[derive(Debug, Error)]
372pub enum ServiceError {
373 #[error("service unavailable")]
374 ServiceUnavailable,
375 #[error("connection failed")]
376 ConnectionFailed,
377 #[error("internal error")]
378 InternalError,
379 #[error("service timeout")]
380 ServiceTimeout,
381 #[error("rate limit exceeded")]
382 RateLimitExceeded,
383 #[error("authentication failed")]
384 AuthenticationFailed,
385}
386
387#[derive(Debug, Error)]
388pub enum CookieError {
389 #[error("{0}")]
390 ParseError(#[source] BoxError),
391 #[error("cookie not found: {0}")]
392 NotFound(#[source] BoxError),
393 #[error("cookie already exists: {0}")]
394 AlreadyExists(#[source] BoxError),
395 #[error("cookie load failed: {0}")]
396 LoadFailed(#[source] BoxError),
397 #[error("cookie save failed: {0}")]
398 SaveFailed(#[source] BoxError),
399 #[error("cookie domain mismatch: {0}")]
400 DomainMismatch(String),
401 #[error("cookie expired")]
402 Expired,
403 #[error("{0}")]
404 LoadError(#[source] BoxError),
405}
406#[derive(Debug, Error)]
407pub enum HeaderError {
408 #[error("header parse error: {0}")]
409 ParseError(#[source] BoxError),
410 #[error("header not found: {0}")]
411 NotFound(#[source] BoxError),
412 #[error("header already exists: {0}")]
413 AlreadyExists(#[source] BoxError),
414 #[error("header load failed: {0}")]
415 LoadFailed(#[source] BoxError),
416 #[error("header save failed: {0}")]
417 SaveFailed(#[source] BoxError),
418 #[error("{0}")]
419 LoadError(#[source] BoxError),
420}
421#[derive(Debug, Error)]
422pub enum DownloadError {
423 #[error("download failed: {0}")]
424 DownloadFailed(#[source] BoxError),
425 #[error("params error: {0}")]
426 InvalidParams(#[source] BoxError),
427 #[error("invalid url: {0}")]
428 InvalidUrl(#[source] BoxError),
429 #[error("invalid proxy: {0}")]
430 InvalidProxy(#[source] BoxError),
431 #[error("network error: {0}")]
432 NetworkError(#[source] BoxError),
433 #[error("timeout error: {0}")]
434 TimeoutError(#[source] BoxError),
435 #[error("client error: {0}")]
436 ClientError(#[source] BoxError),
437 #[error("invalid response with error: {0}")]
438 InvalidResponse(#[source] BoxError),
439 #[error("invalid method: {0}")]
440 InvalidMethod(#[source] BoxError),
441 #[error("file write error: {0}")]
442 FileWriteError(#[source] BoxError),
443 #[error("insufficient storage space")]
444 InsufficientSpace,
445 #[error("download interrupted")]
446 Interrupted,
447 #[error("max retry exceeded")]
448 MaxRetryExceeded,
449}
450
451#[derive(Debug, Error)]
452pub enum RateLimitError {
453 #[error("{0}")]
454 Backend(#[source] BoxError),
455 #[error("wait time: {0} seconds")]
456 WaitTime(u64),
457 #[error("wait time too long: {0} ms")]
458 WaitTimeTooLong(u64),
459}
460#[derive(Debug, Error)]
461pub enum SyncError {
462 #[error("{0}")]
463 ConnectFailed(#[source] BoxError),
464 #[error("{0}")]
465 SyncLoadFailed(#[source] BoxError),
466 #[error("{0}")]
467 SyncSaveFailed(#[source] BoxError),
468 #[error("{0}")]
469 SerdeFailed(#[source] BoxError),
470 #[error("{0}")]
471 DeserializeFailed(#[source] BoxError),
472 #[error("{0}")]
473 Timeout(#[source] BoxError),
474 #[error("{0}")]
475 ExecuteFailed(#[source] BoxError),
476}
477
478#[derive(Debug, Error)]
479pub enum QueueError {
480 #[error("data not serialization")]
481 SerializationFailed(BoxError),
482 #[error("data not deserialization")]
483 DeserializationFailed(BoxError),
484 #[error("connection failed")]
485 ConnectionFailed,
486 #[error("channel create failed: {0}")]
487 ChannelCreateFailed(BoxError),
488 #[error("channel not found: {0}")]
489 ChannelNotFound(BoxError),
490 #[error("push data to queue failed")]
491 PushFailed(BoxError),
492 #[error("receive from queue failed")]
493 PopFailed(BoxError),
494 #[error("queue operation failed: {0}")]
495 OperationFailed(#[source] BoxError),
496}
497
498#[derive(Debug, Error)]
499pub enum OrmError {
500 #[error("database connection error: {0}")]
501 ConnectionError(#[source] BoxError),
502 #[error("query execution error: {0}")]
503 QueryExecutionError(#[source] BoxError),
504 #[error("transaction error: {0}")]
505 TransactionError(#[source] BoxError),
506 #[error("data not found")]
507 NotFound,
508 #[error("data already exists")]
509 AlreadyExists,
510 #[error("invalid data: {0}")]
511 InvalidData(String),
512}
513#[derive(Debug, Error)]
514pub enum ModuleError {
515 #[error("json type cannot use error: {0}")]
516 Json(#[source] BoxError),
517 #[error("form type cannot use error: {0}")]
518 Form(#[source] BoxError),
519 #[error("params type cannot use error: {0}")]
520 Params(#[source] BoxError),
521 #[error("body must type of String: {0}")]
522 Body(#[source] BoxError),
523 #[error("{0}")]
524 Model(#[source] BoxError),
525 #[error("{0}")]
526 ConfigSync(#[source] BoxError),
527 #[error("{0}")]
528 ModuleNotFound(#[source] BoxError),
529 #[error("{0}")]
530 TaskMaxError(#[source] BoxError),
531 #[error("{0}")]
532 ModuleMaxError(#[source] BoxError),
533}
534#[derive(Debug, Error)]
535pub enum ProcessorChainError {
536 #[error("{0}")]
537 FatalFailure(#[source] BoxError),
538 #[error("{0}")]
539 DowncastFailure(#[source] BoxError),
540 #[error("{0}")]
541 MaxRetriesExceeded(#[source] BoxError),
542 #[error("{0}")]
543 EmptyChain(#[source] BoxError),
544 #[error("{0}")]
545 Unexpected(#[source] BoxError),
546 #[error("{0}")]
547 Timeout(#[source] BoxError),
548 #[error("{0}")]
549 Cancelled(#[source] BoxError),
550}
551
552#[derive(Debug, Error)]
553pub enum ParserError {
554 #[error("{0}")]
555 InvalidFormat(#[source] BoxError),
556 #[error("{0}")]
557 ParseError(#[source] BoxError),
558 #[error("{0}")]
559 EmptyResponse(#[source] BoxError),
560 #[error("{0}")]
561 InvalidStatus(#[source] BoxError),
562 #[error("{0}")]
563 InvalidMetaData(#[source] BoxError),
564 #[error("{0}")]
565 BodyTooLarge(#[source] BoxError),
566 #[error("{0}")]
567 DecodeError(#[source] BoxError),
568 #[error("{0}")]
569 PolarsError(#[source] BoxError),
570 #[error("{0}")]
571 JsonParseError(#[source] BoxError),
572 #[error("{0}")]
573 DataError(#[source] BoxError),
574}
575#[derive(Debug, Error)]
576pub enum DataMiddlewareError {
577 #[error("{0}")]
578 HandleDataError(#[source] BoxError),
579 #[error("{0}")]
580 InvalidData(#[source] BoxError),
581 #[error("{0}")]
582 EmptyData(#[source] BoxError),
583 #[error("{0}")]
584 MiddlewareNotFound(#[source] BoxError),
585}
586#[derive(Debug, Error)]
587pub enum DataStoreError {
588 #[error("{0}")]
589 SaveFailed(#[source] BoxError),
590 #[error("{0}")]
591 InvalidData(#[source] BoxError),
592 #[error("{0}")]
593 ConnectionFailed(#[source] BoxError),
594 #[error("{0}")]
595 TransactionFailed(#[source] BoxError),
596}
597
598#[derive(Debug, Error)]
599pub enum TaskError {
600 #[error("{0}")]
601 TaskNotFound(#[source] BoxError),
602 #[error("{0}")]
603 TaskAlreadyExists(#[source] BoxError),
604 #[error("{0}")]
605 InvalidTaskConfig(#[source] BoxError),
606 #[error("{0}")]
607 TaskExecutionFailed(#[source] BoxError),
608 #[error("{0}")]
609 TaskTimeout(#[source] BoxError),
610 #[error("{0}")]
611 TaskMaxError(#[source] BoxError),
612}
613
614#[derive(Debug, Error)]
615pub enum DynLibError {
616 #[error("{0}")]
617 LoadError(#[source] BoxError),
618 #[error("{0}")]
619 SymbolNotFound(#[source] BoxError),
620 #[error("{0}")]
621 InitializationFailed(#[source] BoxError),
622 #[error("{0}")]
623 ExecutionFailed(#[source] BoxError),
624 #[error("{0}")]
625 IncompatibleVersion(#[source] BoxError),
626 #[error("{0}")]
627 InvalidPath(#[source] BoxError),
628 #[error("{0}")]
629 DependencyError(#[source] BoxError),
630 #[error("{0}")]
631 Other(#[source] BoxError),
632}
633
634#[derive(Error, Debug)]
635pub enum CacheError {
636 #[error("Pool error: {0}")]
637 Pool(String),
638 #[error("Serialization error: {0}")]
639 Serde(#[from] serde_json::Error),
640 #[error("Service not initialized")]
641 NotInitialized,
642 #[error("NotFound")]
643 NotFound,
644 #[error("IO error: {0}")]
645 Io(#[from] std::io::Error),
646}
647
648impl Error {
650 pub fn request_timeout() -> Self {
651 Error::from(RequestError::Timeout)
652 }
653
654 pub fn request_not_found() -> Self {
655 Error::from(RequestError::NotFound)
656 }
657
658 pub fn proxy_not_found() -> Self {
659 Error::from(ProxyError::ProxyNotFound)
660 }
661
662 pub fn proxy_expired() -> Self {
663 Error::from(ProxyError::ProxyExpired)
664 }
665
666 pub fn download_failed<E: Into<BoxError>>(source: E) -> Self {
667 Error::from(DownloadError::DownloadFailed(source.into()))
668 }
669
670 pub fn cookie_parse_error<E: Into<BoxError>>(source: E) -> Self {
671 Error::from(CookieError::ParseError(source.into()))
672 }
673
674 pub fn service_unavailable() -> Self {
675 Error::from(ServiceError::ServiceUnavailable)
676 }
677}
678
679impl From<std::io::Error> for Error {
681 fn from(err: std::io::Error) -> Self {
682 match err.kind() {
683 std::io::ErrorKind::TimedOut => Error::request_timeout(),
684 std::io::ErrorKind::ConnectionRefused => Error::from(ServiceError::ConnectionFailed),
685 std::io::ErrorKind::PermissionDenied => Error::from(CommandError::PermissionDenied),
686 std::io::ErrorKind::NotFound => Error::request_not_found(),
687 _ => Error::new(ErrorKind::Service, Some(err)),
688 }
689 }
690}
691impl From<CacheError> for Error {
692 fn from(err: CacheError) -> Self {
693 Error::new(ErrorKind::CacheService, Some(err))
694 }
695}
696impl From<ParseIntError> for Error {
697 fn from(value: ParseIntError) -> Self {
698 Error::new(ErrorKind::Parser, Some(value))
699 }
700}
701impl From<ParseBoolError> for Error {
702 fn from(value: ParseBoolError) -> Self {
703 Error::new(ErrorKind::Parser, Some(value))
704 }
705}
706
707impl From<serde_json::Error> for Error {
708 fn from(err: serde_json::Error) -> Self {
709 Error::from(ResponseError::ParseError(err.to_string().into()))
710 }
711}
712
713#[cfg(feature = "polars")]
714impl From<polars::prelude::PolarsError> for Error {
715 fn from(err: polars::prelude::PolarsError) -> Self {
716 Error::from(ParserError::PolarsError(err.to_string().into()))
717 }
718}
719
720#[cfg(test)]
721mod tests {
722 use super::*;
723
724 #[test]
725 fn test_error_creation() {
726 let err = Error::request_timeout();
727 assert!(err.is_request());
728 assert!(err.is_timeout());
729 }
730
731 #[test]
732 fn test_error_display() {
733 let err = Error::request_not_found();
734 assert_eq!(err.to_string(), "request error: not found");
735 }
736
737 #[test]
738 fn test_error_source() {
739 let io_err = std::io::Error::new(std::io::ErrorKind::TimedOut, "connection timed out");
740 let err = Error::from(io_err);
741 assert!(err.source().is_some());
742 }
743
744 #[test]
745 fn test_error_kinds() {
746 let err = Error::proxy_not_found();
747 assert!(err.is_proxy());
748 assert!(!err.is_request());
749
750 let err = Error::service_unavailable();
751 assert!(err.is_service());
752 assert!(!err.is_proxy());
753 }
754}