carbone_sdk_rust/
carbone.rs1use bytes::Bytes;
2
3use std::path::Path;
4use std::time::Duration;
5
6use reqwest::header;
7use reqwest::header::HeaderValue;
8use reqwest::multipart;
9use reqwest::Client;
10use reqwest::ClientBuilder;
11use reqwest::StatusCode;
12
13
14use crate::carbone_response::APIResponse;
15use crate::config::Config;
16use crate::errors::*;
17use crate::render::*;
18use crate::template::*;
19use crate::types::{ApiJsonToken, JsonData};
20
21use crate::types::Result;
22
23#[derive(Debug, Clone)]
24pub struct Carbone<'a> {
25 config: &'a Config,
26 http_client: Client,
27}
28
29impl<'a> Carbone<'a> {
30 pub fn new(config: &'a Config, api_token: Option<&'a ApiJsonToken>) -> Result<Self> {
31 let mut headers = header::HeaderMap::new();
32 headers.insert(
33 "carbone-version",
34 HeaderValue::from_str(config.api_version.as_str()).unwrap(),
35 );
36 if api_token != None
37 {
38 let bearer = format!("Bearer {}", api_token.expect("REASON").as_str());
39
40 let mut auth_value = header::HeaderValue::from_str(bearer.as_str()).unwrap();
41 auth_value.set_sensitive(true);
42
43 headers.insert(header::AUTHORIZATION, auth_value);
44 }
45
46 let http_client = ClientBuilder::new()
47 .default_headers(headers)
48 .timeout(Duration::from_secs(config.api_timeout))
49 .build()?;
50
51 Ok(Self {
52 config,
53 http_client,
54 })
55 }
56
57 pub async fn delete_template(&self, template_id: TemplateId) -> Result<bool> {
59 let url = format!("{}/template/{}", self.config.api_url, template_id.as_str());
60
61 let response = self.http_client.delete(url).send().await?;
62
63 let json = response.json::<APIResponse>().await?;
64
65 if json.success {
66 Ok(true)
67 } else {
68 Err(CarboneError::Error(json.error.unwrap()))
69 }
70 }
71
72 pub async fn download_template(&self, template_id: &TemplateId) -> Result<Bytes> {
74 let url = format!("{}/template/{}", self.config.api_url, template_id.as_str());
75
76 let response = self.http_client.get(url).send().await?;
77
78 if response.status() == StatusCode::OK {
79 Ok(response.bytes().await?)
80 } else {
81 let json = response.json::<APIResponse>().await?;
82 Err(CarboneError::Error(json.error.unwrap()))
83 }
84 }
85
86 pub async fn generate_report(
88 &self,
89 template_name: String,
90 template_data: Vec<u8>,
91 json_data: JsonData,
92 payload: Option<&str>,
93 salt: Option<&str>
94 ) -> Result<Bytes> {
95
96 let template_id_generated = TemplateId::from_bytes(template_data.to_owned(), payload)?;
97 let mut template_id = template_id_generated;
98 let render_id;
99
100 match self.render_data(template_id, json_data.clone()).await {
101 Ok(id) => {
102 render_id = Some(id);
103 }
104 Err(e) => match e {
105 CarboneError::HttpError { status_code, error_message } => {
106 if status_code == reqwest::StatusCode::NOT_FOUND {
107 template_id = self.upload_template(template_name.as_str(), template_data, salt).await?;
108 render_id = Some(self.render_data(template_id, json_data).await?);
109 } else {
110 return Err(CarboneError::HttpError { status_code, error_message });
111 }
112 },
113 CarboneError::Error(error_message) => {
114 return Err(CarboneError::Error(error_message));
115 },
116 _ => {
117 return Err(e);
118 }
119 }
120 };
121
122 let report_content = self.get_report(&render_id.unwrap()).await?;
123
124 Ok(report_content)
125 }
126
127
128 pub async fn get_report(&self, render_id: &RenderId) -> Result<Bytes> {
130 let url = format!("{}/render/{}", self.config.api_url, render_id.as_str());
131
132 let response = self.http_client.get(url).send().await?;
133
134 if response.status() == StatusCode::OK {
151 Ok(response.bytes().await?)
152 } else {
153 let json = response.json::<APIResponse>().await?;
154 Err(CarboneError::Error(json.error.unwrap()))
155 }
156 }
157
158 pub async fn generate_report_with_template_id(
160 &self,
161 template_id: TemplateId,
162 json_data: JsonData,
163 ) -> Result<Bytes> {
164 let render_id = self.render_data(template_id, json_data).await?;
165 let report_content = self.get_report(&render_id).await?;
166
167 Ok(report_content)
168 }
169
170 pub async fn render_data(
172 &self,
173 template_id: TemplateId,
174 json_data: JsonData,
175 ) -> Result<RenderId> {
176 let url = format!("{}/render/{}", self.config.api_url, template_id.as_str());
177
178 let response = self
179 .http_client
180 .post(url)
181 .header("Content-Type", "application/json")
182 .body(json_data.as_str().to_owned())
183 .send()
184 .await?;
185
186 if !response.status().is_success() {
187 let status_code = response.status();
188 let json = response.json::<APIResponse>().await?;
189 return Err(CarboneError::HttpError {
190 status_code,
191 error_message: json.error.unwrap_or_else(|| "Unknown error".to_string()),
192 });
193 }
194
195 let json = response.json::<APIResponse>().await?;
196
197 if json.success {
198 Ok(json.data.unwrap().render_id.unwrap())
199 } else {
200 Err(CarboneError::Error(json.error.unwrap()))
201 }
202 }
203
204 pub async fn upload_template(
206 &self,
207 file_name: &str,
208 file_content: Vec<u8>,
209 salt: Option<&str>,
210 ) -> Result<TemplateId> {
211 let salt = match salt {
212 Some(s) => s.to_string(),
213 None => "".to_string(),
214 };
215
216 let file_path = Path::new(file_name);
217
218 let file_name = file_path
219 .file_name()
220 .map(|filename| filename.to_string_lossy().into_owned());
221
222 let file_name = match file_name {
223 Some(s) => s,
224 None => return Err(CarboneError::Error("Failed to fetch file name".to_string())),
225 };
226
227
228 let ext = file_path
229 .extension()
230 .and_then(|ext| ext.to_str()) .unwrap_or("");
231 let mime = mime_guess::from_ext(ext).first_or_octet_stream();
232
233 let part = multipart::Part::bytes(file_content)
234 .file_name(file_name)
235 .mime_str(mime.as_ref())?;
236
237 let form: multipart::Form = multipart::Form::new().text("", salt).part("template", part);
238
239 let url = format!("{}/template", self.config.api_url);
240
241
242 let response = self.http_client.post(url).multipart(form).send().await?;
243
244 let json = response.json::<APIResponse>().await?;
245
246 if json.success {
247 Ok(json.data.unwrap().template_id.unwrap())
248 } else {
249 Err(CarboneError::Error(json.error.unwrap()))
250 }
251 }
252
253
254 pub async fn get_status(&self) -> Result<String>
255 {
256 let url = format!("{}/status", self.config.api_url);
257
258 let response = self.http_client.get(url).send().await?;
259
260 if response.status() == StatusCode::OK {
261 let body = response.text().await?;
262 Ok(body)
263 } else {
264 let json = response.json::<APIResponse>().await?;
265 Err(CarboneError::Error(json.error.unwrap()))
266 }
267 }
268}