use super::AppState;
use crate::error::AppError;
use crate::routines;
use axum::{extract::State, http::StatusCode, Json};
use serde::{Deserialize, Serialize};
#[derive(Serialize, utoipa::ToSchema)]
pub struct MachineResponse {
pub name: String,
}
#[utoipa::path(get, path = "/machine",
responses((status = 200, body = MachineResponse)))]
pub async fn get_current_machine() -> Json<MachineResponse> {
Json(MachineResponse {
name: crate::machine::current_machine(),
})
}
#[derive(Deserialize, utoipa::ToSchema)]
pub struct SetMachineRequest {
pub name: String,
}
#[utoipa::path(put, path = "/machine",
request_body = SetMachineRequest,
responses(
(status = 200, body = MachineResponse),
(status = 400, description = "Empty name"),
(status = 500, description = "Write failed"),
))]
pub async fn put_machine(
State(state): State<AppState>,
Json(body): Json<SetMachineRequest>,
) -> Result<Json<MachineResponse>, (StatusCode, String)> {
let old_name = crate::machine::current_machine();
let new_name = body.name.trim().to_string();
match crate::machine::set_machine(&new_name) {
Ok(()) => {
routines::svc_rename_machine(&state.routines, &old_name, &new_name);
Ok(Json(MachineResponse { name: new_name }))
}
Err(err) if err.kind() == std::io::ErrorKind::InvalidInput => {
Err((StatusCode::BAD_REQUEST, err.to_string()))
}
Err(err) => Err((StatusCode::INTERNAL_SERVER_ERROR, err.to_string())),
}
}
#[utoipa::path(get, path = "/config/user-prompt",
responses((status = 200, description = "User prompt contents as plain text")))]
pub async fn get_user_prompt() -> Result<String, AppError> {
match std::fs::read_to_string(crate::paths::user_prompt_path()) {
Ok(text) => Ok(text),
Err(err) if err.kind() == std::io::ErrorKind::NotFound => Ok(String::new()),
Err(_) => Err(AppError::Internal),
}
}
#[derive(Deserialize, utoipa::ToSchema)]
pub struct SetUserPromptRequest {
pub content: String,
}
#[utoipa::path(put, path = "/config/user-prompt",
request_body = SetUserPromptRequest,
responses((status = 204, description = "Saved"), (status = 500, description = "Write failed")))]
pub async fn put_user_prompt(
Json(body): Json<SetUserPromptRequest>,
) -> Result<StatusCode, AppError> {
let path = crate::paths::user_prompt_path();
let parent = path.parent().ok_or(AppError::Internal)?;
crate::utils::fs_perms::create_private_dir_all(parent).map_err(|_| AppError::Internal)?;
std::fs::write(&path, &body.content).map_err(|_| AppError::Internal)?;
Ok(StatusCode::NO_CONTENT)
}
#[derive(Serialize, utoipa::ToSchema)]
pub struct MaxConcurrentRunsResponse {
pub value: usize,
pub override_value: Option<usize>,
}
#[utoipa::path(get, path = "/config/max-concurrent-runs",
responses((status = 200, body = MaxConcurrentRunsResponse)))]
pub async fn get_max_concurrent_runs() -> Json<MaxConcurrentRunsResponse> {
Json(MaxConcurrentRunsResponse {
value: routines::max_concurrent_runs(),
override_value: crate::machine::max_concurrent_runs_override(),
})
}
#[derive(Deserialize, utoipa::ToSchema)]
pub struct SetMaxConcurrentRunsRequest {
pub value: Option<usize>,
}
#[utoipa::path(put, path = "/config/max-concurrent-runs",
request_body = SetMaxConcurrentRunsRequest,
responses(
(status = 200, body = MaxConcurrentRunsResponse),
(status = 500, description = "Write failed"),
))]
pub async fn put_max_concurrent_runs(
Json(body): Json<SetMaxConcurrentRunsRequest>,
) -> Result<Json<MaxConcurrentRunsResponse>, AppError> {
crate::machine::set_max_concurrent_runs_override(body.value).map_err(|_| AppError::Internal)?;
Ok(Json(MaxConcurrentRunsResponse {
value: routines::max_concurrent_runs(),
override_value: body.value,
}))
}
#[utoipa::path(get, path = "/machines",
responses((status = 200, body = Vec<String>, description = "Known machine names, sorted")))]
pub async fn list_machines(State(state): State<AppState>) -> Json<Vec<String>> {
use crate::utils::lock::LockRecover;
let mut names = std::collections::BTreeSet::new();
names.insert(crate::machine::current_machine());
for routine in state.routines.lock_recover().values() {
names.extend(routine.machines.iter().cloned());
}
Json(names.into_iter().collect())
}