k8s-maestro 1.0.0

A Kubernetes job orchestrator tool library
Documentation
use anyhow::Result;
use axum::{
    extract::{Path, State},
    http::{HeaderMap, StatusCode},
    response::{IntoResponse, Json},
};
use std::sync::Arc;

use crate::steps::observers::TieredCache;

pub struct FileHttpService {
    cache: Arc<TieredCache>,
}

impl FileHttpService {
    pub fn new(cache: Arc<TieredCache>) -> Self {
        Self { cache }
    }

    pub async fn start(&self, port: u16) -> Result<()> {
        let app = axum::Router::new()
            .route("/files", axum::routing::get(list_files))
            .route("/files/:path", axum::routing::get(get_file))
            .route("/files/:path/metadata", axum::routing::get(get_metadata))
            .route("/files/:path", axum::routing::head(head_file))
            .with_state(self.cache.clone());

        let listener = tokio::net::TcpListener::bind(format!("0.0.0.0:{}", port)).await?;
        println!("File HTTP service listening on port {}", port);
        axum::serve(listener, app).await?;
        Ok(())
    }
}

async fn get_file(
    State(cache): State<Arc<TieredCache>>,
    Path(path): Path<String>,
) -> impl IntoResponse {
    match cache.get(&path).await {
        Some(content) => {
            let mut headers = HeaderMap::new();
            headers.insert("content-type", content.metadata.mime_type.parse().unwrap());
            headers.insert("content-length", content.metadata.size.to_string().parse().unwrap());
            (StatusCode::OK, headers, content.content).into_response()
        }
        None => StatusCode::NOT_FOUND.into_response(),
    }
}

async fn list_files(State(cache): State<Arc<TieredCache>>) -> impl IntoResponse {
    let files = cache.list().await;
    Json(files).into_response()
}

async fn get_metadata(
    State(cache): State<Arc<TieredCache>>,
    Path(path): Path<String>,
) -> impl IntoResponse {
    match cache.get(&path).await {
        Some(content) => Json(content.metadata).into_response(),
        None => StatusCode::NOT_FOUND.into_response(),
    }
}

async fn head_file(
    State(cache): State<Arc<TieredCache>>,
    Path(path): Path<String>,
) -> impl IntoResponse {
    match cache.get(&path).await {
        Some(content) => {
            let mut headers = HeaderMap::new();
            headers.insert("content-length", content.metadata.size.to_string().parse().unwrap());
            (StatusCode::OK, headers).into_response()
        }
        None => StatusCode::NOT_FOUND.into_response(),
    }
}