use axum::{extract::{Query, State}, http::StatusCode, routing::get, Json, Router};
use serde::Deserialize;
use serde_json::{json, Value};
use crate::fs::{self, SortKey};
use crate::AppState;
pub fn routes() -> Router<AppState> {
Router::new()
.route("/system/info", get(system_info))
.route("/system/dirs", get(list_dirs))
.route("/system/exists", get(check_exists))
.route("/system/multiplexer", get(multiplexer_status))
}
#[derive(Deserialize)]
struct ListDirsQuery {
path: String,
}
async fn system_info() -> Json<Value> {
let home = std::env::var("HOME")
.or_else(|_| std::env::var("USERPROFILE"))
.unwrap_or_else(|_| "/".into());
Json(json!({
"home_dir": home,
}))
}
async fn list_dirs(
State(_state): State<AppState>,
Query(q): Query<ListDirsQuery>,
) -> (axum::http::StatusCode, Json<Value>) {
let path = std::path::Path::new(&q.path);
let canonical = match path.canonicalize() {
Ok(p) => p,
Err(_) => {
return (
axum::http::StatusCode::NOT_FOUND,
Json(json!({ "error": "path not found" })),
);
}
};
if !canonical.is_dir() {
return (
axum::http::StatusCode::BAD_REQUEST,
Json(json!({ "error": "not a directory" })),
);
}
match fs::list_dir(&canonical, "", SortKey::Name, false).await {
Ok(entries) => (
axum::http::StatusCode::OK,
Json(json!({ "files": entries })),
),
Err(e) => (
axum::http::StatusCode::INTERNAL_SERVER_ERROR,
Json(json!({ "error": e.to_string() })),
),
}
}
#[derive(Deserialize)]
struct ExistsQuery {
path: String,
}
async fn check_exists(
Query(q): Query<ExistsQuery>,
) -> (StatusCode, Json<Value>) {
let exists = std::path::Path::new(&q.path).exists();
(StatusCode::OK, Json(json!({ "exists": exists })))
}
async fn multiplexer_status() -> (StatusCode, Json<Value>) {
match crate::tmux::check_multiplexer() {
Ok(()) => (StatusCode::OK, Json(json!({ "available": true }))),
Err(e) => (
StatusCode::SERVICE_UNAVAILABLE,
Json(json!({
"available": false,
"error": e.to_string(),
"install_hints": crate::tmux::MULTIPLEXER_INSTALL_HINTS,
})),
),
}
}