jax_daemon/http_server/api/v0/bucket/
history.rs1use 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 crate::http_server::api::client::ApiRequest;
9use crate::ServiceState;
10
11#[derive(Debug, Clone, Serialize, Deserialize, clap::Args)]
12pub struct HistoryRequest {
13 #[arg(long)]
15 pub bucket_id: Uuid,
16
17 #[serde(default)]
19 #[arg(long)]
20 pub page: Option<u32>,
21
22 #[serde(default)]
24 #[arg(long)]
25 pub page_size: Option<u32>,
26}
27
28#[derive(Debug, Clone, Serialize, Deserialize)]
29pub struct HistoryResponse {
30 pub bucket_id: Uuid,
31 pub entries: Vec<HistoryEntry>,
32}
33
34#[derive(Debug, Clone, Serialize, Deserialize)]
35pub struct HistoryEntry {
36 pub link_hash: String,
37 pub height: u64,
38 pub published: bool,
39 #[serde(with = "time::serde::rfc3339")]
40 pub created_at: OffsetDateTime,
41}
42
43pub async fn handler(
44 State(state): State<ServiceState>,
45 Json(req): Json<HistoryRequest>,
46) -> Result<impl IntoResponse, HistoryError> {
47 let page = req.page.unwrap_or(0);
48 let page_size = req.page_size.unwrap_or(50);
49
50 let entries = state
51 .database()
52 .get_bucket_logs(&req.bucket_id, page, page_size)
53 .await
54 .map_err(|e| HistoryError::Database(e.to_string()))?;
55
56 let history_entries: Vec<HistoryEntry> = entries
57 .into_iter()
58 .map(|e| HistoryEntry {
59 link_hash: e.current_link.to_string(),
60 height: e.height,
61 published: e.published,
62 created_at: e.created_at,
63 })
64 .collect();
65
66 Ok((
67 http::StatusCode::OK,
68 Json(HistoryResponse {
69 bucket_id: req.bucket_id,
70 entries: history_entries,
71 }),
72 )
73 .into_response())
74}
75
76#[derive(Debug, thiserror::Error)]
77pub enum HistoryError {
78 #[error("Database error: {0}")]
79 Database(String),
80}
81
82impl IntoResponse for HistoryError {
83 fn into_response(self) -> Response {
84 (
85 http::StatusCode::INTERNAL_SERVER_ERROR,
86 format!("Error: {}", self),
87 )
88 .into_response()
89 }
90}
91
92impl ApiRequest for HistoryRequest {
93 type Response = HistoryResponse;
94
95 fn build_request(self, base_url: &Url, client: &Client) -> RequestBuilder {
96 let full_url = base_url.join("/api/v0/bucket/history").unwrap();
97 client.post(full_url).json(&self)
98 }
99}