use axum::{
extract::{Path, Query, State},
http::StatusCode,
Json,
};
use serde::{Deserialize, Serialize};
use super::response::ApiResponse;
use crate::state::BosonState;
#[derive(Debug, Serialize, Deserialize)]
pub struct RunResponse {
pub run_id: String,
pub job_id: String,
pub task_name: String,
pub status: String,
pub attempt: i32,
pub started_at: String,
pub finished_at: Option<String>,
pub duration_ms: Option<i64>,
}
impl From<boson_core::Run> for RunResponse {
fn from(r: boson_core::Run) -> Self {
Self {
run_id: r.run_id,
job_id: r.job_id,
task_name: r.task_name,
status: r.status.to_string(),
attempt: r.attempt,
started_at: r.started_at.to_rfc3339(),
finished_at: r.finished_at.map(|t| t.to_rfc3339()),
duration_ms: r.duration_ms,
}
}
}
#[derive(Debug, Default, Deserialize)]
pub struct ListRunsQuery {
pub job_id: Option<String>,
pub limit: Option<usize>,
}
pub async fn list_runs(
State(state): State<BosonState>,
Query(q): Query<ListRunsQuery>,
) -> Json<ApiResponse<Vec<RunResponse>>> {
let limit = q.limit.unwrap_or(100);
match state
.boson
.list_runs(q.job_id.as_deref(), 0, limit)
.await
{
Ok(runs) => Json(ApiResponse::ok(runs.into_iter().map(RunResponse::from).collect())),
Err(e) => Json(ApiResponse::err(e.to_string())),
}
}
pub async fn get_run(
State(state): State<BosonState>,
Path(id): Path<String>,
) -> (StatusCode, Json<ApiResponse<RunResponse>>) {
match state.boson.get_run(&id).await {
Ok(Some(r)) => (StatusCode::OK, Json(ApiResponse::ok(r.into()))),
Ok(None) => (
StatusCode::NOT_FOUND,
Json(ApiResponse::err(format!("Run '{id}' not found"))),
),
Err(e) => (
StatusCode::INTERNAL_SERVER_ERROR,
Json(ApiResponse::err(e.to_string())),
),
}
}