service/http_server/api/v0/bucket/
list.rs

1use axum::extract::{Json, State};
2use axum::response::{IntoResponse, Response};
3use reqwest::{Client, RequestBuilder, Url};
4use serde::{Deserialize, Serialize};
5use time::OffsetDateTime;
6use uuid::Uuid;
7
8use common::prelude::Link;
9
10use crate::http_server::api::client::ApiRequest;
11use crate::ServiceState;
12
13#[derive(Debug, Clone, Serialize, Deserialize)]
14#[cfg_attr(feature = "clap", derive(clap::Args))]
15pub struct ListRequest {
16    /// Optional prefix filter
17    #[serde(skip_serializing_if = "Option::is_none")]
18    #[cfg_attr(feature = "clap", arg(long))]
19    pub prefix: Option<String>,
20
21    /// Optional limit
22    #[serde(skip_serializing_if = "Option::is_none")]
23    #[cfg_attr(feature = "clap", arg(long))]
24    pub limit: Option<u32>,
25}
26
27#[derive(Debug, Clone, Serialize, Deserialize)]
28pub struct ListResponse {
29    pub buckets: Vec<BucketInfo>,
30}
31
32#[derive(Debug, Clone, Serialize, Deserialize)]
33pub struct BucketInfo {
34    pub bucket_id: Uuid,
35    pub name: String,
36    pub link: Link,
37    #[serde(with = "time::serde::rfc3339")]
38    pub created_at: OffsetDateTime,
39}
40
41pub async fn handler(
42    State(state): State<ServiceState>,
43    Json(_req): Json<ListRequest>,
44) -> Result<impl IntoResponse, ListError> {
45    // Use mount_ops to list buckets
46    let buckets = crate::mount_ops::list_buckets(&state)
47        .await
48        .map_err(|e| ListError::MountOps(e.to_string()))?;
49
50    // Convert to response format
51    let bucket_infos = buckets
52        .into_iter()
53        .map(|b| BucketInfo {
54            bucket_id: b.bucket_id,
55            name: b.name,
56            link: b.link,
57            created_at: b.created_at,
58        })
59        .collect();
60
61    Ok((
62        http::StatusCode::OK,
63        Json(ListResponse {
64            buckets: bucket_infos,
65        }),
66    )
67        .into_response())
68}
69
70#[derive(Debug, thiserror::Error)]
71pub enum ListError {
72    #[error("MountOps error: {0}")]
73    MountOps(String),
74}
75
76impl IntoResponse for ListError {
77    fn into_response(self) -> Response {
78        match self {
79            ListError::MountOps(_) => (
80                http::StatusCode::INTERNAL_SERVER_ERROR,
81                "unknown server error",
82            )
83                .into_response(),
84        }
85    }
86}
87
88// Client implementation - builds request for this operation
89impl ApiRequest for ListRequest {
90    type Response = ListResponse;
91
92    fn build_request(self, base_url: &Url, client: &Client) -> RequestBuilder {
93        let full_url = base_url.join("/api/v0/bucket/list").unwrap();
94        client.post(full_url).json(&self)
95    }
96}