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