botui/src/ui_server/mod.rs

166 lines
5.1 KiB
Rust
Raw Normal View History

//! UI Server module for BotUI
//!
//! Serves the web UI (suite, minimal) and handles API proxying.
2025-12-03 18:42:22 -03:00
use axum::{
extract::State,
http::StatusCode,
response::{Html, IntoResponse},
routing::get,
Router,
};
use log::error;
use std::{fs, path::PathBuf};
2025-12-03 18:42:22 -03:00
use crate::shared::AppState;
2025-12-03 18:42:22 -03:00
/// Serve the index page (minimal UI)
2025-12-03 18:42:22 -03:00
pub async fn index() -> impl IntoResponse {
serve_minimal().await
}
/// Handler for minimal UI
2025-12-03 18:42:22 -03:00
pub async fn serve_minimal() -> impl IntoResponse {
match fs::read_to_string("ui/minimal/index.html") {
Ok(html) => (StatusCode::OK, [("content-type", "text/html")], Html(html)),
Err(e) => {
error!("Failed to load minimal UI: {}", e);
(
StatusCode::INTERNAL_SERVER_ERROR,
[("content-type", "text/plain")],
Html("Failed to load minimal interface".to_string()),
)
}
}
}
/// Handler for suite UI
2025-12-03 18:42:22 -03:00
pub async fn serve_suite() -> impl IntoResponse {
match fs::read_to_string("ui/suite/index.html") {
Ok(html) => (StatusCode::OK, [("content-type", "text/html")], Html(html)),
Err(e) => {
error!("Failed to load suite UI: {}", e);
(
StatusCode::INTERNAL_SERVER_ERROR,
[("content-type", "text/plain")],
Html("Failed to load suite interface".to_string()),
)
}
}
}
/// Health check endpoint - checks BotServer connectivity
async fn health(State(state): State<AppState>) -> (StatusCode, axum::Json<serde_json::Value>) {
match state.health_check().await {
2025-12-03 18:42:22 -03:00
true => (
StatusCode::OK,
axum::Json(serde_json::json!({
"status": "healthy",
"service": "botui",
"mode": "web"
})),
),
false => (
StatusCode::SERVICE_UNAVAILABLE,
axum::Json(serde_json::json!({
"status": "unhealthy",
"service": "botui",
"error": "botserver unreachable"
})),
),
}
}
/// API health check endpoint
2025-12-03 18:42:22 -03:00
async fn api_health() -> (StatusCode, axum::Json<serde_json::Value>) {
(
StatusCode::OK,
axum::Json(serde_json::json!({
"status": "ok",
"version": env!("CARGO_PKG_VERSION")
2025-12-03 18:42:22 -03:00
})),
)
}
/// Configure and return the main router
pub fn configure_router() -> Router {
let suite_path = PathBuf::from("./ui/suite");
let minimal_path = PathBuf::from("./ui/minimal");
let state = AppState::new();
Router::new()
// Health check endpoints
.route("/health", get(health))
.route("/api/health", get(api_health))
// UI routes
.route("/", get(index))
.route("/minimal", get(serve_minimal))
.route("/suite", get(serve_suite))
// Suite static assets (when accessing /suite/*)
.nest_service(
"/suite/js",
tower_http::services::ServeDir::new(suite_path.join("js")),
)
.nest_service(
"/suite/css",
tower_http::services::ServeDir::new(suite_path.join("css")),
)
.nest_service(
"/suite/public",
tower_http::services::ServeDir::new(suite_path.join("public")),
)
.nest_service(
"/suite/drive",
tower_http::services::ServeDir::new(suite_path.join("drive")),
)
.nest_service(
"/suite/chat",
tower_http::services::ServeDir::new(suite_path.join("chat")),
)
.nest_service(
"/suite/mail",
tower_http::services::ServeDir::new(suite_path.join("mail")),
)
.nest_service(
"/suite/tasks",
tower_http::services::ServeDir::new(suite_path.join("tasks")),
)
// Legacy paths for backward compatibility (serve suite assets)
.nest_service(
"/js",
tower_http::services::ServeDir::new(suite_path.join("js")),
)
.nest_service(
"/css",
tower_http::services::ServeDir::new(suite_path.join("css")),
)
.nest_service(
"/public",
tower_http::services::ServeDir::new(suite_path.join("public")),
)
.nest_service(
"/drive",
tower_http::services::ServeDir::new(suite_path.join("drive")),
)
.nest_service(
"/chat",
tower_http::services::ServeDir::new(suite_path.join("chat")),
)
.nest_service(
"/mail",
tower_http::services::ServeDir::new(suite_path.join("mail")),
)
.nest_service(
"/tasks",
tower_http::services::ServeDir::new(suite_path.join("tasks")),
)
// Fallback for other static files
.fallback_service(
tower_http::services::ServeDir::new(minimal_path.clone()).fallback(
tower_http::services::ServeDir::new(minimal_path)
.append_index_html_on_directories(true),
),
)
.with_state(state)
2025-12-03 18:42:22 -03:00
}