use axum::{
extract::{Query, State},
routing::{get, post},
Json, Router,
};
use serde::{Deserialize, Serialize};
use crate::error::ServerError;
use crate::state::AppState;
use routa_core::acp::docker::{DockerContainerConfig, DockerStatus};
pub fn router() -> Router<AppState> {
Router::new()
.route("/status", get(docker_status))
.route("/pull", post(docker_pull))
.route("/containers", get(list_containers))
.route("/container/start", post(start_container))
.route("/container/stop", post(stop_container))
}
#[derive(Debug, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct DockerStatusQuery {
#[serde(default)]
force_refresh: bool,
}
async fn docker_status(
State(state): State<AppState>,
Query(query): Query<DockerStatusQuery>,
) -> Result<Json<DockerStatus>, ServerError> {
let status = state
.docker_state
.detector
.check_availability(query.force_refresh)
.await;
Ok(Json(status))
}
#[derive(Debug, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct DockerPullRequest {
pub image: String,
}
async fn docker_pull(
State(state): State<AppState>,
Json(body): Json<DockerPullRequest>,
) -> Result<Json<serde_json::Value>, ServerError> {
let result = state.docker_state.detector.pull_image(&body.image).await;
Ok(Json(serde_json::json!({
"ok": result.ok,
"image": result.image,
"output": result.output,
"error": result.error,
})))
}
async fn list_containers(
State(state): State<AppState>,
) -> Result<Json<serde_json::Value>, ServerError> {
let containers = state.docker_state.process_manager.list_containers().await;
Ok(Json(serde_json::json!({
"containers": containers,
})))
}
#[derive(Debug, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct StartContainerRequest {
pub session_id: String,
pub image: String,
pub workspace_path: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub auth_json: Option<String>,
}
async fn start_container(
State(state): State<AppState>,
Json(body): Json<StartContainerRequest>,
) -> Result<Json<serde_json::Value>, ServerError> {
let config = DockerContainerConfig {
session_id: body.session_id.clone(),
image: body.image,
workspace_path: body.workspace_path,
env: None,
additional_volumes: None,
labels: None,
container_port: None,
auth_json: body.auth_json,
};
match state
.docker_state
.process_manager
.start_container(config)
.await
{
Ok(info) => Ok(Json(serde_json::json!({
"ok": true,
"container": info,
}))),
Err(e) => Ok(Json(serde_json::json!({
"ok": false,
"error": e,
}))),
}
}
#[derive(Debug, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct StopContainerRequest {
pub session_id: String,
}
async fn stop_container(
State(state): State<AppState>,
Json(body): Json<StopContainerRequest>,
) -> Result<Json<serde_json::Value>, ServerError> {
match state
.docker_state
.process_manager
.stop_container(&body.session_id)
.await
{
Ok(()) => Ok(Json(serde_json::json!({ "ok": true }))),
Err(e) => Ok(Json(serde_json::json!({ "ok": false, "error": e }))),
}
}