use crate::cli::commands::{DiagnosticOutputFormat, StorageCommand, TdgCommand};
use crate::tdg::{StorageBackendType, StorageConfig, TieredStorageFactory, TieredStore};
use anyhow::Result;
use prettytable::row;
use serde_json::json;
use std::path::PathBuf;
pub async fn handle_tdg_diagnostics(command: &TdgCommand, base_path: &PathBuf) -> Result<()> {
match command {
TdgCommand::Diagnostics {
detailed,
storage,
scheduler,
adaptive,
resources,
all,
format,
} => {
show_diagnostics(
base_path,
*detailed,
*storage || *all,
*scheduler || *all,
*adaptive || *all,
*resources || *all,
format.clone(),
)
.await
}
TdgCommand::Storage { command } => handle_storage_command(command, base_path).await,
TdgCommand::Compare { .. } => {
Ok(())
}
TdgCommand::Dashboard {
port,
host,
open,
update_interval,
} => handle_dashboard_command(*port, host.clone(), *open, *update_interval).await,
TdgCommand::Config(config_cmd) => {
super::config_command_handlers::handle_config_command(config_cmd).await
}
TdgCommand::Hooks(hooks_cmd) => {
super::hooks_command_handlers::handle_hooks_command(hooks_cmd).await
}
}
}
async fn show_diagnostics(
base_path: &PathBuf,
detailed: bool,
show_storage: bool,
_show_scheduler: bool,
_show_adaptive: bool,
_show_resources: bool,
format: DiagnosticOutputFormat,
) -> Result<()> {
if !show_storage {
return Ok(());
}
let storage = TieredStorageFactory::create_at_path(base_path)?;
let stats = storage.get_statistics();
match format {
DiagnosticOutputFormat::Plain => show_plain_diagnostics(&stats, detailed),
DiagnosticOutputFormat::Human => show_human_diagnostics(&stats, detailed),
DiagnosticOutputFormat::Json => show_json_diagnostics(&stats, show_storage)?,
DiagnosticOutputFormat::Yaml => show_yaml_diagnostics(&stats, show_storage)?,
DiagnosticOutputFormat::Table => show_table_diagnostics(&stats),
}
Ok(())
}
fn show_plain_diagnostics(stats: &crate::tdg::storage::StorageStatistics, detailed: bool) {
println!("TDG System Diagnostics\n");
print_basic_storage_info(stats);
if detailed {
show_backend_details(&stats.backend_stats);
}
}
fn show_human_diagnostics(stats: &crate::tdg::storage::StorageStatistics, detailed: bool) {
println!("=== TDG System Diagnostics ===\n");
println!("Storage Diagnostics:");
println!("{}", stats.format_diagnostic());
if detailed {
show_human_backend_details(&stats.backend_stats);
}
println!();
println!("Note: Full diagnostic infrastructure is in development.");
println!("Currently showing storage statistics only.");
}
fn show_json_diagnostics(
stats: &crate::tdg::storage::StorageStatistics,
show_storage: bool,
) -> Result<()> {
let json_output = json!({
"storage": if show_storage { Some(stats) } else { None },
"note": "Full diagnostic infrastructure in development"
});
println!("{}", serde_json::to_string_pretty(&json_output)?);
Ok(())
}
fn show_yaml_diagnostics(
stats: &crate::tdg::storage::StorageStatistics,
show_storage: bool,
) -> Result<()> {
let yaml_output = json!({
"storage": if show_storage { Some(stats) } else { None },
"note": "Full diagnostic infrastructure in development"
});
println!("{}", serde_yaml::to_string(&yaml_output)?);
Ok(())
}
fn show_table_diagnostics(stats: &crate::tdg::storage::StorageStatistics) {
use prettytable::{row, Table};
let mut table = Table::new();
table.add_row(row!["Component", "Status", "Details"]);
add_storage_table_rows(&mut table, stats);
table.printstd();
}
fn print_basic_storage_info(stats: &crate::tdg::storage::StorageStatistics) {
println!("Storage: {} entries", stats.total_entries);
println!(
"Hot: {}, Warm: {}, Cold: {}",
stats.hot_entries, stats.warm_entries, stats.cold_entries
);
println!(
"Backends - Warm: {}, Cold: {}",
stats.warm_backend, stats.cold_backend
);
println!(
"Compression: {:.1}%, Memory: {} KB",
stats.compression_ratio * 100.0,
stats.hot_memory_kb
);
}
fn show_backend_details(
backend_stats: &std::collections::HashMap<String, std::collections::HashMap<String, String>>,
) {
println!("\nBackend Details:");
for (tier, stats) in backend_stats {
println!("{tier}: {stats:?}");
}
}
fn show_human_backend_details(
backend_stats: &std::collections::HashMap<String, std::collections::HashMap<String, String>>,
) {
println!("\nBackend Details:");
for (tier, stats) in backend_stats {
println!(" {tier}:");
for (key, value) in stats {
println!(" {key}: {value}");
}
}
}
fn add_storage_table_rows(
table: &mut prettytable::Table,
stats: &crate::tdg::storage::StorageStatistics,
) {
table.add_row(row![
"Storage",
format!("{} entries", stats.total_entries),
format!(
"Hot: {}, Warm: {}, Cold: {}",
stats.hot_entries, stats.warm_entries, stats.cold_entries
)
]);
table.add_row(row![
"Backends",
format!("Warm: {}", stats.warm_backend),
format!("Cold: {}", stats.cold_backend)
]);
table.add_row(row![
"Compression",
format!("{:.1}%", stats.compression_ratio * 100.0),
format!("Memory: {} KB", stats.hot_memory_kb)
]);
}
async fn handle_storage_command(command: &StorageCommand, base_path: &PathBuf) -> Result<()> {
let storage = TieredStorageFactory::create_at_path(base_path)?;
match command {
StorageCommand::Stats { detailed } => handle_stats(&storage, *detailed),
StorageCommand::Cleanup { max_age } => handle_cleanup(&storage, *max_age),
StorageCommand::Migrate { backend, path } => handle_migrate(backend, path.as_ref()),
StorageCommand::Flush => handle_flush(&storage),
}
}
fn handle_stats(storage: &TieredStore, detailed: bool) -> Result<()> {
let stats = storage.get_statistics();
println!("=== TDG Storage Statistics ===\n");
println!("{}", stats.format_diagnostic());
if detailed {
print_backend_statistics(&stats.backend_stats);
}
Ok(())
}
fn print_backend_statistics(
backend_stats: &std::collections::HashMap<String, std::collections::HashMap<String, String>>,
) {
println!("\nBackend Statistics:");
for (tier, backend_stats) in backend_stats {
println!("\n{tier}:");
for (key, value) in backend_stats {
println!(" {key}: {value}");
}
}
}
fn handle_cleanup(storage: &TieredStore, max_age: u64) -> Result<()> {
let removed = storage.cleanup_hot_cache(max_age);
println!("Cleaned up {removed} expired hot cache entries");
Ok(())
}
fn handle_migrate(backend: &str, path: Option<&PathBuf>) -> Result<()> {
let backend_type = parse_backend_type(backend)?;
let (warm_config, cold_config) = create_migration_configs(backend_type, path);
println!("Migrating storage to {backend} backend...");
println!("⚠️ Migration requires restart to take effect");
println!("New configuration:");
println!(" Warm storage: {warm_config:?}");
println!(" Cold storage: {cold_config:?}");
Ok(())
}
fn parse_backend_type(backend: &str) -> Result<StorageBackendType> {
match backend {
"sled" => Ok(StorageBackendType::Sled),
"rocksdb" => Ok(StorageBackendType::RocksDb),
"inmemory" => Ok(StorageBackendType::InMemory),
_ => Err(anyhow::anyhow!(
"Unknown backend type: {backend}. Valid options: sled, rocksdb, inmemory"
)),
}
}
fn create_migration_configs(
backend_type: StorageBackendType,
path: Option<&PathBuf>,
) -> (StorageConfig, StorageConfig) {
let warm_config = StorageConfig {
backend_type,
path: path.map(|p| p.join("tdg-warm")),
cache_size_mb: Some(128),
compression: true,
};
let cold_config = StorageConfig {
backend_type,
path: path.map(|p| p.join("tdg-cold")),
cache_size_mb: Some(64),
compression: false,
};
(warm_config, cold_config)
}
fn handle_flush(storage: &TieredStore) -> Result<()> {
storage.flush()?;
println!("✅ All pending writes flushed to storage");
Ok(())
}
async fn handle_dashboard_command(
port: u16,
host: String,
open: bool,
_update_interval: u64,
) -> Result<()> {
use crate::tdg::web_dashboard::start_dashboard_server;
use std::net::{IpAddr, SocketAddr};
println!("🚀 Starting TDG Dashboard server...");
let addr: IpAddr = host.parse()?;
let socket_addr = SocketAddr::new(addr, port);
println!(
"📊 Dashboard will be available at: http://{host}:{port}"
);
println!("🔄 Real-time metrics updates enabled");
if open {
if let Err(e) = webbrowser::open(&format!("http://{host}:{port}")) {
eprintln!("⚠️ Could not open browser: {e}");
} else {
println!("🌐 Opening dashboard in browser...");
}
}
println!("Press Ctrl+C to stop the server");
start_dashboard_server(socket_addr)
.await
.map_err(|e| anyhow::anyhow!("Dashboard server error: {e}"))?;
Ok(())
}
#[cfg(test)]
mod property_tests {
use proptest::prelude::*;
proptest! {
#[test]
fn basic_property_stability(_input in ".*") {
prop_assert!(true);
}
#[test]
fn module_consistency_check(_x in 0u32..1000) {
prop_assert!(_x < 1001);
}
}
}