From 0143ad49b17a2c3dd0acfabab9ad0194071fbcf9 Mon Sep 17 00:00:00 2001 From: "Rodrigo Rodriguez (Pragmatismo)" Date: Thu, 4 Dec 2025 09:33:31 -0300 Subject: [PATCH] Implement real code, remove dead code - AppState now uses BotServerClient directly - BOTSERVER_URL env var support for configuration - index() handler properly integrated into router - Removed unused web module (DTOs were never used) - Removed all #[allow(dead_code)] attributes - Zero warnings, cargo audit clean --- src/lib.rs | 22 +----- src/main.rs | 1 - src/shared/mod.rs | 8 +- src/shared/state.rs | 41 ++++------ src/ui_server/mod.rs | 153 ++++++++++++++++++++++--------------- src/web/health_handlers.rs | 56 -------------- src/web/mod.rs | 54 ------------- 7 files changed, 109 insertions(+), 226 deletions(-) delete mode 100644 src/web/health_handlers.rs delete mode 100644 src/web/mod.rs diff --git a/src/lib.rs b/src/lib.rs index e0e8214..96cad8b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -8,25 +8,9 @@ //! For desktop/mobile native features, see the `botapp` crate which //! wraps this pure web UI with Tauri. -// Re-export common types from botlib -pub use botlib::{ - branding, error, init_branding, is_white_label, platform_name, platform_short, ApiResponse, - BotError, BotResponse, BotResult, MessageType, Session, Suggestion, UserMessage, -}; - -// HTTP client is always available via botlib -pub use botlib::BotServerClient; - pub mod shared; - -#[cfg(feature = "ui-server")] pub mod ui_server; -#[cfg(feature = "ui-server")] -pub mod web; - -// Re-exports -pub use shared::*; - -#[cfg(feature = "ui-server")] -pub use ui_server::*; +// Re-export commonly used types +pub use shared::AppState; +pub use ui_server::configure_router; diff --git a/src/main.rs b/src/main.rs index 58618e2..94808cb 100644 --- a/src/main.rs +++ b/src/main.rs @@ -7,7 +7,6 @@ use log::info; mod shared; mod ui_server; -mod web; #[tokio::main] async fn main() -> std::io::Result<()> { diff --git a/src/shared/mod.rs b/src/shared/mod.rs index 5868322..83687a4 100644 --- a/src/shared/mod.rs +++ b/src/shared/mod.rs @@ -1,10 +1,8 @@ //! Shared types and state management for BotUI //! -//! This module re-exports common types from botlib and provides -//! UI-specific shared functionality. +//! This module provides shared application state and utilities +//! used across the UI server. pub mod state; -// Re-export from botlib for convenience - -// Local re-exports +pub use state::AppState; diff --git a/src/shared/state.rs b/src/shared/state.rs index 5af0633..66e6696 100644 --- a/src/shared/state.rs +++ b/src/shared/state.rs @@ -1,48 +1,33 @@ //! Application state management //! //! This module contains the shared application state that is passed to all -//! route handlers and provides access to database connections, configuration, -//! and other shared resources. - -#![allow(dead_code)] // Prepared for future use +//! route handlers and provides access to the BotServer client. +use botlib::http_client::BotServerClient; use std::sync::Arc; -use tokio::sync::RwLock; - -/// Database connection pool type -/// This would typically be a real connection pool in production -pub type DbPool = Arc>; /// Application state shared across all handlers #[derive(Clone)] pub struct AppState { - /// Database connection pool - pub conn: Arc>, - /// Configuration cache - pub config: Arc>>, - /// Session store - pub sessions: Arc>>, -} - -/// User session information -#[derive(Clone, Debug)] -pub struct Session { - pub user_id: String, - pub username: String, - pub email: String, - pub created_at: chrono::DateTime, - pub expires_at: chrono::DateTime, + /// HTTP client for communicating with BotServer + pub client: Arc, } impl AppState { /// Create a new application state + /// + /// Uses BOTSERVER_URL environment variable if set, otherwise defaults to localhost:8080 pub fn new() -> Self { + let url = std::env::var("BOTSERVER_URL").ok(); Self { - conn: Arc::new(std::sync::Mutex::new(())), - config: Arc::new(RwLock::new(std::collections::HashMap::new())), - sessions: Arc::new(RwLock::new(std::collections::HashMap::new())), + client: Arc::new(BotServerClient::new(url)), } } + + /// Check if the BotServer is healthy + pub async fn health_check(&self) -> bool { + self.client.health_check().await + } } impl Default for AppState { diff --git a/src/ui_server/mod.rs b/src/ui_server/mod.rs index 028d7e5..3b00128 100644 --- a/src/ui_server/mod.rs +++ b/src/ui_server/mod.rs @@ -2,8 +2,6 @@ //! //! Serves the web UI (suite, minimal) and handles API proxying. -#![allow(dead_code)] // Some functions prepared for future use - use axum::{ extract::State, http::StatusCode, @@ -12,17 +10,16 @@ use axum::{ Router, }; use log::error; -use std::{fs, path::PathBuf, sync::Arc}; -use tower_http::services::ServeDir; +use std::{fs, path::PathBuf}; -use botlib::http_client::BotServerClient; +use crate::shared::AppState; -// Serve minimal UI (default at /) +/// Serve the index page (minimal UI) pub async fn index() -> impl IntoResponse { serve_minimal().await } -// Handler for minimal UI +/// Handler for minimal UI 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)), @@ -37,7 +34,7 @@ pub async fn serve_minimal() -> impl IntoResponse { } } -// Handler for suite UI +/// Handler for suite UI 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)), @@ -52,49 +49,9 @@ pub async fn serve_suite() -> impl IntoResponse { } } -pub fn configure_router() -> Router { - let suite_path = PathBuf::from("./ui/suite"); - let minimal_path = PathBuf::from("./ui/minimal"); - let client = Arc::new(BotServerClient::new(None)); - - Router::new() - // API health check - .route("/health", get(health)) - .route("/api/health", get(api_health)) - // Default route serves minimal UI - .route("/", get(root)) - .route("/minimal", get(serve_minimal)) - // Suite UI route - .route("/suite", get(serve_suite)) - // Suite static assets (when accessing /suite/*) - .nest_service("/suite/js", ServeDir::new(suite_path.join("js"))) - .nest_service("/suite/css", ServeDir::new(suite_path.join("css"))) - .nest_service("/suite/public", ServeDir::new(suite_path.join("public"))) - .nest_service("/suite/drive", ServeDir::new(suite_path.join("drive"))) - .nest_service("/suite/chat", ServeDir::new(suite_path.join("chat"))) - .nest_service("/suite/mail", ServeDir::new(suite_path.join("mail"))) - .nest_service("/suite/tasks", ServeDir::new(suite_path.join("tasks"))) - // Legacy paths for backward compatibility (serve suite assets) - .nest_service("/js", ServeDir::new(suite_path.join("js"))) - .nest_service("/css", ServeDir::new(suite_path.join("css"))) - .nest_service("/public", ServeDir::new(suite_path.join("public"))) - .nest_service("/drive", ServeDir::new(suite_path.join("drive"))) - .nest_service("/chat", ServeDir::new(suite_path.join("chat"))) - .nest_service("/mail", ServeDir::new(suite_path.join("mail"))) - .nest_service("/tasks", ServeDir::new(suite_path.join("tasks"))) - // Fallback for other static files - .fallback_service( - ServeDir::new(minimal_path.clone()).fallback( - ServeDir::new(minimal_path.clone()).append_index_html_on_directories(true), - ), - ) - .with_state(client) -} - -async fn health( - State(client): State>, -) -> (StatusCode, axum::Json) { - match client.health_check().await { +/// Health check endpoint - checks BotServer connectivity +async fn health(State(state): State) -> (StatusCode, axum::Json) { + match state.health_check().await { true => ( StatusCode::OK, axum::Json(serde_json::json!({ @@ -114,25 +71,95 @@ async fn health( } } +/// API health check endpoint async fn api_health() -> (StatusCode, axum::Json) { ( StatusCode::OK, axum::Json(serde_json::json!({ "status": "ok", - "version": "1.0.0" + "version": env!("CARGO_PKG_VERSION") })), ) } -async fn root() -> axum::Json { - axum::Json(serde_json::json!({ - "service": "BotUI", - "version": "1.0.0", - "description": "General Bots User Interface", - "endpoints": { - "health": "/health", - "api": "/api/health", - "ui": "/" - } - })) +/// 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) } diff --git a/src/web/health_handlers.rs b/src/web/health_handlers.rs deleted file mode 100644 index ad7bd9a..0000000 --- a/src/web/health_handlers.rs +++ /dev/null @@ -1,56 +0,0 @@ -#![cfg(not(feature = "desktop"))] - -use axum::{extract::State, http::StatusCode, Json}; -use serde_json::json; -use std::sync::Arc; - -use crate::http_client::BotServerClient; - -/// Health check endpoint -pub async fn health( - State(client): State>, -) -> (StatusCode, Json) { - match client.health_check().await { - true => ( - StatusCode::OK, - Json(json!({ - "status": "healthy", - "service": "botui", - "mode": "web" - })), - ), - false => ( - StatusCode::SERVICE_UNAVAILABLE, - Json(json!({ - "status": "unhealthy", - "service": "botui", - "error": "botserver unreachable" - })), - ), - } -} - -/// API health check endpoint -pub async fn api_health() -> (StatusCode, Json) { - ( - StatusCode::OK, - Json(json!({ - "status": "ok", - "version": "1.0.0" - })), - ) -} - -/// Root endpoint -pub async fn root() -> Json { - Json(json!({ - "service": "BotUI", - "version": "1.0.0", - "description": "General Bots User Interface", - "endpoints": { - "health": "/health", - "api": "/api/health", - "ui": "/" - } - })) -} diff --git a/src/web/mod.rs b/src/web/mod.rs deleted file mode 100644 index 1ec3971..0000000 --- a/src/web/mod.rs +++ /dev/null @@ -1,54 +0,0 @@ -//! Web module with basic data structures -//! -//! Contains DTOs and types for the web API layer. - -#![allow(dead_code)] // DTOs prepared for future use - -use serde::{Deserialize, Serialize}; - -/// Request/Response DTOs for web API -#[derive(Debug, Deserialize, Serialize, Clone)] -pub struct Message { - pub id: String, - pub session_id: String, - pub sender: String, - pub content: String, - pub timestamp: String, - pub is_user: bool, -} - -#[derive(Debug, Deserialize, Serialize)] -pub struct ScanRequest { - pub bot_id: Option, - pub include_info: bool, -} - -#[derive(Debug, Serialize)] -pub struct IssueResponse { - pub id: String, - pub severity: String, - pub issue_type: String, - pub title: String, - pub description: String, - pub file_path: String, - pub line_number: Option, - pub code_snippet: Option, - pub remediation: String, - pub category: String, -} - -#[derive(Debug, Serialize)] -pub struct ScanSummary { - pub total_issues: usize, - pub critical_count: usize, - pub high_count: usize, - pub total_files_scanned: usize, - pub compliance_score: f64, -} - -#[derive(Debug, Serialize)] -pub struct ScanResponse { - pub scan_id: String, - pub issues: Vec, - pub summary: ScanSummary, -}