Skip to main content

hanzo_client/apis/
s3_api.rs

1/*
2 * Hanzo Cloud API
3 *
4 * The Hanzo Cloud API as a customer calls it: every operation under /v1/ except the operator's admin product, relay routes, legacy spellings and capabilities still reached by flag. Tagged by product: the first path segment after /v1/.
5 *
6 * The version of the OpenAPI document: v1
7 * 
8 * Generated by: https://openapi-generator.tech
9 */
10
11
12use reqwest;
13use serde::{Deserialize, Serialize, de::Error as _};
14use crate::{apis::ResponseContent, models};
15use super::{Error, configuration, ContentType};
16
17
18/// struct for typed errors of method [`delete_s3_buckets_by_bucket`]
19#[derive(Debug, Clone, Serialize, Deserialize)]
20#[serde(untagged)]
21pub enum DeleteS3BucketsByBucketError {
22    UnknownValue(serde_json::Value),
23}
24
25/// struct for typed errors of method [`get_s3_buckets`]
26#[derive(Debug, Clone, Serialize, Deserialize)]
27#[serde(untagged)]
28pub enum GetS3BucketsError {
29    UnknownValue(serde_json::Value),
30}
31
32/// struct for typed errors of method [`get_s3_buckets_by_bucket_objects`]
33#[derive(Debug, Clone, Serialize, Deserialize)]
34#[serde(untagged)]
35pub enum GetS3BucketsByBucketObjectsError {
36    UnknownValue(serde_json::Value),
37}
38
39/// struct for typed errors of method [`get_s3_health`]
40#[derive(Debug, Clone, Serialize, Deserialize)]
41#[serde(untagged)]
42pub enum GetS3HealthError {
43    Status503(models::S3Health),
44    UnknownValue(serde_json::Value),
45}
46
47/// struct for typed errors of method [`post_s3_buckets`]
48#[derive(Debug, Clone, Serialize, Deserialize)]
49#[serde(untagged)]
50pub enum PostS3BucketsError {
51    UnknownValue(serde_json::Value),
52}
53
54/// struct for typed errors of method [`post_s3_buckets_by_bucket_objects`]
55#[derive(Debug, Clone, Serialize, Deserialize)]
56#[serde(untagged)]
57pub enum PostS3BucketsByBucketObjectsError {
58    UnknownValue(serde_json::Value),
59}
60
61
62/// Removes an EMPTY bucket and answers 204.  A non-empty bucket is 409 rather than a cascade: deleting a tenant's objects behind a single bucket call is not a thing this surface will do silently. A bucket the caller's org does not own is the same 404 an unknown name gives.  Billed per call: the balance is checked BEFORE anything is touched, so an unfunded org is refused with nothing deleted, and the debit lands only once the bucket is gone.
63pub async fn delete_s3_buckets_by_bucket(configuration: &configuration::Configuration, bucket: &str) -> Result<(), Error<DeleteS3BucketsByBucketError>> {
64    // add a prefix to parameters to efficiently prevent name collisions
65    let p_bucket = bucket;
66
67    let uri_str = format!("{}/v1/s3/buckets/{bucket}", configuration.base_path, bucket=crate::apis::urlencode(p_bucket));
68    let mut req_builder = configuration.client.request(reqwest::Method::DELETE, &uri_str);
69
70    if let Some(ref user_agent) = configuration.user_agent {
71        req_builder = req_builder.header(reqwest::header::USER_AGENT, user_agent.clone());
72    }
73    if let Some(ref token) = configuration.bearer_access_token {
74        req_builder = req_builder.bearer_auth(token.to_owned());
75    };
76
77    let req = req_builder.build()?;
78    let resp = configuration.client.execute(req).await?;
79
80    let status = resp.status();
81
82    if !status.is_client_error() && !status.is_server_error() {
83        Ok(())
84    } else {
85        let content = resp.text().await?;
86        let entity: Option<DeleteS3BucketsByBucketError> = serde_json::from_str(&content).ok();
87        Err(Error::ResponseError(ResponseContent { status, content, entity }))
88    }
89}
90
91/// Lists the caller org's own buckets.  Only the caller's: every bucket is physically named under a per-org prefix and the listing strips that prefix, so a tenant sees friendly names and another tenant's buckets are not in the answer at all. Another org's bucket is not refused but INVISIBLE, so this cannot be used to learn that a name is taken elsewhere.  Billed per call: the balance is checked BEFORE anything is touched, so an unfunded org is refused with nothing done, and the debit lands only once the work has succeeded.
92pub async fn get_s3_buckets(configuration: &configuration::Configuration, ) -> Result<models::BucketList, Error<GetS3BucketsError>> {
93
94    let uri_str = format!("{}/v1/s3/buckets", configuration.base_path);
95    let mut req_builder = configuration.client.request(reqwest::Method::GET, &uri_str);
96
97    if let Some(ref user_agent) = configuration.user_agent {
98        req_builder = req_builder.header(reqwest::header::USER_AGENT, user_agent.clone());
99    }
100    if let Some(ref token) = configuration.bearer_access_token {
101        req_builder = req_builder.bearer_auth(token.to_owned());
102    };
103
104    let req = req_builder.build()?;
105    let resp = configuration.client.execute(req).await?;
106
107    let status = resp.status();
108    let content_type = resp
109        .headers()
110        .get("content-type")
111        .and_then(|v| v.to_str().ok())
112        .unwrap_or("application/octet-stream");
113    let content_type = super::ContentType::from(content_type);
114
115    if !status.is_client_error() && !status.is_server_error() {
116        let content = resp.text().await?;
117        match content_type {
118            ContentType::Json => serde_json::from_str(&content).map_err(Error::from),
119            ContentType::Text => return Err(Error::from(serde_json::Error::custom("Received `text/plain` content type response that cannot be converted to `models::BucketList`"))),
120            ContentType::Unsupported(unknown_type) => return Err(Error::from(serde_json::Error::custom(format!("Received `{unknown_type}` content type response that cannot be converted to `models::BucketList`")))),
121        }
122    } else {
123        let content = resp.text().await?;
124        let entity: Option<GetS3BucketsError> = serde_json::from_str(&content).ok();
125        Err(Error::ResponseError(ResponseContent { status, content, entity }))
126    }
127}
128
129/// Lists one folder level of a bucket.  Folder-style by default: sub-prefixes come back as directory entries, which is the file-manager view. `?recursive=true` lists every key flat under the prefix instead. Keys are RELATIVE to `?prefix=`, and the listing is bounded so a huge bucket cannot exhaust memory — Total is what came back, not what the bucket holds.  Billed per call: the balance is checked BEFORE anything is touched, so an unfunded org is refused with nothing read, and the debit lands only once the listing has succeeded.
130pub async fn get_s3_buckets_by_bucket_objects(configuration: &configuration::Configuration, bucket: &str, prefix: Option<&str>, recursive: Option<&str>) -> Result<models::ObjectList, Error<GetS3BucketsByBucketObjectsError>> {
131    // add a prefix to parameters to efficiently prevent name collisions
132    let p_bucket = bucket;
133    let p_prefix = prefix;
134    let p_recursive = recursive;
135
136    let uri_str = format!("{}/v1/s3/buckets/{bucket}/objects", configuration.base_path, bucket=crate::apis::urlencode(p_bucket));
137    let mut req_builder = configuration.client.request(reqwest::Method::GET, &uri_str);
138
139    if let Some(ref param_value) = p_prefix {
140        req_builder = req_builder.query(&[("prefix", &param_value.to_string())]);
141    }
142    if let Some(ref param_value) = p_recursive {
143        req_builder = req_builder.query(&[("recursive", &param_value.to_string())]);
144    }
145    if let Some(ref user_agent) = configuration.user_agent {
146        req_builder = req_builder.header(reqwest::header::USER_AGENT, user_agent.clone());
147    }
148    if let Some(ref token) = configuration.bearer_access_token {
149        req_builder = req_builder.bearer_auth(token.to_owned());
150    };
151
152    let req = req_builder.build()?;
153    let resp = configuration.client.execute(req).await?;
154
155    let status = resp.status();
156    let content_type = resp
157        .headers()
158        .get("content-type")
159        .and_then(|v| v.to_str().ok())
160        .unwrap_or("application/octet-stream");
161    let content_type = super::ContentType::from(content_type);
162
163    if !status.is_client_error() && !status.is_server_error() {
164        let content = resp.text().await?;
165        match content_type {
166            ContentType::Json => serde_json::from_str(&content).map_err(Error::from),
167            ContentType::Text => return Err(Error::from(serde_json::Error::custom("Received `text/plain` content type response that cannot be converted to `models::ObjectList`"))),
168            ContentType::Unsupported(unknown_type) => return Err(Error::from(serde_json::Error::custom(format!("Received `{unknown_type}` content type response that cannot be converted to `models::ObjectList`")))),
169        }
170    } else {
171        let content = resp.text().await?;
172        let entity: Option<GetS3BucketsByBucketObjectsError> = serde_json::from_str(&content).ok();
173        Err(Error::ResponseError(ResponseContent { status, content, entity }))
174    }
175}
176
177/// Health reports whether this deployment can serve object storage.  It is a REAL probe rather than a constant: 200 when admin credentials are present, so the store is reachable in principle, and 503 with the reason when they are not. It is deliberately NOT gated — liveness has to be probe-able without a token — so it is the one operation here that names no bucket and bills nothing.
178pub async fn get_s3_health(configuration: &configuration::Configuration, ) -> Result<models::S3Health, Error<GetS3HealthError>> {
179
180    let uri_str = format!("{}/v1/s3/health", configuration.base_path);
181    let mut req_builder = configuration.client.request(reqwest::Method::GET, &uri_str);
182
183    if let Some(ref user_agent) = configuration.user_agent {
184        req_builder = req_builder.header(reqwest::header::USER_AGENT, user_agent.clone());
185    }
186    if let Some(ref token) = configuration.bearer_access_token {
187        req_builder = req_builder.bearer_auth(token.to_owned());
188    };
189
190    let req = req_builder.build()?;
191    let resp = configuration.client.execute(req).await?;
192
193    let status = resp.status();
194    let content_type = resp
195        .headers()
196        .get("content-type")
197        .and_then(|v| v.to_str().ok())
198        .unwrap_or("application/octet-stream");
199    let content_type = super::ContentType::from(content_type);
200
201    if !status.is_client_error() && !status.is_server_error() {
202        let content = resp.text().await?;
203        match content_type {
204            ContentType::Json => serde_json::from_str(&content).map_err(Error::from),
205            ContentType::Text => return Err(Error::from(serde_json::Error::custom("Received `text/plain` content type response that cannot be converted to `models::S3Health`"))),
206            ContentType::Unsupported(unknown_type) => return Err(Error::from(serde_json::Error::custom(format!("Received `{unknown_type}` content type response that cannot be converted to `models::S3Health`")))),
207        }
208    } else {
209        let content = resp.text().await?;
210        let entity: Option<GetS3HealthError> = serde_json::from_str(&content).ok();
211        Err(Error::ResponseError(ResponseContent { status, content, entity }))
212    }
213}
214
215/// Makes a new bucket for the caller's org and answers 201 with it.  The physical name is derived from the caller's validated org, so a tenant can only ever create inside its own namespace and no request field can redirect that. A name already taken in the org is 409.  Billed per call: the balance is checked BEFORE anything is touched, so an unfunded org is refused with nothing created, and the debit lands only once the bucket exists.
216pub async fn post_s3_buckets(configuration: &configuration::Configuration, bucket_in: models::BucketIn) -> Result<models::BucketItem, Error<PostS3BucketsError>> {
217    // add a prefix to parameters to efficiently prevent name collisions
218    let p_bucket_in = bucket_in;
219
220    let uri_str = format!("{}/v1/s3/buckets", configuration.base_path);
221    let mut req_builder = configuration.client.request(reqwest::Method::POST, &uri_str);
222
223    if let Some(ref user_agent) = configuration.user_agent {
224        req_builder = req_builder.header(reqwest::header::USER_AGENT, user_agent.clone());
225    }
226    if let Some(ref token) = configuration.bearer_access_token {
227        req_builder = req_builder.bearer_auth(token.to_owned());
228    };
229    req_builder = req_builder.json(&p_bucket_in);
230
231    let req = req_builder.build()?;
232    let resp = configuration.client.execute(req).await?;
233
234    let status = resp.status();
235    let content_type = resp
236        .headers()
237        .get("content-type")
238        .and_then(|v| v.to_str().ok())
239        .unwrap_or("application/octet-stream");
240    let content_type = super::ContentType::from(content_type);
241
242    if !status.is_client_error() && !status.is_server_error() {
243        let content = resp.text().await?;
244        match content_type {
245            ContentType::Json => serde_json::from_str(&content).map_err(Error::from),
246            ContentType::Text => return Err(Error::from(serde_json::Error::custom("Received `text/plain` content type response that cannot be converted to `models::BucketItem`"))),
247            ContentType::Unsupported(unknown_type) => return Err(Error::from(serde_json::Error::custom(format!("Received `{unknown_type}` content type response that cannot be converted to `models::BucketItem`")))),
248        }
249    } else {
250        let content = resp.text().await?;
251        let entity: Option<PostS3BucketsError> = serde_json::from_str(&content).ok();
252        Err(Error::ResponseError(ResponseContent { status, content, entity }))
253    }
254}
255
256/// Mints a presigned PUT URL the caller uploads to DIRECTLY.  The bytes never pass through this binary and the admin credential never leaves the server: the URL is signed against the PUBLIC host, scoped to exactly this bucket and key, and expires. A deployment with no public endpoint configured cannot mint one and answers 503 rather than a URL that will not work.  Billed per call — for MINTING the URL, which is the work this operation does; the upload that follows it goes straight to the store and is not seen here. The balance is checked BEFORE anything is touched, so an unfunded org is refused with no URL issued.
257pub async fn post_s3_buckets_by_bucket_objects(configuration: &configuration::Configuration, bucket: &str, upload_in: models::UploadIn) -> Result<models::PresignResponse, Error<PostS3BucketsByBucketObjectsError>> {
258    // add a prefix to parameters to efficiently prevent name collisions
259    let p_bucket = bucket;
260    let p_upload_in = upload_in;
261
262    let uri_str = format!("{}/v1/s3/buckets/{bucket}/objects", configuration.base_path, bucket=crate::apis::urlencode(p_bucket));
263    let mut req_builder = configuration.client.request(reqwest::Method::POST, &uri_str);
264
265    if let Some(ref user_agent) = configuration.user_agent {
266        req_builder = req_builder.header(reqwest::header::USER_AGENT, user_agent.clone());
267    }
268    if let Some(ref token) = configuration.bearer_access_token {
269        req_builder = req_builder.bearer_auth(token.to_owned());
270    };
271    req_builder = req_builder.json(&p_upload_in);
272
273    let req = req_builder.build()?;
274    let resp = configuration.client.execute(req).await?;
275
276    let status = resp.status();
277    let content_type = resp
278        .headers()
279        .get("content-type")
280        .and_then(|v| v.to_str().ok())
281        .unwrap_or("application/octet-stream");
282    let content_type = super::ContentType::from(content_type);
283
284    if !status.is_client_error() && !status.is_server_error() {
285        let content = resp.text().await?;
286        match content_type {
287            ContentType::Json => serde_json::from_str(&content).map_err(Error::from),
288            ContentType::Text => return Err(Error::from(serde_json::Error::custom("Received `text/plain` content type response that cannot be converted to `models::PresignResponse`"))),
289            ContentType::Unsupported(unknown_type) => return Err(Error::from(serde_json::Error::custom(format!("Received `{unknown_type}` content type response that cannot be converted to `models::PresignResponse`")))),
290        }
291    } else {
292        let content = resp.text().await?;
293        let entity: Option<PostS3BucketsByBucketObjectsError> = serde_json::from_str(&content).ok();
294        Err(Error::ResponseError(ResponseContent { status, content, entity }))
295    }
296}
297