vectorizer_sdk/
http_transport.rs1use async_trait::async_trait;
4use reqwest::header::{CONTENT_TYPE, HeaderMap, HeaderValue};
5use reqwest::{Client, ClientBuilder};
6use serde_json::Value;
7
8use crate::error::{Result, VectorizerError};
9use crate::transport::{Protocol, Transport};
10
11pub struct HttpTransport {
13 client: Client,
14 base_url: String,
15}
16
17impl HttpTransport {
18 pub fn new(base_url: &str, api_key: Option<&str>, timeout_secs: u64) -> Result<Self> {
20 let mut headers = HeaderMap::new();
21 headers.insert(CONTENT_TYPE, HeaderValue::from_static("application/json"));
22
23 if let Some(key) = api_key {
24 headers.insert(
25 "Authorization",
26 HeaderValue::from_str(&format!("Bearer {key}"))
27 .map_err(|e| VectorizerError::configuration(format!("Invalid API key: {e}")))?,
28 );
29 }
30
31 let client = ClientBuilder::new()
32 .timeout(std::time::Duration::from_secs(timeout_secs))
33 .default_headers(headers)
34 .build()
35 .map_err(|e| {
36 VectorizerError::configuration(format!("Failed to create HTTP client: {e}"))
37 })?;
38
39 Ok(Self {
40 client,
41 base_url: base_url.to_string(),
42 })
43 }
44
45 async fn request(&self, method: &str, path: &str, body: Option<&Value>) -> Result<String> {
47 let url = format!("{}{}", self.base_url, path);
48
49 let mut request = match method {
50 "GET" => self.client.get(&url),
51 "POST" => self.client.post(&url),
52 "PUT" => self.client.put(&url),
53 "DELETE" => self.client.delete(&url),
54 _ => {
55 return Err(VectorizerError::configuration(format!(
56 "Unsupported HTTP method: {method}"
57 )));
58 }
59 };
60
61 if let Some(data) = body {
62 request = request.json(data);
63 }
64
65 let response = request
66 .send()
67 .await
68 .map_err(|e| VectorizerError::network(format!("HTTP request failed: {e}")))?;
69
70 if !response.status().is_success() {
71 let status = response.status();
72 let error_text = response
73 .text()
74 .await
75 .unwrap_or_else(|_| "Unknown error".to_string());
76 return Err(VectorizerError::server(format!(
77 "HTTP {status}: {error_text}"
78 )));
79 }
80
81 response
82 .text()
83 .await
84 .map_err(|e| VectorizerError::network(format!("Failed to read response: {e}")))
85 }
86}
87
88#[async_trait]
89impl Transport for HttpTransport {
90 async fn get(&self, path: &str) -> Result<String> {
91 self.request("GET", path, None).await
92 }
93
94 async fn post(&self, path: &str, data: Option<&Value>) -> Result<String> {
95 self.request("POST", path, data).await
96 }
97
98 async fn put(&self, path: &str, data: Option<&Value>) -> Result<String> {
99 self.request("PUT", path, data).await
100 }
101
102 async fn delete(&self, path: &str) -> Result<String> {
103 self.request("DELETE", path, None).await
104 }
105
106 fn protocol(&self) -> Protocol {
107 Protocol::Http
108 }
109}
110
111impl HttpTransport {
112 pub async fn post_multipart(
114 &self,
115 path: &str,
116 file_bytes: Vec<u8>,
117 filename: &str,
118 form_fields: std::collections::HashMap<String, String>,
119 ) -> Result<String> {
120 let url = format!("{}{}", self.base_url, path);
121
122 let mut form = reqwest::multipart::Form::new();
124
125 let file_part = reqwest::multipart::Part::bytes(file_bytes).file_name(filename.to_string());
127 form = form.part("file", file_part);
128
129 for (key, value) in form_fields {
131 form = form.text(key, value);
132 }
133
134 let response = self
135 .client
136 .post(&url)
137 .multipart(form)
138 .send()
139 .await
140 .map_err(|e| VectorizerError::network(format!("File upload failed: {e}")))?;
141
142 if !response.status().is_success() {
143 let status = response.status();
144 let error_text = response
145 .text()
146 .await
147 .unwrap_or_else(|_| "Unknown error".to_string());
148 return Err(VectorizerError::server(format!(
149 "HTTP {status}: {error_text}"
150 )));
151 }
152
153 response
154 .text()
155 .await
156 .map_err(|e| VectorizerError::network(format!("Failed to read response: {e}")))
157 }
158}