2025-11-22 22:55:35 -03:00
|
|
|
use crate::config::ConfigManager;
|
Add .env.example with comprehensive configuration template
The commit adds a complete example environment configuration file
documenting all available settings for BotServer, including logging,
database, server, drive, LLM, Redis, email, and feature flags.
Also removes hardcoded environment variable usage throughout the
codebase, replacing them with configuration via config.csv or
appropriate defaults. This includes:
- WhatsApp, Teams, Instagram adapter configurations
- Weather API key handling
- Email and directory service configurations
- Console feature conditionally compiles monitoring code
- Improved logging configuration with library suppression
2025-11-28 13:19:03 -03:00
|
|
|
#[cfg(feature = "nvidia")]
|
2025-11-22 22:55:35 -03:00
|
|
|
use crate::nvidia;
|
Add .env.example with comprehensive configuration template
The commit adds a complete example environment configuration file
documenting all available settings for BotServer, including logging,
database, server, drive, LLM, Redis, email, and feature flags.
Also removes hardcoded environment variable usage throughout the
codebase, replacing them with configuration via config.csv or
appropriate defaults. This includes:
- WhatsApp, Teams, Instagram adapter configurations
- Weather API key handling
- Email and directory service configurations
- Console feature conditionally compiles monitoring code
- Improved logging configuration with library suppression
2025-11-28 13:19:03 -03:00
|
|
|
#[cfg(feature = "nvidia")]
|
2025-11-22 22:55:35 -03:00
|
|
|
use crate::nvidia::get_system_metrics;
|
|
|
|
|
use crate::shared::models::schema::bots::dsl::*;
|
|
|
|
|
use crate::shared::state::AppState;
|
|
|
|
|
use diesel::prelude::*;
|
|
|
|
|
use std::sync::Arc;
|
|
|
|
|
use sysinfo::System;
|
|
|
|
|
|
|
|
|
|
pub struct StatusPanel {
|
|
|
|
|
app_state: Arc<AppState>,
|
|
|
|
|
last_update: std::time::Instant,
|
|
|
|
|
cached_content: String,
|
|
|
|
|
system: System,
|
|
|
|
|
}
|
|
|
|
|
|
2025-12-02 21:09:43 -03:00
|
|
|
impl std::fmt::Debug for StatusPanel {
|
|
|
|
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
|
|
|
f.debug_struct("StatusPanel")
|
|
|
|
|
.field("app_state", &"Arc<AppState>")
|
|
|
|
|
.field("last_update", &self.last_update)
|
|
|
|
|
.field("cached_content_len", &self.cached_content.len())
|
2025-12-26 08:59:25 -03:00
|
|
|
.field("system", &"System")
|
2025-12-02 21:09:43 -03:00
|
|
|
.finish()
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-11-22 22:55:35 -03:00
|
|
|
impl StatusPanel {
|
|
|
|
|
pub fn new(app_state: Arc<AppState>) -> Self {
|
|
|
|
|
Self {
|
|
|
|
|
app_state,
|
|
|
|
|
last_update: std::time::Instant::now(),
|
|
|
|
|
cached_content: String::new(),
|
|
|
|
|
system: System::new_all(),
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-12-26 08:59:25 -03:00
|
|
|
pub fn update(&mut self) -> Result<(), std::io::Error> {
|
2025-11-22 22:55:35 -03:00
|
|
|
self.system.refresh_all();
|
2025-12-23 18:40:58 -03:00
|
|
|
|
2025-11-22 22:55:35 -03:00
|
|
|
let _tokens = (std::time::SystemTime::now()
|
|
|
|
|
.duration_since(std::time::UNIX_EPOCH)
|
feat(security): Complete security infrastructure implementation
SECURITY MODULES ADDED:
- security/auth.rs: Full RBAC with roles (Anonymous, User, Moderator, Admin, SuperAdmin, Service, Bot, BotOwner, BotOperator, BotViewer) and permissions
- security/cors.rs: Hardened CORS (no wildcard in production, env-based config)
- security/panic_handler.rs: Panic catching middleware with safe 500 responses
- security/path_guard.rs: Path traversal protection, null byte prevention
- security/request_id.rs: UUID request tracking with correlation IDs
- security/error_sanitizer.rs: Sensitive data redaction from responses
- security/zitadel_auth.rs: Zitadel token introspection and role mapping
- security/sql_guard.rs: SQL injection prevention with table whitelist
- security/command_guard.rs: Command injection prevention
- security/secrets.rs: Zeroizing secret management
- security/validation.rs: Input validation utilities
- security/rate_limiter.rs: Rate limiting with governor crate
- security/headers.rs: Security headers (CSP, HSTS, X-Frame-Options)
MAIN.RS UPDATES:
- Replaced tower_http::cors::Any with hardened create_cors_layer()
- Added panic handler middleware
- Added request ID tracking middleware
- Set global panic hook
SECURITY STATUS:
- 0 unwrap() in production code
- 0 panic! in production code
- 0 unsafe blocks
- cargo audit: PASS (no vulnerabilities)
- Estimated completion: ~98%
Remaining: Wire auth middleware to handlers, audit logs for sensitive data
2025-12-28 19:29:18 -03:00
|
|
|
.expect("system time after UNIX epoch")
|
2025-11-22 22:55:35 -03:00
|
|
|
.as_secs()
|
|
|
|
|
% 1000) as usize;
|
Add .env.example with comprehensive configuration template
The commit adds a complete example environment configuration file
documenting all available settings for BotServer, including logging,
database, server, drive, LLM, Redis, email, and feature flags.
Also removes hardcoded environment variable usage throughout the
codebase, replacing them with configuration via config.csv or
appropriate defaults. This includes:
- WhatsApp, Teams, Instagram adapter configurations
- Weather API key handling
- Email and directory service configurations
- Console feature conditionally compiles monitoring code
- Improved logging configuration with library suppression
2025-11-28 13:19:03 -03:00
|
|
|
#[cfg(feature = "nvidia")]
|
2025-11-22 22:55:35 -03:00
|
|
|
let _system_metrics = nvidia::get_system_metrics().unwrap_or_default();
|
|
|
|
|
self.cached_content = self.render(None);
|
|
|
|
|
self.last_update = std::time::Instant::now();
|
|
|
|
|
Ok(())
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn render(&mut self, selected_bot: Option<String>) -> String {
|
2025-12-26 08:59:25 -03:00
|
|
|
let mut lines = vec![
|
|
|
|
|
"╔═══════════════════════════════════════╗".to_string(),
|
|
|
|
|
"║ SYSTEM METRICS ║".to_string(),
|
|
|
|
|
"╚═══════════════════════════════════════╝".to_string(),
|
|
|
|
|
String::new(),
|
|
|
|
|
];
|
2025-11-22 22:55:35 -03:00
|
|
|
|
|
|
|
|
self.system.refresh_cpu_all();
|
|
|
|
|
let cpu_usage = self.system.global_cpu_usage();
|
|
|
|
|
let cpu_bar = Self::create_progress_bar(cpu_usage, 20);
|
|
|
|
|
lines.push(format!(" CPU: {:5.1}% {}", cpu_usage, cpu_bar));
|
Add .env.example with comprehensive configuration template
The commit adds a complete example environment configuration file
documenting all available settings for BotServer, including logging,
database, server, drive, LLM, Redis, email, and feature flags.
Also removes hardcoded environment variable usage throughout the
codebase, replacing them with configuration via config.csv or
appropriate defaults. This includes:
- WhatsApp, Teams, Instagram adapter configurations
- Weather API key handling
- Email and directory service configurations
- Console feature conditionally compiles monitoring code
- Improved logging configuration with library suppression
2025-11-28 13:19:03 -03:00
|
|
|
#[cfg(feature = "nvidia")]
|
|
|
|
|
{
|
|
|
|
|
let system_metrics = get_system_metrics().unwrap_or_default();
|
|
|
|
|
if let Some(gpu_usage) = system_metrics.gpu_usage {
|
|
|
|
|
let gpu_bar = Self::create_progress_bar(gpu_usage, 20);
|
|
|
|
|
lines.push(format!(" GPU: {:5.1}% {}", gpu_usage, gpu_bar));
|
|
|
|
|
} else {
|
|
|
|
|
lines.push(" GPU: Not available".to_string());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
#[cfg(not(feature = "nvidia"))]
|
|
|
|
|
{
|
|
|
|
|
lines.push(" GPU: Feature not enabled".to_string());
|
2025-11-22 22:55:35 -03:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
let total_mem = self.system.total_memory() as f32 / 1024.0 / 1024.0 / 1024.0;
|
|
|
|
|
let used_mem = self.system.used_memory() as f32 / 1024.0 / 1024.0 / 1024.0;
|
|
|
|
|
let mem_percentage = (used_mem / total_mem) * 100.0;
|
|
|
|
|
let mem_bar = Self::create_progress_bar(mem_percentage, 20);
|
|
|
|
|
lines.push(format!(
|
|
|
|
|
" MEM: {:5.1}% {} ({:.1}/{:.1} GB)",
|
|
|
|
|
mem_percentage, mem_bar, used_mem, total_mem
|
|
|
|
|
));
|
|
|
|
|
|
|
|
|
|
lines.push("".to_string());
|
|
|
|
|
lines.push("╔═══════════════════════════════════════╗".to_string());
|
|
|
|
|
lines.push("║ COMPONENTS STATUS ║".to_string());
|
|
|
|
|
lines.push("╚═══════════════════════════════════════╝".to_string());
|
|
|
|
|
lines.push("".to_string());
|
|
|
|
|
|
|
|
|
|
let components = vec![
|
|
|
|
|
("Tables", "postgres", "5432"),
|
|
|
|
|
("Cache", "valkey-server", "6379"),
|
|
|
|
|
("Drive", "minio", "9000"),
|
|
|
|
|
("LLM", "llama-server", "8081"),
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
for (comp_name, process, port) in components {
|
|
|
|
|
let status = if Self::check_component_running(process) {
|
2025-12-09 07:55:11 -03:00
|
|
|
format!(" ONLINE [Port: {}]", port)
|
2025-11-22 22:55:35 -03:00
|
|
|
} else {
|
2025-12-09 07:55:11 -03:00
|
|
|
" OFFLINE".to_string()
|
2025-11-22 22:55:35 -03:00
|
|
|
};
|
|
|
|
|
lines.push(format!(" {:<10} {}", comp_name, status));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
lines.push("".to_string());
|
|
|
|
|
lines.push("╔═══════════════════════════════════════╗".to_string());
|
|
|
|
|
lines.push("║ ACTIVE BOTS ║".to_string());
|
|
|
|
|
lines.push("╚═══════════════════════════════════════╝".to_string());
|
|
|
|
|
lines.push("".to_string());
|
|
|
|
|
|
|
|
|
|
if let Ok(mut conn) = self.app_state.conn.get() {
|
|
|
|
|
match bots
|
|
|
|
|
.filter(is_active.eq(true))
|
|
|
|
|
.select((name, id))
|
|
|
|
|
.load::<(String, uuid::Uuid)>(&mut *conn)
|
|
|
|
|
{
|
|
|
|
|
Ok(bot_list) => {
|
|
|
|
|
if bot_list.is_empty() {
|
|
|
|
|
lines.push(" No active bots".to_string());
|
|
|
|
|
} else {
|
|
|
|
|
for (bot_name, bot_id) in bot_list {
|
|
|
|
|
let marker = if let Some(ref selected) = selected_bot {
|
|
|
|
|
if selected == &bot_name {
|
|
|
|
|
"►"
|
|
|
|
|
} else {
|
|
|
|
|
" "
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
" "
|
|
|
|
|
};
|
2025-12-09 07:55:11 -03:00
|
|
|
lines.push(format!(" {} {}", marker, bot_name));
|
2025-11-22 22:55:35 -03:00
|
|
|
|
|
|
|
|
if let Some(ref selected) = selected_bot {
|
|
|
|
|
if selected == &bot_name {
|
|
|
|
|
lines.push("".to_string());
|
|
|
|
|
lines.push(" ┌─ Bot Configuration ─────────┐".to_string());
|
|
|
|
|
let config_manager =
|
|
|
|
|
ConfigManager::new(self.app_state.conn.clone());
|
|
|
|
|
let llm_model = config_manager
|
|
|
|
|
.get_config(&bot_id, "llm-model", None)
|
|
|
|
|
.unwrap_or_else(|_| "N/A".to_string());
|
|
|
|
|
lines.push(format!(" Model: {}", llm_model));
|
|
|
|
|
let ctx_size = config_manager
|
|
|
|
|
.get_config(&bot_id, "llm-server-ctx-size", None)
|
|
|
|
|
.unwrap_or_else(|_| "N/A".to_string());
|
|
|
|
|
lines.push(format!(" Context: {}", ctx_size));
|
|
|
|
|
let temp = config_manager
|
|
|
|
|
.get_config(&bot_id, "llm-temperature", None)
|
|
|
|
|
.unwrap_or_else(|_| "N/A".to_string());
|
|
|
|
|
lines.push(format!(" Temp: {}", temp));
|
|
|
|
|
lines.push(" └─────────────────────────────┘".to_string());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
Err(_) => {
|
|
|
|
|
lines.push(" Error loading bots".to_string());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
lines.push(" Database locked".to_string());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
lines.push("".to_string());
|
|
|
|
|
lines.push("╔═══════════════════════════════════════╗".to_string());
|
|
|
|
|
lines.push("║ SESSIONS ║".to_string());
|
|
|
|
|
lines.push("╚═══════════════════════════════════════╝".to_string());
|
|
|
|
|
|
|
|
|
|
let session_count = self
|
|
|
|
|
.app_state
|
|
|
|
|
.response_channels
|
|
|
|
|
.try_lock()
|
|
|
|
|
.map(|channels| channels.len())
|
|
|
|
|
.unwrap_or(0);
|
|
|
|
|
lines.push(format!(" Active Sessions: {}", session_count));
|
|
|
|
|
|
|
|
|
|
lines.join("\n")
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn create_progress_bar(percentage: f32, width: usize) -> String {
|
|
|
|
|
let filled = (percentage / 100.0 * width as f32).round() as usize;
|
|
|
|
|
let empty = width.saturating_sub(filled);
|
|
|
|
|
let filled_chars = "█".repeat(filled);
|
|
|
|
|
let empty_chars = "░".repeat(empty);
|
|
|
|
|
format!("[{}{}]", filled_chars, empty_chars)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn check_component_running(process_name: &str) -> bool {
|
|
|
|
|
std::process::Command::new("pgrep")
|
|
|
|
|
.arg("-f")
|
|
|
|
|
.arg(process_name)
|
|
|
|
|
.output()
|
|
|
|
|
.map(|output| !output.stdout.is_empty())
|
|
|
|
|
.unwrap_or(false)
|
|
|
|
|
}
|
|
|
|
|
}
|