use axum::{ Router, extract::{Path, Query, State}, http::StatusCode, response::IntoResponse, routing::{delete, get, put}, }; use bytes::Bytes; use object_store::ObjectStore; use serde::Deserialize; use std::sync::Arc; use crate::ops; pub type StorageState = Arc; pub fn router(store: Arc) -> Router { Router::new() .route("/health", get(health)) .route("/objects/{*key}", put(put_object)) .route("/objects/{*key}", get(get_object)) .route("/objects/{*key}", delete(delete_object)) .route("/objects", get(list_objects)) .with_state(store) } async fn health() -> &'static str { "storaged ok" } async fn put_object( State(store): State, Path(key): Path, body: Bytes, ) -> impl IntoResponse { match ops::put(&store, &key, body).await { Ok(()) => (StatusCode::CREATED, format!("stored: {key}")), Err(e) => (StatusCode::INTERNAL_SERVER_ERROR, e), } } async fn get_object( State(store): State, Path(key): Path, ) -> impl IntoResponse { match ops::get(&store, &key).await { Ok(data) => Ok(data), Err(e) => Err((StatusCode::NOT_FOUND, e)), } } async fn delete_object( State(store): State, Path(key): Path, ) -> impl IntoResponse { match ops::delete(&store, &key).await { Ok(()) => (StatusCode::OK, format!("deleted: {key}")), Err(e) => (StatusCode::INTERNAL_SERVER_ERROR, e), } } #[derive(Deserialize)] struct ListQuery { prefix: Option, } async fn list_objects( State(store): State, Query(q): Query, ) -> impl IntoResponse { match ops::list(&store, q.prefix.as_deref()).await { Ok(keys) => Ok(axum::Json(keys)), Err(e) => Err((StatusCode::INTERNAL_SERVER_ERROR, e)), } }