cloudconvert_sdk/
error.rs1use serde::{Deserialize, Serialize};
2use serde_json::Value;
3
4use crate::jobs::RateLimit;
5
6pub type Result<T, E = Error> = std::result::Result<T, E>;
7
8#[derive(Debug, thiserror::Error)]
9#[non_exhaustive]
10pub enum Error {
11 #[error("CloudConvert API returned HTTP {status}: {message}")]
12 Api {
13 status: u16,
14 message: String,
15 code: Option<String>,
16 errors: Option<Box<Value>>,
17 rate_limit: Option<Box<RateLimit>>,
18 },
19
20 #[error("HTTP request failed: {0}")]
21 Http(#[from] reqwest::Error),
22
23 #[error("local IO failed: {0}")]
24 Io(#[from] std::io::Error),
25
26 #[error("URL parsing failed: {0}")]
27 Url(#[from] url::ParseError),
28
29 #[error("JSON serialization failed: {0}")]
30 Json(#[from] serde_json::Error),
31
32 #[error("missing required environment variable {0}")]
33 MissingEnv(&'static str),
34
35 #[error("task is not an import/upload task that is ready for upload")]
36 UploadTaskNotReady,
37
38 #[error("CloudConvert redirect response did not include a valid Location header")]
39 MissingRedirectLocation,
40
41 #[error("webhook signature is not valid hex")]
42 InvalidSignatureHex,
43
44 #[error("invalid CloudConvert API path")]
45 InvalidApiPath,
46
47 #[error("invalid CloudConvert resource id")]
48 InvalidResourceId,
49
50 #[error("invalid CloudConvert region")]
51 InvalidRegion,
52
53 #[error("{0}")]
54 InvalidBuilderState(#[from] InvalidBuilderState),
55
56 #[cfg(feature = "socket")]
57 #[error("Socket.IO operation failed: {0}")]
58 Socket(String),
59}
60
61impl Error {
62 pub fn api_error(&self) -> Option<ApiError<'_>> {
63 match self {
64 Self::Api {
65 status,
66 message,
67 code,
68 errors,
69 rate_limit,
70 } => Some(ApiError {
71 status: *status,
72 message,
73 code: code.as_deref(),
74 errors: errors.as_deref(),
75 rate_limit: rate_limit.as_deref(),
76 retry_after: rate_limit
77 .as_ref()
78 .and_then(|rate_limit| rate_limit.retry_after),
79 }),
80 _ => None,
81 }
82 }
83}
84
85#[derive(Clone, Copy, Debug)]
86#[non_exhaustive]
87pub struct ApiError<'a> {
88 pub status: u16,
89 pub message: &'a str,
90 pub code: Option<&'a str>,
91 pub errors: Option<&'a Value>,
92 pub rate_limit: Option<&'a RateLimit>,
93 pub retry_after: Option<u64>,
94}
95
96#[derive(Clone, Copy, Debug, Eq, PartialEq)]
97pub struct InvalidBuilderState {
98 pub kind: InvalidBuilderStateKind,
99 pub builder: &'static str,
100 pub method: &'static str,
101}
102
103impl InvalidBuilderState {
104 pub(crate) fn missing_previous_task(method: &'static str) -> Self {
105 Self {
106 kind: InvalidBuilderStateKind::MissingPreviousTask,
107 builder: "JobBuilder",
108 method,
109 }
110 }
111}
112
113impl std::fmt::Display for InvalidBuilderState {
114 fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
115 match self.kind {
116 InvalidBuilderStateKind::MissingPreviousTask => write!(
117 formatter,
118 "invalid {} state in {}: shorthand requires a previous task",
119 self.builder, self.method
120 ),
121 }
122 }
123}
124
125impl std::error::Error for InvalidBuilderState {}
126
127#[derive(Clone, Copy, Debug, Eq, PartialEq)]
128#[non_exhaustive]
129pub enum InvalidBuilderStateKind {
130 MissingPreviousTask,
131}
132
133#[derive(Debug, Deserialize, Serialize)]
134pub(crate) struct ApiErrorBody {
135 pub message: Option<String>,
136 pub code: Option<String>,
137 pub errors: Option<Value>,
138}