1#![allow(non_snake_case)]
166
167use std::{env, net::SocketAddr, sync::Arc, time::Duration};
168
169use AirLibrary::dev_log;
170use tokio::{signal, time::interval};
171use AirLibrary::{
173 ApplicationState::ApplicationState,
174 Authentication::AuthenticationService,
175 CLI::{CliParser, Command, ConfigCommand, DebugCommand, OutputFormatter},
176 Configuration::{AirConfiguration, ConfigurationManager},
177 Daemon::DaemonManager,
178 DefaultBindAddress,
179 DefaultConfigFile,
180 Downloader::DownloadManager,
181 HealthCheck::{HealthCheckLevel, HealthCheckManager, HealthStatistics},
182 Indexing::FileIndexer,
183 Logging,
184 Metrics,
185 ProtocolVersion,
186 Tracing,
187 Updates::UpdateManager,
188 VERSION,
189 Vine::Generated::air::air_service_server::AirServiceServer,
190 Vine::Server::AirVinegRPCService::AirVinegRPCService,
191};
192
193macro_rules! Trace {
199 ($($arg:tt)*) => {{
200 dev_log!("lifecycle", $($arg)*);
201 }};
202}
203
204async fn WaitForShutdownSignal() {
216 dev_log!("lifecycle", "[Shutdown] Waiting for termination signal...");
217
218 let ctrl_c = async {
219 match signal::ctrl_c().await {
220 Ok(()) => dev_log!("lifecycle", "[Shutdown] Received Ctrl+C signal"),
221 Err(e) => dev_log!("lifecycle", "error: [Shutdown] Failed to install Ctrl+C handler: {}", e),
222 }
223 };
224
225 #[cfg(unix)]
226 let terminate = async {
227 match signal::unix::signal(signal::unix::SignalKind::terminate()) {
228 Ok(mut sig) => {
229 sig.recv().await;
230 dev_log!("lifecycle", "[Shutdown] Received SIGTERM signal");
231 },
232 Err(e) => dev_log!("lifecycle", "error: [Shutdown] Failed to install signal handler: {}", e),
233 }
234 };
235
236 #[cfg(not(unix))]
237 let terminate = std::future::pending::<()>();
238
239 tokio::select! {
240 _ = ctrl_c => {},
241 _ = terminate => {},
242 }
243
244 dev_log!("lifecycle", "[Shutdown] Signal received, initiating graceful shutdown");
245}
246
247fn InitializeLogging() {
264 let json_output = match std::env::var("AIR_LOG_JSON") {
266 Ok(val) if !val.is_empty() => {
267 let normalized = val.to_lowercase();
268 if normalized != "true" && normalized != "false" {
269 eprintln!(
270 "Warning: Invalid AIR_LOG_JSON value '{}', expected 'true' or 'false'. Using default: false",
271 val
272 );
273 false
274 } else {
275 normalized == "true"
276 }
277 },
278 Ok(_) => false,
279 Err(_) => false,
280 };
281
282 let log_file_path = std::env::var("AIR_LOG_FILE").ok().and_then(|path| {
284 if path.is_empty() {
285 None
286 } else {
287 if let Some(parent) = std::path::PathBuf::from(&path).parent() {
289 if parent.as_os_str().is_empty() {
290 Some(path)
292 } else if parent.exists() {
293 Some(path)
294 } else {
295 eprintln!(
296 "Warning: Log file directory does not exist: {}. Logging to stdout only.",
297 parent.display()
298 );
299 None
300 }
301 } else {
302 Some(path)
303 }
304 }
305 });
306
307 let log_result = Logging::InitializeLogger(json_output, log_file_path.clone());
309
310 match log_result {
311 Ok(_) => {
312 let log_info = match &log_file_path {
313 Some(path) => format!("file: {}", path),
314 None => "stdout/stderr".to_string(),
315 };
316 dev_log!(
317 "lifecycle",
318 "[Boot] Logging initialized - JSON: {}, Output: {}",
319 json_output,
320 log_info
321 );
322 },
323 Err(e) => {
324 eprintln!("[ERROR] Failed to initialize structured logging: {}", e);
326 eprintln!("[ERROR] Logging will fall back to stderr-only output");
327 },
328 }
329}
330
331fn ParseArguments() -> (Option<String>, Option<String>, Option<Command>) {
350 let args:Vec<String> = std::env::args().collect();
352
353 if args.len() > 1024 {
355 eprintln!("[ERROR] Too many command line arguments (max: 1024)");
356 std::process::exit(1);
357 }
358
359 for (i, arg) in args.iter().enumerate() {
361 if arg.len() > 4096 {
362 eprintln!("[ERROR] Argument at position {} is too long (max: 4096 characters)", i);
363 std::process::exit(1);
364 }
365 }
366
367 if args.len() > 1 {
369 match args[1].as_str() {
370 "status" | "restart" | "config" | "metrics" | "logs" | "debug" | "help" | "version" | "-h" | "--help"
371 | "-v" | "--version" => {
372 match CliParser::parse(args.clone()) {
374 Ok(cmd) => {
375 dev_log!("lifecycle", "[Boot] CLI command parsed: {:?}", cmd);
376 return (None, None, Some(cmd));
377 },
378 Err(e) => {
379 eprintln!("[ERROR] Error parsing CLI command: {}", e);
380 eprintln!("[ERROR] Run 'Air help' for usage information");
381 std::process::exit(1);
382 },
383 }
384 },
385 _ => {},
386 }
387 }
388
389 let mut config_path:Option<String> = None;
391 let mut bind_address:Option<String> = None;
392
393 let mut i = 0;
394 while i < args.len() {
395 match args[i].as_str() {
396 "--config" | "-c" => {
397 if i + 1 < args.len() {
398 let path = &args[i + 1];
399 if path.contains("..") || path.contains('\0') {
401 eprintln!("[ERROR] Invalid config path: contains '..' or null character");
402 std::process::exit(1);
403 }
404 config_path = Some(path.clone());
405 i += 1;
406 } else {
407 eprintln!("[ERROR] --config flag requires a path argument");
408 std::process::exit(1);
409 }
410 },
411 "--bind" | "-b" => {
412 if i + 1 < args.len() {
413 let addr = &args[i + 1];
414 if addr.is_empty() || addr.len() > 256 {
416 eprintln!("[ERROR] Invalid bind address: must be 1-256 characters");
417 std::process::exit(1);
418 }
419 if addr.contains('\0') {
421 eprintln!("[ERROR] Invalid bind address: contains null character");
422 std::process::exit(1);
423 }
424 bind_address = Some(addr.clone());
425 i += 1;
426 } else {
427 eprintln!("[ERROR] --bind flag requires an address argument");
428 std::process::exit(1);
429 }
430 },
431 _ => {
432 },
435 }
436 i += 1;
437 }
438
439 dev_log!(
440 "lifecycle",
441 "[Boot] Daemon mode - config: {:?}, bind: {:?}",
442 config_path,
443 bind_address
444 );
445
446 (config_path, bind_address, None)
447}
448
449async fn HandleCommand(cmd:Command) -> Result<(), Box<dyn std::error::Error>> {
472 let validation_result = validate_command(&cmd);
474 if let Err(e) = validation_result {
475 eprintln!("[ERROR] Command validation failed: {}", e);
476 return Err(e.into());
477 }
478
479 match cmd {
480 Command::Help { command } => {
481 if let Some(ref cmd) = command {
483 if cmd.len() > 128 {
484 eprintln!("[ERROR] Command name too long (max: 128 characters)");
485 return Err("Command name too long".into());
486 }
487 }
488 println!("{}", OutputFormatter::format_help(command.as_deref(), VERSION));
489 Ok(())
490 },
491
492 Command::Version => {
493 println!("Air {} ({})", VERSION, env!("CARGO_PKG_NAME"));
494 println!("Protocol: Version {} (gRPC)", ProtocolVersion);
495 println!("Port: {} (Air), {} (Cocoon)", DefaultBindAddress, "[::1]:50052");
496 println!("Build: {} {}", env!("CARGO_PKG_VERSION"), env!("CARGO_PKG_NAME"));
497 Ok(())
498 },
499
500 Command::Status { service, verbose, json } => {
501 if let Some(ref svc) = service {
503 if svc.is_empty() || svc.len() > 64 {
504 return Err("Service name must be 1-64 characters".into());
505 }
506 }
507
508 if let Some(svc) = service {
513 println!("📊 Status for service: {}", svc);
514
515 match attempt_daemon_connection().await {
517 Ok(_) => {
518 println!(" Status: ⚠️ Running (basic check)");
519 println!(" Note: Connect to gRPC endpoint for detailed status");
520 },
521 Err(e) => {
522 println!(" Status: ❌ Cannot connect to daemon");
523 println!(" Error: {}", e);
524 println!("");
525 println!(" To start the daemon, run: Air --daemon");
526 return Err(format!("Cannot connect to daemon: {}", e).into());
527 },
528 }
529 } else {
530 println!("📊 Air Daemon Status");
531 println!("");
532
533 match attempt_daemon_connection().await {
535 Ok(_) => {
536 println!(" Overall: ⚠️ Running (basic check)");
537 println!(" Note: Connect to gRPC endpoint for detailed status");
538 println!("");
539 println!(" Services:");
540 println!(" gRPC Server: ✅ Listening");
541 println!(" Authentication: ⚠️ Status check not implemented");
542 println!(" Updates: ⚠️ Status check not implemented");
543 println!(" Download Manager: ⚠️ Status check not implemented");
544 println!(" File Indexer: ⚠️ Status check not implemented");
545 },
546 Err(e) => {
547 println!(" Overall: ❌ Daemon not running");
548 println!(" Error: {}", e);
549 println!("");
550 println!(" To start the daemon, run: Air --daemon");
551 return Err("Daemon not running".into());
552 },
553 }
554 }
555
556 if verbose {
557 println!("");
558 println!("🔍 Verbose Information:");
559 println!(" Debug mode: Disabled by default");
560 println!(" Log level: info");
561 println!(" Config file: {}", DefaultConfigFile);
562 println!("");
563 println!(" Detailed service status can be obtained via gRPC:");
564 println!(" - Service uptime");
565 println!(" - Request/response statistics");
566 println!(" - Error rates and recent errors");
567 println!(" - Resource usage");
568 println!(" - Active connections");
569 }
570
571 if json {
572 println!("");
573 println!("📋 JSON Output:");
574 println!(
575 "{}",
576 serde_json::json!({
577 "overall": "running",
578 "services": {
579 "grpc": "listening",
580 "status": "not_implemented"
581 },
582 "note": "Detailed JSON output not yet implemented"
583 })
584 );
585 }
586
587 Ok(())
588 },
589
590 Command::Restart { service, force } => {
591 if let Some(ref svc) = service {
593 if svc.is_empty() || svc.len() > 64 {
594 return Err("Service name must be 1-64 characters".into());
595 }
596 }
597
598 println!("🔄 Restart Command");
601 println!("");
602
603 if let Some(svc) = service {
604 println!("Restarting service: {}", svc);
605 println!(" Note: Individual service restart requires gRPC integration");
606 println!(" Workaround: Restart the entire daemon");
607 } else {
608 println!("Restarting all services...");
609 println!(" Note: Full daemon restart requires gRPC integration");
610 println!(" Workaround: Use: kill <pid> && Air --daemon");
611 }
612
613 if force {
614 println!("");
615 println!("⚠️ Force mode enabled");
616 println!(
617 " Note: Force restart requires proper coordination to gracefully terminate in-progress operations"
618 );
619 }
620
621 Err("Restart command requires gRPC integration".into())
622 },
623
624 Command::Config(config_cmd) => {
625 match config_cmd {
626 ConfigCommand::Get { key } => {
627 if key.is_empty() || key.len() > 256 {
629 return Err("Configuration key must be 1-256 characters".into());
630 }
631 if key.contains('\0') || key.contains('\n') {
632 return Err("Configuration key contains invalid characters".into());
633 }
634
635 println!("⚙️ Get Configuration");
638 println!(" Key: {}", key);
639 println!("");
640
641 match attempt_daemon_connection().await {
642 Ok(_) => {
643 println!(" Status: ✅ Connected to daemon");
644 println!("");
645 println!(" Note: Config retrieval via gRPC not yet implemented");
646 println!(" Config value would be retrieved from daemon's configuration manager");
647 },
648 Err(e) => {
649 println!(" Status: ❌ Cannot connect to daemon");
650 println!(" Error: {}", e);
651 println!("");
652 println!(" Workaround: Check config file directly: cat {}", DefaultConfigFile);
653 return Err(format!("Cannot get config: {}", e).into());
654 },
655 }
656
657 Err("Config 'get' command requires gRPC integration".into())
658 },
659
660 ConfigCommand::Set { key, value } => {
661 if key.is_empty() || key.len() > 256 {
663 return Err("Configuration key must be 1-256 characters".into());
664 }
665 if value.len() > 8192 {
666 return Err("Configuration value too long (max: 8192 characters)".into());
667 }
668 if key.contains('\0') || key.contains('\n') {
669 return Err("Configuration key contains invalid characters".into());
670 }
671
672 println!("⚙️ Set Configuration");
675 println!(" Key: {}", key);
676 println!(" Value: {}", value);
677 println!("");
678
679 match attempt_daemon_connection().await {
680 Ok(_) => {
681 println!(" Status: ✅ Connected to daemon");
682 println!("");
683 println!(" Note: Config update via gRPC not yet implemented");
684 println!(" Config value would be set in daemon's configuration manager");
685 },
686 Err(e) => {
687 println!(" Status: ❌ Cannot connect to daemon");
688 println!(" Error: {}", e);
689 println!("");
690 println!(" Workaround: Edit config file directly, then use 'Air config reload'");
691 return Err(format!("Cannot set config: {}", e).into());
692 },
693 }
694
695 println!("");
696 println!(" ⚠️ Warning: Config changes may require reload or restart");
697
698 Err("Config 'set' command requires gRPC integration".into())
699 },
700
701 ConfigCommand::Reload { validate } => {
702 println!("🔄 Reload Configuration");
705 println!("");
706
707 match attempt_daemon_connection().await {
708 Ok(_) => {
709 println!(" Status: ✅ Connected to daemon");
710 println!("");
711 if validate {
712 println!(" Validating configuration...");
713 println!(" Note: Validation not yet implemented");
714 }
715 println!(" Note: Config reload via gRPC not yet implemented");
716 println!(" Workaround: Restart daemon to apply config changes");
717 },
718 Err(e) => {
719 println!(" Status: ❌ Cannot connect to daemon");
720 println!(" Error: {}", e);
721 return Err(format!("Cannot reload config: {}", e).into());
722 },
723 }
724
725 Err("Config 'reload' command requires gRPC integration".into())
726 },
727
728 ConfigCommand::Show { json } => {
729 println!("⚙️ Show Configuration");
732 println!("");
733
734 if json {
735 println!(" JSON output requested");
736 match attempt_daemon_connection().await {
737 Ok(_) => {
738 println!(" Status: ✅ Connected to daemon");
739 println!(" Note: JSON config export via gRPC not yet implemented");
740 },
741 Err(e) => {
742 println!(" Status: ❌ Cannot connect to daemon");
743 println!(" Error: {}", e);
744 return Err(format!("Cannot show config: {}", e).into());
745 },
746 }
747 } else {
748 println!(" Current Configuration:");
749 match attempt_daemon_connection().await {
750 Ok(_) => {
751 println!(" Status: ✅ Connected to daemon");
752 println!(" Note: Config display via gRPC not yet implemented");
753 },
754 Err(e) => {
755 println!(" Status: ❌ Cannot connect to daemon");
756 println!(" Error: {}", e);
757 println!(" Workaround: View config file: cat {}", DefaultConfigFile);
758 return Err(format!("Cannot show config: {}", e).into());
759 },
760 }
761 }
762
763 println!("");
764 println!(" Default config file: {}", DefaultConfigFile);
765 println!(" Config directory: ~/.config/Air/");
766
767 Err("Config 'show' command requires gRPC integration".into())
768 },
769
770 ConfigCommand::Validate { path } => {
771 if let Some(ref p) = path {
773 if p.is_empty() || p.len() > 512 {
774 return Err("Config path must be 1-512 characters".into());
775 }
776 if p.contains("..") || p.contains('\0') {
777 return Err("Config path contains invalid characters".into());
778 }
779 }
780
781 println!("✅ Validate Configuration");
782 println!("");
783
784 let config_path = path.unwrap_or_else(|| DefaultConfigFile.to_string());
785 println!(" Config file: {}", config_path);
786 println!("");
787
788 match std::path::Path::new(&config_path).exists() {
790 true => {
791 println!(" ✅ Config file exists");
792 println!(" Note: Detailed validation not yet implemented");
793 println!(" Workaround: Use: Air --validate-config");
794 },
795 false => {
796 println!(" ❌ Config file not found");
797 println!(" Hint: Create a config file or use defaults");
798 },
799 }
800
801 Err("Config 'validate' command not yet implemented".into())
802 },
803 }
804 },
805
806 Command::Metrics { json, service } => {
807 if let Some(ref svc) = service {
809 if svc.is_empty() || svc.len() > 64 {
810 return Err("Service name must be 1-64 characters".into());
811 }
812 }
813
814 println!("📊 Metrics");
815 println!("");
816
817 match attempt_daemon_connection().await {
819 Ok(_) => {
820 println!(" Status: ✅ Daemon is running");
821 println!("");
822 println!(" Note: Metrics collection is partially implemented");
823 println!("");
824 println!(" Current Metrics (basic):");
825 println!(" Uptime: Not tracked yet");
826 println!(" Requests: Not tracked yet");
827 println!(" Errors: Not tracked yet");
828 println!(" Memory: Not tracked yet");
829 println!(" CPU: Not tracked yet");
830 println!("");
831 println!(" Note: Comprehensive metrics require gRPC integration:");
832 println!(" - Request/response counters");
833 println!(" - Latency percentiles");
834 println!(" - Error rate tracking");
835 println!(" - Resource usage");
836 println!(" - Connection pool stats");
837 println!(" - Background queue depth");
838 },
839 Err(e) => {
840 println!(" Status: ❌ Cannot connect to daemon");
841 println!(" Error: {}", e);
842 return Err(format!("Cannot retrieve metrics: {}", e).into());
843 },
844 }
845
846 if json {
847 println!("");
848 println!("📋 JSON Output:");
849 println!(
850 "{}",
851 serde_json::json!({
852 "note": "Detailed metrics not yet implemented",
853 "suggestion": "Use /metrics endpoint when daemon is running"
854 })
855 );
856 }
857
858 if let Some(svc) = service {
859 println!("");
860 println!(" Service-specific metrics requested: {}", svc);
861 println!(" Note: Service isolation not yet implemented");
862 }
863
864 Ok(())
865 },
866
867 Command::Logs { service, tail, filter, follow } => {
868 if let Some(ref svc) = service {
870 if svc.is_empty() || svc.len() > 64 {
871 return Err("Service name must be 1-64 characters".into());
872 }
873 }
874 if let Some(n) = tail {
875 if n < 1 || n > 10000 {
876 return Err("Tail count must be 1-10000 lines".into());
877 }
878 }
879 if let Some(ref f) = filter {
880 if f.is_empty() || f.len() > 512 {
881 return Err("Filter string must be 1-512 characters".into());
882 }
883 }
884
885 println!("📝 Logs");
886 println!("");
887
888 let log_file = std::env::var("AIR_LOG_FILE").ok();
890 let log_dir = std::env::var("AIR_LOG_DIR").ok();
891
892 match (log_file, log_dir) {
893 (Some(file), _) => {
894 println!(" Log file: {}", file);
895
896 if std::path::Path::new(&file).exists() {
898 println!(" Status: ✅ Log file exists");
899 println!("");
900
901 println!(" Note: Log tailing via file API not yet implemented");
904 println!(" Workaround: Use standard tools:");
905 println!(" - tail -n {} {}", tail.unwrap_or(100), file);
906
907 if let Some(f) = filter {
908 println!(" - grep '{}' {} | tail -n {}", f, file, tail.unwrap_or(100));
909 }
910
911 if follow {
912 println!(" - tail -f {}", file);
913 }
914 } else {
915 println!(" Status: ❌ Log file not found");
916 println!(" Check logging configuration");
917 }
918 },
919 (_, Some(dir)) => {
920 println!(" Log directory: {}", dir);
921 println!(" Note: Log file viewing not yet implemented");
922 println!(" Workaround: Find and view log files in the directory");
923 },
924 _ => {
925 println!(" Log file: Not configured");
926 println!(" Set via: AIR_LOG_FILE=/path/to/Air.log");
927 println!("");
928 println!(" Logs are likely going to stdout/stderr");
929 println!(" Use journalctl (Linux/macOS) or Event Viewer (Windows)");
930 },
931 }
932
933 if let Some(svc) = service {
934 println!("");
935 println!(" Service-specific logs requested: {}", svc);
936 println!(" Note: Service log isolation not yet implemented");
937 }
938
939 Err("Logs command not yet fully implemented".into())
941 },
942
943 Command::Debug(debug_cmd) => {
944 match debug_cmd {
945 DebugCommand::DumpState { service, json } => {
946 if let Some(ref svc) = service {
948 if svc.is_empty() || svc.len() > 64 {
949 return Err("Service name must be 1-64 characters".into());
950 }
951 }
952
953 println!("🔧 Debug: Dump State");
954 println!("");
955
956 if let Some(svc) = service {
957 println!(" Service: {}", svc);
958 println!(" Note: Service state isolation not yet implemented");
959 } else {
960 println!(" Dumping all service states...");
961 println!(" Note: State dumping not yet implemented");
962 }
963
964 if json {
965 println!("");
966 println!(" JSON format requested");
967 println!(" Note: JSON state export not yet implemented");
968 }
969
970 println!("");
971 println!(" Note: State dumping requires gRPC integration:");
972 println!(" - Application state");
973 println!(" - Service states");
974 println!(" - Connection pool");
975 println!(" - Background tasks");
976 println!(" - Metrics cache");
977 println!(" - Configuration snapshot");
978
979 Err("Debug 'dump-state' command not yet implemented".into())
980 },
981
982 DebugCommand::DumpConnections { format } => {
983 println!("🔧 Debug: Dump Connections");
984 println!("");
985
986 match attempt_daemon_connection().await {
987 Ok(_) => {
988 println!(" Status: ✅ Daemon is running");
989 println!("");
990 println!(" Active Connections: 0");
991 println!(" Note: Connection tracking not yet implemented");
992 },
993 Err(e) => {
994 println!(" Status: ❌ Cannot connect to daemon");
995 println!(" Error: {}", e);
996 return Err(format!("Cannot dump connections: {}", e).into());
997 },
998 }
999
1000 if let Some(fmt) = format {
1001 println!("");
1002 println!(" Format: {}", fmt);
1003 println!(" Note: Custom format not yet implemented");
1004 }
1005
1006 println!("");
1007 println!(" Note: Connection dump requires gRPC integration:");
1008 println!(" - Connection ID");
1009 println!(" - Remote address");
1010 println!(" - Connected at timestamp");
1011 println!(" - Last activity");
1012 println!(" - Active requests");
1013 println!(" - Bytes transferred");
1014
1015 Err("Debug 'dump-connections' command not yet implemented".into())
1016 },
1017
1018 DebugCommand::HealthCheck { verbose, service } => {
1019 if let Some(ref svc) = service {
1021 if svc.is_empty() || svc.len() > 64 {
1022 return Err("Service name must be 1-64 characters".into());
1023 }
1024 }
1025
1026 println!("🔧 Debug: Health Check");
1027 println!("");
1028
1029 match attempt_daemon_connection().await {
1030 Ok(_) => {
1031 println!(" Overall: ⚠️ Basic check passed");
1032 println!("");
1033
1034 if let Some(svc) = service {
1035 println!(" Service: {}", svc);
1036 println!(" Status: Not checked (detailed checks not implemented)");
1037 } else {
1038 println!(" Services:");
1039 println!(" gRPC Server: ✅ Responding");
1040 println!(" Authentication: ⏸️ Not checked");
1041 println!(" Updates: ⏸️ Not checked");
1042 println!(" Download Manager: ⏸️ Not checked");
1043 println!(" File Indexer: ⏸️ Not checked");
1044 }
1045
1046 if verbose {
1047 println!("");
1048 println!(" 🔍 Verbose Information:");
1049 println!(" Last health check: Not tracked");
1050 println!(" Health check interval: 30s (default)");
1051 println!(" Failure threshold: 3 (configurable)");
1052 println!(" Recovery threshold: 2 (configurable)");
1053 }
1054 },
1055 Err(e) => {
1056 println!(" Overall: ❌ Daemon unreachable");
1057 println!(" Error: {}", e);
1058 return Err(format!("Health check failed: {}", e).into());
1059 },
1060 }
1061
1062 Err("Debug 'health-check' not detailed yet".into())
1063 },
1064
1065 DebugCommand::Diagnostics { level } => {
1066 println!("🔧 Debug: Diagnostics");
1067 println!("");
1068 println!(" Level: {:?}", level);
1069 println!("");
1070
1071 println!(" System Information:");
1073 println!(" OS: {}", std::env::consts::OS);
1074 println!(" Arch: {}", std::env::consts::ARCH);
1075 println!(" Air Version: {}", VERSION);
1076 println!("");
1077
1078 match attempt_daemon_connection().await {
1079 Ok(_) => {
1080 println!(" Daemon: ✅ Running");
1081 },
1082 Err(e) => {
1083 println!(" Daemon: ❌ Running");
1084 println!(" Error: {}", e);
1085 },
1086 }
1087
1088 println!("");
1089 println!(" Note: Advanced diagnostics require additional infrastructure:");
1090 println!(" - Thread dump");
1091 println!(" - Memory profiling");
1092 println!(" - Lock contention analysis");
1093 println!(" - Resource leak detection");
1094 println!(" - Performance bottlenecks");
1095
1096 Ok(())
1097 },
1098 }
1099 },
1100 }
1101}
1102
1103fn validate_command(cmd:&Command) -> Result<(), String> {
1110 match cmd {
1111 Command::Help { command } => {
1112 if let Some(cmd) = command {
1113 if cmd.len() > 128 {
1114 return Err("Command name too long (max: 128)".to_string());
1115 }
1116 }
1117 },
1118 _ => {},
1119 }
1120 Ok(())
1121}
1122
1123async fn attempt_daemon_connection_with_retry(max_retries:usize, initial_delay_ms:u64) -> Result<(), String> {
1146 use tokio::{
1147 net::TcpStream,
1148 time::{Duration, timeout},
1149 };
1150
1151 let addr = DefaultBindAddress;
1152 let mut attempt = 0;
1153 let mut delay_ms = initial_delay_ms;
1154
1155 loop {
1156 attempt += 1;
1157 dev_log!("lifecycle", "[DaemonConnection] Attempt {} of {}", attempt, max_retries + 1);
1158
1159 let connection_result = timeout(Duration::from_secs(5), async { TcpStream::connect(addr).await }).await;
1161
1162 match connection_result {
1163 Ok(Ok(_stream)) => {
1164 dev_log!("lifecycle", "[DaemonConnection] Connected successfully on attempt {}", attempt);
1165 return Ok(());
1166 },
1167 Ok(Err(e)) => {
1168 dev_log!("lifecycle", "[DaemonConnection] Attempt {} failed: {}", attempt, e);
1169 },
1170 Err(_) => {
1171 dev_log!("lifecycle", "[DaemonConnection] Attempt {} timed out", attempt);
1172 },
1173 }
1174
1175 if attempt > max_retries {
1177 break;
1178 }
1179
1180 dev_log!("lifecycle", "[DaemonConnection] Waiting {}ms before retry...", delay_ms);
1182 tokio::time::sleep(Duration::from_millis(delay_ms)).await;
1183 delay_ms = delay_ms * 2; }
1185
1186 Err(format!("Failed to connect after {} attempts", max_retries + 1))
1187}
1188
1189async fn attempt_daemon_connection() -> Result<(), String> {
1194 attempt_daemon_connection_with_retry(3, 500).await
1196}
1197
1198#[allow(dead_code)]
1218fn HandleMetricsRequest() -> String {
1219 let _timeout_duration = std::time::Duration::from_millis(100);
1221
1222 let metrics_collector = Metrics::GetMetrics();
1223
1224 let export_result = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| metrics_collector.ExportMetrics()));
1226
1227 match export_result {
1228 Ok(Ok(metrics_text)) => {
1229 if metrics_text.len() > 10_000_000 {
1231 dev_log!(
1232 "metrics",
1233 "error: [Metrics] Exported metrics unreasonably large (size: {} bytes)",
1234 metrics_text.len()
1235 );
1236 format!("# ERROR: Metrics export too large (max: 10MB)\n")
1237 } else {
1238 metrics_text
1239 }
1240 },
1241 Ok(Err(e)) => {
1242 dev_log!("metrics", "error: [Metrics] Failed to export metrics: {}", e);
1243 format!("# ERROR: Failed to export metrics: {}\n", e)
1244 },
1245 Err(_) => {
1246 dev_log!("metrics", "error: [Metrics] Metrics export panicked");
1247 format!("# ERROR: Metrics export failed due to internal error\n")
1248 },
1249 }
1250}
1251
1252async fn Main() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
1293 InitializeLogging();
1297
1298 dev_log!("lifecycle", "[Boot] ===========================================");
1299 dev_log!("lifecycle", "[Boot] Starting Air Daemon");
1300 dev_log!("lifecycle", "[Boot] ===========================================");
1301 dev_log!(
1302 "lifecycle",
1303 "[Boot] Version: {} ({})",
1304 env!("CARGO_PKG_VERSION"),
1305 env!("CARGO_PKG_NAME")
1306 );
1307 let build_timestamp = env::var("BUILD_TIMESTAMP").unwrap_or_else(|_| "unknown".to_string());
1308 dev_log!("lifecycle", "[Boot] Build: {}", build_timestamp);
1309 dev_log!(
1310 "lifecycle",
1311 "[Boot] Target: {}-{}",
1312 std::env::consts::OS,
1313 std::env::consts::ARCH
1314 );
1315
1316 dev_log!("lifecycle", "[Boot] Validating environment...");
1320
1321 if let Err(e) = validate_environment().await {
1322 dev_log!("lifecycle", "error: [Boot] Environment validation failed: {}", e);
1323 return Err(format!("Environment validation failed: {}", e).into());
1324 }
1325
1326 dev_log!("lifecycle", "[Boot] Environment validation passed");
1327
1328 Trace!("[Boot] [Observability] Initializing observability systems...");
1332
1333 if let Err(e) = Metrics::InitializeMetrics() {
1335 dev_log!("lifecycle", "error: [Boot] Failed to initialize metrics: {}", e);
1336 } else {
1338 dev_log!("lifecycle", "[Boot] [Observability] Metrics system initialized");
1339 }
1340
1341 if let Err(e) = Tracing::initialize_tracing(None) {
1343 dev_log!("lifecycle", "error: [Boot] Failed to initialize tracing: {}", e);
1344 } else {
1346 dev_log!("lifecycle", "[Boot] [Observability] Tracing system initialized");
1347 }
1348
1349 dev_log!("lifecycle", "[Boot] [Observability] Observability systems initialized");
1350
1351 Trace!("[Boot] [Args] Parsing command line arguments...");
1355
1356 let (config_path, bind_address, cli_command) = ParseArguments();
1357
1358 if let Some(cmd) = cli_command {
1360 dev_log!("lifecycle", "[Boot] CLI command detected, executing...");
1361 let result = HandleCommand(cmd).await;
1362
1363 match &result {
1364 Ok(_) => {
1365 dev_log!("lifecycle", "[Boot] CLI command completed successfully");
1366 std::process::exit(0);
1367 },
1368 Err(e) => {
1369 dev_log!("lifecycle", "error: [Boot] CLI command failed: {}", e);
1370 std::process::exit(1);
1371 },
1372 }
1373 }
1374
1375 Trace!("[Boot] [Configuration] Loading configuration...");
1379
1380 let config_manager = match ConfigurationManager::New(config_path) {
1381 Ok(cm) => cm,
1382 Err(e) => {
1383 dev_log!("lifecycle", "error: [Boot] Failed to create configuration manager: {}", e);
1384 return Err(format!("Configuration manager initialization failed: {}", e).into());
1385 },
1386 };
1387
1388 let configuration:std::sync::Arc<AirLibrary::Configuration::AirConfiguration> =
1390 match tokio::time::timeout(Duration::from_secs(10), config_manager.LoadConfiguration()).await {
1391 Ok(Ok(config)) => {
1392 dev_log!("lifecycle", "[Boot] [Configuration] Configuration loaded successfully");
1393 std::sync::Arc::new(config)
1394 },
1395 Ok(Err(e)) => {
1396 dev_log!("lifecycle", "error: [Boot] Failed to load configuration: {}", e);
1397 return Err(format!("Configuration load failed: {}", e).into());
1398 },
1399 Err(_) => {
1400 dev_log!("lifecycle", "error: [Boot] Configuration load timed out");
1401 return Err("Configuration load timed out".into());
1402 },
1403 };
1404
1405 validate_configuration(&configuration)?;
1407
1408 Trace!("[Boot] [Daemon] Initializing daemon lifecycle management...");
1412
1413 let daemon_manager = match DaemonManager::New(None) {
1414 Ok(dm) => dm,
1415 Err(e) => {
1416 dev_log!("lifecycle", "error: [Boot] Failed to create daemon manager: {}", e);
1417 return Err(format!("Daemon manager initialization failed: {}", e).into());
1418 },
1419 };
1420
1421 match tokio::time::timeout(Duration::from_secs(5), daemon_manager.AcquireLock()).await {
1423 Ok(Ok(_)) => {
1424 dev_log!("lifecycle", "[Boot] [Daemon] Daemon lock acquired successfully");
1425 },
1426 Ok(Err(e)) => {
1427 dev_log!("lifecycle", "error: [Boot] Failed to acquire daemon lock: {}", e);
1428 dev_log!("lifecycle", "error: [Boot] Another instance may already be running");
1429 return Err(format!("Daemon lock acquisition failed: {}", e).into());
1430 },
1431 Err(_) => {
1432 dev_log!("lifecycle", "error: [Boot] Daemon lock acquisition timed out");
1433 return Err("Daemon lock acquisition timed out".into());
1434 },
1435 }
1436
1437 Trace!("[Boot] [Health] Initializing health check system...");
1441
1442 let health_manager:std::sync::Arc<HealthCheckManager> = Arc::new(HealthCheckManager::new(None));
1443
1444 dev_log!("lifecycle", "[Boot] [Health] Health check system initialized");
1445
1446 Trace!("[Boot] [State] Initializing application state...");
1450
1451 let AppState:std::sync::Arc<ApplicationState> =
1452 match tokio::time::timeout(Duration::from_secs(10), ApplicationState::New(configuration.clone())).await {
1453 Ok(Ok(state)) => {
1454 dev_log!("lifecycle", "[Boot] [State] Application state initialized");
1455 Arc::new(state)
1456 },
1457 Ok(Err(e)) => {
1458 dev_log!("lifecycle", "error: [Boot] Failed to initialize application state: {}", e);
1459 let _ = daemon_manager.ReleaseLock().await;
1461 return Err(format!("Application state initialization failed: {}", e).into());
1462 },
1463 Err(_) => {
1464 dev_log!("lifecycle", "error: [Boot] Application state initialization timed out");
1465 let _ = daemon_manager.ReleaseLock().await;
1466 return Err("Application state initialization timed out".into());
1467 },
1468 };
1469
1470 Trace!("[Boot] [Services] Initializing core services...");
1474
1475 let auth_service:std::sync::Arc<AuthenticationService> =
1477 match tokio::time::timeout(Duration::from_secs(10), AuthenticationService::new(AppState.clone())).await {
1478 Ok(Ok(svc)) => Arc::new(svc),
1479 Ok(Err(e)) => {
1480 dev_log!("lifecycle", "error: [Boot] Failed to initialize authentication service: {}", e);
1481 return Err(format!("Authentication service initialization failed: {}", e).into());
1482 },
1483 Err(_) => {
1484 dev_log!("lifecycle", "error: [Boot] Authentication service initialization timed out");
1485 return Err("Authentication service initialization timed out".into());
1486 },
1487 };
1488
1489 let update_manager:std::sync::Arc<UpdateManager> =
1490 match tokio::time::timeout(Duration::from_secs(10), UpdateManager::new(AppState.clone())).await {
1491 Ok(Ok(svc)) => Arc::new(svc),
1492 Ok(Err(e)) => {
1493 dev_log!("lifecycle", "error: [Boot] Failed to initialize update manager: {}", e);
1494 return Err(format!("Update manager initialization failed: {}", e).into());
1495 },
1496 Err(_) => {
1497 dev_log!("lifecycle", "error: [Boot] Update manager initialization timed out");
1498 return Err("Update manager initialization timed out".into());
1499 },
1500 };
1501
1502 let download_manager:std::sync::Arc<DownloadManager> =
1503 match tokio::time::timeout(Duration::from_secs(10), DownloadManager::new(AppState.clone())).await {
1504 Ok(Ok(svc)) => Arc::new(svc),
1505 Ok(Err(e)) => {
1506 dev_log!("lifecycle", "error: [Boot] Failed to initialize download manager: {}", e);
1507 return Err(format!("Download manager initialization failed: {}", e).into());
1508 },
1509 Err(_) => {
1510 dev_log!("lifecycle", "error: [Boot] Download manager initialization timed out");
1511 return Err("Download manager initialization timed out".into());
1512 },
1513 };
1514
1515 let file_indexer:std::sync::Arc<FileIndexer> =
1516 match tokio::time::timeout(Duration::from_secs(10), FileIndexer::new(AppState.clone())).await {
1517 Ok(Ok(svc)) => Arc::new(svc),
1518 Ok(Err(e)) => {
1519 dev_log!("lifecycle", "error: [Boot] Failed to initialize file indexer: {}", e);
1520 return Err(format!("File indexer initialization failed: {}", e).into());
1521 },
1522 Err(_) => {
1523 dev_log!("lifecycle", "error: [Boot] File indexer initialization timed out");
1524 return Err("File indexer initialization timed out".into());
1525 },
1526 };
1527
1528 dev_log!("lifecycle", "[Boot] [Services] All core services initialized successfully");
1529
1530 Trace!("[Boot] [Health] Registering services for health monitoring...");
1534
1535 let service_registrations = vec![
1537 ("authentication", HealthCheckLevel::Functional),
1538 ("updates", HealthCheckLevel::Functional),
1539 ("downloader", HealthCheckLevel::Functional),
1540 ("indexing", HealthCheckLevel::Functional),
1541 ("grpc", HealthCheckLevel::Responsive),
1542 ("connections", HealthCheckLevel::Alive),
1543 ];
1544
1545 for (service_name, level) in service_registrations {
1546 match tokio::time::timeout(
1547 Duration::from_secs(5),
1548 health_manager.RegisterService(service_name.to_string(), level),
1549 )
1550 .await
1551 {
1552 Ok(result) => {
1553 match result {
1554 Ok(_) => {
1555 dev_log!("lifecycle", "[Boot] [Health] Registered service: {}", service_name);
1556 },
1557 Err(e) => {
1558 dev_log!("lifecycle", "warn: [Boot] Failed to register service {}: {}", service_name, e);
1559 },
1562 }
1563 },
1564 Err(_) => {
1565 dev_log!("lifecycle", "warn: [Boot] Service registration timed out: {}", service_name);
1566 },
1567 }
1568 }
1569
1570 dev_log!("lifecycle", "[Boot] [Health] Service health monitoring configured");
1571
1572 Trace!("[Boot] [Vine] Initializing gRPC server...");
1576
1577 let bind_addr:SocketAddr = match bind_address {
1579 Some(addr) => {
1580 match addr.parse() {
1581 Ok(parsed) => {
1582 dev_log!("lifecycle", "[Boot] [Vine] Using custom bind address: {}", parsed);
1583 parsed
1584 },
1585 Err(e) => {
1586 dev_log!("lifecycle", "error: [Boot] Invalid bind address '{}': {}", addr, e);
1587 return Err(format!("Invalid bind address: {}", e).into());
1588 },
1589 }
1590 },
1591 None => {
1592 match DefaultBindAddress.parse() {
1593 Ok(parsed) => parsed,
1594 Err(e) => {
1595 dev_log!(
1596 "lifecycle",
1597 "error: [Boot] Invalid default bind address '{}': {}",
1598 DefaultBindAddress,
1599 e
1600 );
1601 return Err(format!("Invalid default bind address: {}", e).into());
1602 },
1603 }
1604 },
1605 };
1606
1607 dev_log!("lifecycle", "[Boot] [Vine] Configuring gRPC server on {}", bind_addr);
1608
1609 let vine_service = AirVinegRPCService::new(
1611 AppState.clone(),
1612 auth_service.clone(),
1613 update_manager.clone(),
1614 download_manager.clone(),
1615 file_indexer.clone(),
1616 );
1617
1618 let (shutdown_tx, shutdown_rx) = tokio::sync::oneshot::channel::<()>();
1620
1621 let server_handle:tokio::task::JoinHandle<Result<(), Box<dyn std::error::Error + Send + Sync>>> =
1623 tokio::spawn(async move {
1624 dev_log!("lifecycle", "[Vine] Starting gRPC server on {}", bind_addr);
1625
1626 let svc = AirServiceServer::new(vine_service);
1627
1628 let server = tonic::transport::Server::builder()
1629 .add_service(svc)
1630 .serve_with_shutdown(bind_addr, async {
1631 let _ = shutdown_rx.await;
1633 dev_log!("lifecycle", "[Vine] Shutdown signal received, stopping server...");
1634 });
1635
1636 dev_log!("lifecycle", "[Vine] gRPC server listening on {}", bind_addr);
1637
1638 match server.await {
1639 Ok(_) => {
1640 dev_log!("lifecycle", "[Vine] gRPC server stopped cleanly");
1641 Ok(())
1642 },
1643 Err(e) => {
1644 dev_log!("grpc", "error: [Vine] gRPC server error: {}", e);
1645 Err(e.into())
1646 },
1647 }
1648 });
1649
1650 tokio::time::sleep(Duration::from_millis(100)).await;
1652
1653 if server_handle.is_finished() {
1655 dev_log!("lifecycle", "error: [Boot] gRPC server failed to start");
1656 let _ = daemon_manager.ReleaseLock().await;
1657 return Err("gRPC server failed to start".into());
1658 }
1659
1660 Trace!("[Boot] [Monitoring] Starting background monitoring tasks...");
1664
1665 let connection_monitor_handle:tokio::task::JoinHandle<()> = tokio::spawn({
1667 let AppState = AppState.clone();
1668 let health_manager = health_manager.clone();
1669 async move {
1670 let mut interval = interval(Duration::from_secs(60)); loop {
1672 interval.tick().await;
1673
1674 if let Err(e) = AppState.UpdateResourceUsage().await {
1676 dev_log!("lifecycle", "warn: [ConnectionMonitor] Failed to update resource usage: {}", e);
1677 }
1678
1679 let resources = AppState.GetResourceUsage().await;
1681
1682 let metrics_collector = Metrics::GetMetrics();
1684 metrics_collector.UpdateResourceMetrics(
1685 (resources.MemoryUsageMb * 1024.0 * 1024.0) as u64, resources.CPUUsagePercent,
1687 AppState.GetActiveConnectionCount().await as u64,
1688 0, );
1690
1691 if let Err(e) = AppState.CleanupStaleConnections(300).await {
1693 dev_log!(
1694 "lifecycle",
1695 "warn: [ConnectionMonitor] Failed to cleanup stale connections: {}",
1696 e
1697 );
1698 }
1699
1700 match health_manager.CheckService("connections").await {
1702 Ok(_) => {},
1703 Err(e) => {
1704 dev_log!("lifecycle", "warn: [ConnectionMonitor] Health check failed: {}", e);
1705
1706 let metrics_collector = Metrics::GetMetrics();
1708 metrics_collector.RecordRequestFailure("health_check_failed", 0.0);
1709 },
1710 }
1711
1712 dev_log!(
1713 "lifecycle",
1714 "[ConnectionMonitor] Active connections: {}",
1715 AppState.GetActiveConnectionCount().await
1716 );
1717 }
1718 }
1719 });
1720
1721 if let Err(e) = AppState.RegisterBackgroundTask(connection_monitor_handle).await {
1723 dev_log!("lifecycle", "warn: [Boot] Failed to register connection monitor: {}", e);
1724 }
1726
1727 let health_monitor_handle:tokio::task::JoinHandle<()> = tokio::spawn({
1729 let health_manager = health_manager.clone();
1730 async move {
1731 let mut interval = interval(Duration::from_secs(30)); loop {
1733 interval.tick().await;
1734
1735 let services = ["authentication", "updates", "downloader", "indexing", "grpc"];
1737 for service in services.iter() {
1738 if let Err(e) = health_manager.CheckService(service).await {
1739 dev_log!("lifecycle", "warn: [HealthMonitor] Health check failed for {}: {}", service, e);
1740 }
1741 }
1742
1743 let overall_health = health_manager.GetOverallHealth().await;
1745 dev_log!("lifecycle", "[HealthMonitor] Overall health: {:?}", overall_health);
1746 }
1747 }
1748 });
1749
1750 if let Err(e) = AppState.RegisterBackgroundTask(health_monitor_handle).await {
1752 dev_log!("lifecycle", "warn: [Boot] Failed to register health monitor: {}", e);
1753 }
1755
1756 Trace!("[Boot] [Startup] Starting background services...");
1760
1761 let _ = auth_service.StartBackgroundTasks().await?;
1763 let _ = update_manager.StartBackgroundTasks().await?;
1764 let _ = download_manager.StartBackgroundTasks().await?;
1765 let _indexing_handle = None::<tokio::task::JoinHandle<()>>;
1767
1768 dev_log!("lifecycle", "[Boot] [Startup] All services started successfully");
1769
1770 dev_log!("lifecycle", "===========================================");
1774 dev_log!("lifecycle", "[Runtime] Air Daemon is now running");
1775 dev_log!("lifecycle", "[Runtime] Listening on {} for Mountain connections", bind_addr);
1776 dev_log!("lifecycle", "[Runtime] Protocol Version: {}", ProtocolVersion);
1777 dev_log!("lifecycle", "[Runtime] Cocoon Port: 50052");
1778 dev_log!("lifecycle", "===========================================");
1779 dev_log!("lifecycle", "");
1780 dev_log!("lifecycle", "Running. Press Ctrl+C to stop.");
1781 dev_log!("lifecycle", "");
1782
1783 WaitForShutdownSignal().await;
1785
1786 dev_log!("lifecycle", "[Shutdown] Signaling gRPC server to stop...");
1788 let _ = shutdown_tx.send(());
1789
1790 match tokio::time::timeout(Duration::from_secs(30), server_handle).await {
1792 Ok(Ok(Ok(_))) => {
1793 dev_log!("lifecycle", "[Shutdown] gRPC server stopped normally");
1794 },
1795 Ok(Ok(Err(e))) => {
1796 dev_log!("lifecycle", "warn: [Shutdown] gRPC server stopped with error: {}", e);
1797 },
1798 Ok(Err(e)) => {
1799 dev_log!("lifecycle", "warn: [Shutdown] gRPC server task panicked: {:?}", e);
1800 },
1801 Err(_) => {
1802 dev_log!("lifecycle", "warn: [Shutdown] gRPC server shutdown timed out");
1803 },
1804 }
1805
1806 dev_log!("lifecycle", "===========================================");
1810 dev_log!("lifecycle", "[Shutdown] Initiating graceful shutdown...");
1811 dev_log!("lifecycle", "===========================================");
1812
1813 dev_log!("lifecycle", "[Shutdown] Stopping background tasks...");
1815 if let Err(_) =
1816 tokio::time::timeout(Duration::from_secs(10), async { AppState.StopAllBackgroundTasks().await }).await
1817 {
1818 dev_log!("lifecycle", "warn: [Shutdown] Background tasks stop timed out or failed");
1819 }
1820
1821 dev_log!("lifecycle", "[Shutdown] Stopping background services...");
1823 auth_service.StopBackgroundTasks().await;
1824 update_manager.StopBackgroundTasks().await;
1825 download_manager.StopBackgroundTasks().await;
1826
1827 dev_log!("lifecycle", "[Shutdown] Collecting final statistics...");
1829
1830 let metrics = AppState.GetMetrics().await;
1831 let resources = AppState.GetResourceUsage().await;
1832 let health_stats:HealthStatistics = health_manager.GetHealthStatistics().await;
1833
1834 let metrics_data = Metrics::GetMetrics().GetMetricsData();
1836
1837 dev_log!("lifecycle", "===========================================");
1838 dev_log!("lifecycle", "[Shutdown] Final Statistics");
1839 dev_log!("lifecycle", "===========================================");
1840 dev_log!("lifecycle", "[Shutdown] Requests:");
1841 dev_log!("lifecycle", " - Successful: {}", metrics.SuccessfulRequest);
1842 dev_log!("lifecycle", " - Failed: {}", metrics.FailedRequest);
1843 dev_log!("lifecycle", "[Shutdown] Metrics:");
1844 dev_log!("lifecycle", " - Success rate: {:.2}%", metrics_data.SuccessRate());
1845 dev_log!("lifecycle", " - Error rate: {:.2}%", metrics_data.ErrorRate());
1846 dev_log!("lifecycle", "[Shutdown] Resources:");
1847 dev_log!("lifecycle", " - Memory: {:.2} MB", resources.MemoryUsageMb);
1848 dev_log!("lifecycle", " - CPU: {:.2}%", resources.CPUUsagePercent);
1849 dev_log!("lifecycle", "[Shutdown] Health:");
1850 dev_log!("lifecycle", " - Overall: {:.2}%", health_stats.OverallHealthPercentage());
1851 dev_log!(
1852 "lifecycle",
1853 " - Healthy services: {}/{}",
1854 health_stats.HealthyServices,
1855 health_stats.TotalServices
1856 );
1857 dev_log!("lifecycle", "===========================================");
1858
1859 dev_log!("lifecycle", "[Shutdown] Releasing daemon lock...");
1861 if let Err(e) = daemon_manager.ReleaseLock().await {
1862 dev_log!("lifecycle", "warn: [Shutdown] Failed to release daemon lock: {}", e);
1863 }
1864
1865 dev_log!("lifecycle", "[Shutdown] All services stopped");
1866 dev_log!("lifecycle", "[Shutdown] Air Daemon has shut down gracefully");
1867 dev_log!("lifecycle", "===========================================");
1868
1869 Ok(())
1870}
1871
1872async fn validate_environment() -> Result<(), String> {
1881 dev_log!(
1883 "lifecycle",
1884 "[Environment] OS: {}, Arch: {}",
1885 std::env::consts::OS,
1886 std::env::consts::ARCH
1887 );
1888
1889 if let Ok(home) = std::env::var("HOME") {
1891 if home.is_empty() {
1892 return Err("HOME environment variable is not set".to_string());
1893 }
1894 }
1895
1896 let lock_path = "/tmp/Air-test-lock.tmp";
1898 if std::fs::write(lock_path, b"test").is_err() {
1899 return Err("Cannot write to /tmp directory".to_string());
1900 }
1901 let _ = std::fs::remove_file(lock_path);
1902
1903 Ok(())
1904}
1905
1906fn validate_configuration(_config:&AirConfiguration) -> Result<(), String> {
1915 dev_log!("lifecycle", "[Config] Configuration passed basic validation");
1917 Ok(())
1918}
1919
1920#[tokio::main]
1921async fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync>> { Main().await }