1#![allow(
2 non_snake_case,
3 non_camel_case_types,
4 non_upper_case_globals,
5 dead_code,
6 unused_imports,
7 unused_variables,
8 unused_assignments
9)]
10
11use std::{env, net::SocketAddr, sync::Arc, time::Duration};
176
177use AirLibrary::dev_log;
178use tokio::{signal, time::interval};
179use AirLibrary::{
181 ApplicationState::ApplicationState,
182 Authentication::AuthenticationService,
183 CLI::{CliParser, Command, ConfigCommand, DebugCommand, OutputFormatter},
184 Configuration::{AirConfiguration, ConfigurationManager},
185 Daemon::DaemonManager,
186 DefaultBindAddress,
187 DefaultConfigFile,
188 Downloader::DownloadManager,
189 HealthCheck::{HealthCheckLevel, HealthCheckManager, HealthStatistics},
190 Indexing::FileIndexer,
191 Logging,
192 Metrics,
193 ProtocolVersion,
194 Tracing,
195 Updates::UpdateManager,
196 VERSION,
197 Vine::Generated::air::air_service_server::AirServiceServer,
198 Vine::Server::AirVinegRPCService::AirVinegRPCService,
199};
200
201macro_rules! Trace {
207
208 ($($arg:tt)*) => {{
209
210 dev_log!("lifecycle", $($arg)*);
211 }};
212}
213
214async fn WaitForShutdownSignal() {
226 dev_log!("lifecycle", "[Shutdown] Waiting for termination signal...");
227
228 let ctrl_c = async {
229 match signal::ctrl_c().await {
230 Ok(()) => dev_log!("lifecycle", "[Shutdown] Received Ctrl+C signal"),
231
232 Err(e) => dev_log!("lifecycle", "error: [Shutdown] Failed to install Ctrl+C handler: {}", e),
233 }
234 };
235
236 #[cfg(unix)]
237 let terminate = async {
238 match signal::unix::signal(signal::unix::SignalKind::terminate()) {
239 Ok(mut sig) => {
240 sig.recv().await;
241
242 dev_log!("lifecycle", "[Shutdown] Received SIGTERM signal");
243 },
244
245 Err(e) => dev_log!("lifecycle", "error: [Shutdown] Failed to install signal handler: {}", e),
246 }
247 };
248
249 #[cfg(not(unix))]
250 let terminate = std::future::pending::<()>();
251
252 tokio::select! {
253
254 _ = ctrl_c => {},
255
256 _ = terminate => {},
257 }
258
259 dev_log!("lifecycle", "[Shutdown] Signal received, initiating graceful shutdown");
260}
261
262fn InitializeLogging() {
279 let json_output = match std::env::var("AIR_LOG_JSON") {
281 Ok(val) if !val.is_empty() => {
282 let normalized = val.to_lowercase();
283
284 if normalized != "true" && normalized != "false" {
285 eprintln!(
286 "Warning: Invalid AIR_LOG_JSON value '{}', expected 'true' or 'false'. Using default: false",
287 val
288 );
289
290 false
291 } else {
292 normalized == "true"
293 }
294 },
295
296 Ok(_) => false,
297
298 Err(_) => false,
299 };
300
301 let log_file_path = std::env::var("AIR_LOG_FILE").ok().and_then(|path| {
303 if path.is_empty() {
304 None
305 } else {
306 if let Some(parent) = std::path::PathBuf::from(&path).parent() {
308 if parent.as_os_str().is_empty() {
309 Some(path)
311 } else if parent.exists() {
312 Some(path)
313 } else {
314 eprintln!(
315 "Warning: Log file directory does not exist: {}. Logging to stdout only.",
316 parent.display()
317 );
318
319 None
320 }
321 } else {
322 Some(path)
323 }
324 }
325 });
326
327 let log_result = Logging::InitializeLogger(json_output, log_file_path.clone());
329
330 match log_result {
331 Ok(_) => {
332 let log_info = match &log_file_path {
333 Some(path) => format!("file: {}", path),
334
335 None => "stdout/stderr".to_string(),
336 };
337
338 dev_log!(
339 "lifecycle",
340 "[Boot] Logging initialized - JSON: {}, Output: {}",
341 json_output,
342 log_info
343 );
344 },
345
346 Err(e) => {
347 eprintln!("[ERROR] Failed to initialize structured logging: {}", e);
349
350 eprintln!("[ERROR] Logging will fall back to stderr-only output");
351 },
352 }
353}
354
355fn ParseArguments() -> (Option<String>, Option<String>, Option<Command>) {
374 let args:Vec<String> = std::env::args().collect();
376
377 if args.len() > 1024 {
379 eprintln!("[ERROR] Too many command line arguments (max: 1024)");
380
381 std::process::exit(1);
382 }
383
384 for (i, arg) in args.iter().enumerate() {
386 if arg.len() > 4096 {
387 eprintln!("[ERROR] Argument at position {} is too long (max: 4096 characters)", i);
388
389 std::process::exit(1);
390 }
391 }
392
393 if args.len() > 1 {
395 match args[1].as_str() {
396 "status" | "restart" | "config" | "metrics" | "logs" | "debug" | "help" | "version" | "-h" | "--help"
397 | "-v" | "--version" => {
398 match CliParser::parse(args.clone()) {
400 Ok(cmd) => {
401 dev_log!("lifecycle", "[Boot] CLI command parsed: {:?}", cmd);
402
403 return (None, None, Some(cmd));
404 },
405
406 Err(e) => {
407 eprintln!("[ERROR] Error parsing CLI command: {}", e);
408
409 eprintln!("[ERROR] Run 'Air help' for usage information");
410
411 std::process::exit(1);
412 },
413 }
414 },
415
416 _ => {},
417 }
418 }
419
420 let mut config_path:Option<String> = None;
422
423 let mut bind_address:Option<String> = None;
424
425 let mut i = 0;
426
427 while i < args.len() {
428 match args[i].as_str() {
429 "--config" | "-c" => {
430 if i + 1 < args.len() {
431 let path = &args[i + 1];
432
433 if path.contains("..") || path.contains('\0') {
435 eprintln!("[ERROR] Invalid config path: contains '..' or null character");
436
437 std::process::exit(1);
438 }
439
440 config_path = Some(path.clone());
441
442 i += 1;
443 } else {
444 eprintln!("[ERROR] --config flag requires a path argument");
445
446 std::process::exit(1);
447 }
448 },
449
450 "--bind" | "-b" => {
451 if i + 1 < args.len() {
452 let addr = &args[i + 1];
453
454 if addr.is_empty() || addr.len() > 256 {
456 eprintln!("[ERROR] Invalid bind address: must be 1-256 characters");
457
458 std::process::exit(1);
459 }
460
461 if addr.contains('\0') {
463 eprintln!("[ERROR] Invalid bind address: contains null character");
464
465 std::process::exit(1);
466 }
467
468 bind_address = Some(addr.clone());
469
470 i += 1;
471 } else {
472 eprintln!("[ERROR] --bind flag requires an address argument");
473
474 std::process::exit(1);
475 }
476 },
477
478 _ => {
479
480 },
483 }
484
485 i += 1;
486 }
487
488 dev_log!(
489 "lifecycle",
490 "[Boot] Daemon mode - config: {:?}, bind: {:?}",
491 config_path,
492 bind_address
493 );
494
495 (config_path, bind_address, None)
496}
497
498async fn HandleCommand(cmd:Command) -> Result<(), Box<dyn std::error::Error>> {
521 let validation_result = validate_command(&cmd);
523
524 if let Err(e) = validation_result {
525 eprintln!("[ERROR] Command validation failed: {}", e);
526
527 return Err(e.into());
528 }
529
530 match cmd {
531 Command::Help { command } => {
532 if let Some(ref cmd) = command {
534 if cmd.len() > 128 {
535 eprintln!("[ERROR] Command name too long (max: 128 characters)");
536
537 return Err("Command name too long".into());
538 }
539 }
540
541 println!("{}", OutputFormatter::format_help(command.as_deref(), VERSION));
542
543 Ok(())
544 },
545
546 Command::Version => {
547 println!("Air {} ({})", VERSION, env!("CARGO_PKG_NAME"));
548
549 println!("Protocol: Version {} (gRPC)", ProtocolVersion);
550
551 println!("Port: {} (Air), {} (Cocoon)", DefaultBindAddress, "[::1]:50052");
552
553 println!("Build: {} {}", env!("CARGO_PKG_VERSION"), env!("CARGO_PKG_NAME"));
554
555 Ok(())
556 },
557
558 Command::Status { service, verbose, json } => {
559 if let Some(ref svc) = service {
561 if svc.is_empty() || svc.len() > 64 {
562 return Err("Service name must be 1-64 characters".into());
563 }
564 }
565
566 if let Some(svc) = service {
571 println!("📊 Status for service: {}", svc);
572
573 match attempt_daemon_connection().await {
575 Ok(_) => {
576 println!(" Status: ⚠️ Running (basic check)");
577
578 println!(" Note: Connect to gRPC endpoint for detailed status");
579 },
580
581 Err(e) => {
582 println!(" Status: ❌ Cannot connect to daemon");
583
584 println!(" Error: {}", e);
585
586 println!("");
587
588 println!(" To start the daemon, run: Air --daemon");
589
590 return Err(format!("Cannot connect to daemon: {}", e).into());
591 },
592 }
593 } else {
594 println!("📊 Air Daemon Status");
595
596 println!("");
597
598 match attempt_daemon_connection().await {
600 Ok(_) => {
601 println!(" Overall: ⚠️ Running (basic check)");
602
603 println!(" Note: Connect to gRPC endpoint for detailed status");
604
605 println!("");
606
607 println!(" Services:");
608
609 println!(" gRPC Server: ✅ Listening");
610
611 println!(" Authentication: ⚠️ Status check not implemented");
612
613 println!(" Updates: ⚠️ Status check not implemented");
614
615 println!(" Download Manager: ⚠️ Status check not implemented");
616
617 println!(" File Indexer: ⚠️ Status check not implemented");
618 },
619
620 Err(e) => {
621 println!(" Overall: ❌ Daemon not running");
622
623 println!(" Error: {}", e);
624
625 println!("");
626
627 println!(" To start the daemon, run: Air --daemon");
628
629 return Err("Daemon not running".into());
630 },
631 }
632 }
633
634 if verbose {
635 println!("");
636
637 println!("🔍 Verbose Information:");
638
639 println!(" Debug mode: Disabled by default");
640
641 println!(" Log level: info");
642
643 println!(" Config file: {}", DefaultConfigFile);
644
645 println!("");
646
647 println!(" Detailed service status can be obtained via gRPC:");
648
649 println!(" - Service uptime");
650
651 println!(" - Request/response statistics");
652
653 println!(" - Error rates and recent errors");
654
655 println!(" - Resource usage");
656
657 println!(" - Active connections");
658 }
659
660 if json {
661 println!("");
662
663 println!("📋 JSON Output:");
664
665 println!(
666 "{}",
667 serde_json::json!({
668 "overall": "running",
669 "services": {
670 "grpc": "listening",
671 "status": "not_implemented"
672 },
673 "note": "Detailed JSON output not yet implemented"
674 })
675 );
676 }
677
678 Ok(())
679 },
680
681 Command::Restart { service, force } => {
682 if let Some(ref svc) = service {
684 if svc.is_empty() || svc.len() > 64 {
685 return Err("Service name must be 1-64 characters".into());
686 }
687 }
688
689 println!("🔄 Restart Command");
692
693 println!("");
694
695 if let Some(svc) = service {
696 println!("Restarting service: {}", svc);
697
698 println!(" Note: Individual service restart requires gRPC integration");
699
700 println!(" Workaround: Restart the entire daemon");
701 } else {
702 println!("Restarting all services...");
703
704 println!(" Note: Full daemon restart requires gRPC integration");
705
706 println!(" Workaround: Use: kill <pid> && Air --daemon");
707 }
708
709 if force {
710 println!("");
711
712 println!("⚠️ Force mode enabled");
713
714 println!(
715 " Note: Force restart requires proper coordination to gracefully terminate in-progress operations"
716 );
717 }
718
719 Err("Restart command requires gRPC integration".into())
720 },
721
722 Command::Config(config_cmd) => {
723 match config_cmd {
724 ConfigCommand::Get { key } => {
725 if key.is_empty() || key.len() > 256 {
727 return Err("Configuration key must be 1-256 characters".into());
728 }
729
730 if key.contains('\0') || key.contains('\n') {
731 return Err("Configuration key contains invalid characters".into());
732 }
733
734 println!("⚙️ Get Configuration");
737
738 println!(" Key: {}", key);
739
740 println!("");
741
742 match attempt_daemon_connection().await {
743 Ok(_) => {
744 println!(" Status: ✅ Connected to daemon");
745
746 println!("");
747
748 println!(" Note: Config retrieval via gRPC not yet implemented");
749
750 println!(" Config value would be retrieved from daemon's configuration manager");
751 },
752
753 Err(e) => {
754 println!(" Status: ❌ Cannot connect to daemon");
755
756 println!(" Error: {}", e);
757
758 println!("");
759
760 println!(" Workaround: Check config file directly: cat {}", DefaultConfigFile);
761
762 return Err(format!("Cannot get config: {}", e).into());
763 },
764 }
765
766 Err("Config 'get' command requires gRPC integration".into())
767 },
768
769 ConfigCommand::Set { key, value } => {
770 if key.is_empty() || key.len() > 256 {
772 return Err("Configuration key must be 1-256 characters".into());
773 }
774
775 if value.len() > 8192 {
776 return Err("Configuration value too long (max: 8192 characters)".into());
777 }
778
779 if key.contains('\0') || key.contains('\n') {
780 return Err("Configuration key contains invalid characters".into());
781 }
782
783 println!("⚙️ Set Configuration");
786
787 println!(" Key: {}", key);
788
789 println!(" Value: {}", value);
790
791 println!("");
792
793 match attempt_daemon_connection().await {
794 Ok(_) => {
795 println!(" Status: ✅ Connected to daemon");
796
797 println!("");
798
799 println!(" Note: Config update via gRPC not yet implemented");
800
801 println!(" Config value would be set in daemon's configuration manager");
802 },
803
804 Err(e) => {
805 println!(" Status: ❌ Cannot connect to daemon");
806
807 println!(" Error: {}", e);
808
809 println!("");
810
811 println!(" Workaround: Edit config file directly, then use 'Air config reload'");
812
813 return Err(format!("Cannot set config: {}", e).into());
814 },
815 }
816
817 println!("");
818
819 println!(" ⚠️ Warning: Config changes may require reload or restart");
820
821 Err("Config 'set' command requires gRPC integration".into())
822 },
823
824 ConfigCommand::Reload { validate } => {
825 println!("🔄 Reload Configuration");
828
829 println!("");
830
831 match attempt_daemon_connection().await {
832 Ok(_) => {
833 println!(" Status: ✅ Connected to daemon");
834
835 println!("");
836
837 if validate {
838 println!(" Validating configuration...");
839
840 println!(" Note: Validation not yet implemented");
841 }
842
843 println!(" Note: Config reload via gRPC not yet implemented");
844
845 println!(" Workaround: Restart daemon to apply config changes");
846 },
847
848 Err(e) => {
849 println!(" Status: ❌ Cannot connect to daemon");
850
851 println!(" Error: {}", e);
852
853 return Err(format!("Cannot reload config: {}", e).into());
854 },
855 }
856
857 Err("Config 'reload' command requires gRPC integration".into())
858 },
859
860 ConfigCommand::Show { json } => {
861 println!("⚙️ Show Configuration");
864
865 println!("");
866
867 if json {
868 println!(" JSON output requested");
869
870 match attempt_daemon_connection().await {
871 Ok(_) => {
872 println!(" Status: ✅ Connected to daemon");
873
874 println!(" Note: JSON config export via gRPC not yet implemented");
875 },
876
877 Err(e) => {
878 println!(" Status: ❌ Cannot connect to daemon");
879
880 println!(" Error: {}", e);
881
882 return Err(format!("Cannot show config: {}", e).into());
883 },
884 }
885 } else {
886 println!(" Current Configuration:");
887
888 match attempt_daemon_connection().await {
889 Ok(_) => {
890 println!(" Status: ✅ Connected to daemon");
891
892 println!(" Note: Config display via gRPC not yet implemented");
893 },
894
895 Err(e) => {
896 println!(" Status: ❌ Cannot connect to daemon");
897
898 println!(" Error: {}", e);
899
900 println!(" Workaround: View config file: cat {}", DefaultConfigFile);
901
902 return Err(format!("Cannot show config: {}", e).into());
903 },
904 }
905 }
906
907 println!("");
908
909 println!(" Default config file: {}", DefaultConfigFile);
910
911 println!(" Config directory: ~/.config/Air/");
912
913 Err("Config 'show' command requires gRPC integration".into())
914 },
915
916 ConfigCommand::Validate { path } => {
917 if let Some(ref p) = path {
919 if p.is_empty() || p.len() > 512 {
920 return Err("Config path must be 1-512 characters".into());
921 }
922
923 if p.contains("..") || p.contains('\0') {
924 return Err("Config path contains invalid characters".into());
925 }
926 }
927
928 println!("✅ Validate Configuration");
929
930 println!("");
931
932 let config_path = path.unwrap_or_else(|| DefaultConfigFile.to_string());
933
934 println!(" Config file: {}", config_path);
935
936 println!("");
937
938 match std::path::Path::new(&config_path).exists() {
940 true => {
941 println!(" ✅ Config file exists");
942
943 println!(" Note: Detailed validation not yet implemented");
944
945 println!(" Workaround: Use: Air --validate-config");
946 },
947
948 false => {
949 println!(" ❌ Config file not found");
950
951 println!(" Hint: Create a config file or use defaults");
952 },
953 }
954
955 Err("Config 'validate' command not yet implemented".into())
956 },
957 }
958 },
959
960 Command::Metrics { json, service } => {
961 if let Some(ref svc) = service {
963 if svc.is_empty() || svc.len() > 64 {
964 return Err("Service name must be 1-64 characters".into());
965 }
966 }
967
968 println!("📊 Metrics");
969
970 println!("");
971
972 match attempt_daemon_connection().await {
974 Ok(_) => {
975 println!(" Status: ✅ Daemon is running");
976
977 println!("");
978
979 println!(" Note: Metrics collection is partially implemented");
980
981 println!("");
982
983 println!(" Current Metrics (basic):");
984
985 println!(" Uptime: Not tracked yet");
986
987 println!(" Requests: Not tracked yet");
988
989 println!(" Errors: Not tracked yet");
990
991 println!(" Memory: Not tracked yet");
992
993 println!(" CPU: Not tracked yet");
994
995 println!("");
996
997 println!(" Note: Comprehensive metrics require gRPC integration:");
998
999 println!(" - Request/response counters");
1000
1001 println!(" - Latency percentiles");
1002
1003 println!(" - Error rate tracking");
1004
1005 println!(" - Resource usage");
1006
1007 println!(" - Connection pool stats");
1008
1009 println!(" - Background queue depth");
1010 },
1011
1012 Err(e) => {
1013 println!(" Status: ❌ Cannot connect to daemon");
1014
1015 println!(" Error: {}", e);
1016
1017 return Err(format!("Cannot retrieve metrics: {}", e).into());
1018 },
1019 }
1020
1021 if json {
1022 println!("");
1023
1024 println!("📋 JSON Output:");
1025
1026 println!(
1027 "{}",
1028 serde_json::json!({
1029 "note": "Detailed metrics not yet implemented",
1030 "suggestion": "Use /metrics endpoint when daemon is running"
1031 })
1032 );
1033 }
1034
1035 if let Some(svc) = service {
1036 println!("");
1037
1038 println!(" Service-specific metrics requested: {}", svc);
1039
1040 println!(" Note: Service isolation not yet implemented");
1041 }
1042
1043 Ok(())
1044 },
1045
1046 Command::Logs { service, tail, filter, follow } => {
1047 if let Some(ref svc) = service {
1049 if svc.is_empty() || svc.len() > 64 {
1050 return Err("Service name must be 1-64 characters".into());
1051 }
1052 }
1053
1054 if let Some(n) = tail {
1055 if n < 1 || n > 10000 {
1056 return Err("Tail count must be 1-10000 lines".into());
1057 }
1058 }
1059
1060 if let Some(ref f) = filter {
1061 if f.is_empty() || f.len() > 512 {
1062 return Err("Filter string must be 1-512 characters".into());
1063 }
1064 }
1065
1066 println!("📝 Logs");
1067
1068 println!("");
1069
1070 let log_file = std::env::var("AIR_LOG_FILE").ok();
1072
1073 let log_dir = std::env::var("AIR_LOG_DIR").ok();
1074
1075 match (log_file, log_dir) {
1076 (Some(file), _) => {
1077 println!(" Log file: {}", file);
1078
1079 if std::path::Path::new(&file).exists() {
1081 println!(" Status: ✅ Log file exists");
1082
1083 println!("");
1084
1085 println!(" Note: Log tailing via file API not yet implemented");
1088
1089 println!(" Workaround: Use standard tools:");
1090
1091 println!(" - tail -n {} {}", tail.unwrap_or(100), file);
1092
1093 if let Some(f) = filter {
1094 println!(" - grep '{}' {} | tail -n {}", f, file, tail.unwrap_or(100));
1095 }
1096
1097 if follow {
1098 println!(" - tail -f {}", file);
1099 }
1100 } else {
1101 println!(" Status: ❌ Log file not found");
1102
1103 println!(" Check logging configuration");
1104 }
1105 },
1106
1107 (_, Some(dir)) => {
1108 println!(" Log directory: {}", dir);
1109
1110 println!(" Note: Log file viewing not yet implemented");
1111
1112 println!(" Workaround: Find and view log files in the directory");
1113 },
1114
1115 _ => {
1116 println!(" Log file: Not configured");
1117
1118 println!(" Set via: AIR_LOG_FILE=/path/to/Air.log");
1119
1120 println!("");
1121
1122 println!(" Logs are likely going to stdout/stderr");
1123
1124 println!(" Use journalctl (Linux/macOS) or Event Viewer (Windows)");
1125 },
1126 }
1127
1128 if let Some(svc) = service {
1129 println!("");
1130
1131 println!(" Service-specific logs requested: {}", svc);
1132
1133 println!(" Note: Service log isolation not yet implemented");
1134 }
1135
1136 Err("Logs command not yet fully implemented".into())
1138 },
1139
1140 Command::Debug(debug_cmd) => {
1141 match debug_cmd {
1142 DebugCommand::DumpState { service, json } => {
1143 if let Some(ref svc) = service {
1145 if svc.is_empty() || svc.len() > 64 {
1146 return Err("Service name must be 1-64 characters".into());
1147 }
1148 }
1149
1150 println!("🔧 Debug: Dump State");
1151
1152 println!("");
1153
1154 if let Some(svc) = service {
1155 println!(" Service: {}", svc);
1156
1157 println!(" Note: Service state isolation not yet implemented");
1158 } else {
1159 println!(" Dumping all service states...");
1160
1161 println!(" Note: State dumping not yet implemented");
1162 }
1163
1164 if json {
1165 println!("");
1166
1167 println!(" JSON format requested");
1168
1169 println!(" Note: JSON state export not yet implemented");
1170 }
1171
1172 println!("");
1173
1174 println!(" Note: State dumping requires gRPC integration:");
1175
1176 println!(" - Application state");
1177
1178 println!(" - Service states");
1179
1180 println!(" - Connection pool");
1181
1182 println!(" - Background tasks");
1183
1184 println!(" - Metrics cache");
1185
1186 println!(" - Configuration snapshot");
1187
1188 Err("Debug 'dump-state' command not yet implemented".into())
1189 },
1190
1191 DebugCommand::DumpConnections { format } => {
1192 println!("🔧 Debug: Dump Connections");
1193
1194 println!("");
1195
1196 match attempt_daemon_connection().await {
1197 Ok(_) => {
1198 println!(" Status: ✅ Daemon is running");
1199
1200 println!("");
1201
1202 println!(" Active Connections: 0");
1203
1204 println!(" Note: Connection tracking not yet implemented");
1205 },
1206
1207 Err(e) => {
1208 println!(" Status: ❌ Cannot connect to daemon");
1209
1210 println!(" Error: {}", e);
1211
1212 return Err(format!("Cannot dump connections: {}", e).into());
1213 },
1214 }
1215
1216 if let Some(fmt) = format {
1217 println!("");
1218
1219 println!(" Format: {}", fmt);
1220
1221 println!(" Note: Custom format not yet implemented");
1222 }
1223
1224 println!("");
1225
1226 println!(" Note: Connection dump requires gRPC integration:");
1227
1228 println!(" - Connection ID");
1229
1230 println!(" - Remote address");
1231
1232 println!(" - Connected at timestamp");
1233
1234 println!(" - Last activity");
1235
1236 println!(" - Active requests");
1237
1238 println!(" - Bytes transferred");
1239
1240 Err("Debug 'dump-connections' command not yet implemented".into())
1241 },
1242
1243 DebugCommand::HealthCheck { verbose, service } => {
1244 if let Some(ref svc) = service {
1246 if svc.is_empty() || svc.len() > 64 {
1247 return Err("Service name must be 1-64 characters".into());
1248 }
1249 }
1250
1251 println!("🔧 Debug: Health Check");
1252
1253 println!("");
1254
1255 match attempt_daemon_connection().await {
1256 Ok(_) => {
1257 println!(" Overall: ⚠️ Basic check passed");
1258
1259 println!("");
1260
1261 if let Some(svc) = service {
1262 println!(" Service: {}", svc);
1263
1264 println!(" Status: Not checked (detailed checks not implemented)");
1265 } else {
1266 println!(" Services:");
1267
1268 println!(" gRPC Server: ✅ Responding");
1269
1270 println!(" Authentication: ⏸️ Not checked");
1271
1272 println!(" Updates: ⏸️ Not checked");
1273
1274 println!(" Download Manager: ⏸️ Not checked");
1275
1276 println!(" File Indexer: ⏸️ Not checked");
1277 }
1278
1279 if verbose {
1280 println!("");
1281
1282 println!(" 🔍 Verbose Information:");
1283
1284 println!(" Last health check: Not tracked");
1285
1286 println!(" Health check interval: 30s (default)");
1287
1288 println!(" Failure threshold: 3 (configurable)");
1289
1290 println!(" Recovery threshold: 2 (configurable)");
1291 }
1292 },
1293
1294 Err(e) => {
1295 println!(" Overall: ❌ Daemon unreachable");
1296
1297 println!(" Error: {}", e);
1298
1299 return Err(format!("Health check failed: {}", e).into());
1300 },
1301 }
1302
1303 Err("Debug 'health-check' not detailed yet".into())
1304 },
1305
1306 DebugCommand::Diagnostics { level } => {
1307 println!("🔧 Debug: Diagnostics");
1308
1309 println!("");
1310
1311 println!(" Level: {:?}", level);
1312
1313 println!("");
1314
1315 println!(" System Information:");
1317
1318 println!(" OS: {}", std::env::consts::OS);
1319
1320 println!(" Arch: {}", std::env::consts::ARCH);
1321
1322 println!(" Air Version: {}", VERSION);
1323
1324 println!("");
1325
1326 match attempt_daemon_connection().await {
1327 Ok(_) => {
1328 println!(" Daemon: ✅ Running");
1329 },
1330
1331 Err(e) => {
1332 println!(" Daemon: ❌ Running");
1333
1334 println!(" Error: {}", e);
1335 },
1336 }
1337
1338 println!("");
1339
1340 println!(" Note: Advanced diagnostics require additional infrastructure:");
1341
1342 println!(" - Thread dump");
1343
1344 println!(" - Memory profiling");
1345
1346 println!(" - Lock contention analysis");
1347
1348 println!(" - Resource leak detection");
1349
1350 println!(" - Performance bottlenecks");
1351
1352 Ok(())
1353 },
1354 }
1355 },
1356 }
1357}
1358
1359fn validate_command(cmd:&Command) -> Result<(), String> {
1366 match cmd {
1367 Command::Help { command } => {
1368 if let Some(cmd) = command {
1369 if cmd.len() > 128 {
1370 return Err("Command name too long (max: 128)".to_string());
1371 }
1372 }
1373 },
1374
1375 _ => {},
1376 }
1377
1378 Ok(())
1379}
1380
1381async fn attempt_daemon_connection_with_retry(max_retries:usize, initial_delay_ms:u64) -> Result<(), String> {
1404 use tokio::{
1405 net::TcpStream,
1406 time::{Duration, timeout},
1407 };
1408
1409 let addr = DefaultBindAddress;
1410
1411 let mut attempt = 0;
1412
1413 let mut delay_ms = initial_delay_ms;
1414
1415 loop {
1416 attempt += 1;
1417
1418 dev_log!("lifecycle", "[DaemonConnection] Attempt {} of {}", attempt, max_retries + 1);
1419
1420 let connection_result = timeout(Duration::from_secs(5), async { TcpStream::connect(addr).await }).await;
1422
1423 match connection_result {
1424 Ok(Ok(_stream)) => {
1425 dev_log!("lifecycle", "[DaemonConnection] Connected successfully on attempt {}", attempt);
1426
1427 return Ok(());
1428 },
1429
1430 Ok(Err(e)) => {
1431 dev_log!("lifecycle", "[DaemonConnection] Attempt {} failed: {}", attempt, e);
1432 },
1433
1434 Err(_) => {
1435 dev_log!("lifecycle", "[DaemonConnection] Attempt {} timed out", attempt);
1436 },
1437 }
1438
1439 if attempt > max_retries {
1441 break;
1442 }
1443
1444 dev_log!("lifecycle", "[DaemonConnection] Waiting {}ms before retry...", delay_ms);
1446
1447 tokio::time::sleep(Duration::from_millis(delay_ms)).await;
1448
1449 delay_ms = delay_ms * 2; }
1451
1452 Err(format!("Failed to connect after {} attempts", max_retries + 1))
1453}
1454
1455async fn attempt_daemon_connection() -> Result<(), String> {
1460 attempt_daemon_connection_with_retry(3, 500).await
1462}
1463
1464fn HandleMetricsRequest() -> String {
1484 let _timeout_duration = std::time::Duration::from_millis(100);
1486
1487 let metrics_collector = Metrics::GetMetrics();
1488
1489 let export_result = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| metrics_collector.ExportMetrics()));
1491
1492 match export_result {
1493 Ok(Ok(metrics_text)) => {
1494 if metrics_text.len() > 10_000_000 {
1496 dev_log!(
1497 "metrics",
1498 "error: [Metrics] Exported metrics unreasonably large (size: {} bytes)",
1499 metrics_text.len()
1500 );
1501
1502 format!("# ERROR: Metrics export too large (max: 10MB)\n")
1503 } else {
1504 metrics_text
1505 }
1506 },
1507
1508 Ok(Err(e)) => {
1509 dev_log!("metrics", "error: [Metrics] Failed to export metrics: {}", e);
1510
1511 format!("# ERROR: Failed to export metrics: {}\n", e)
1512 },
1513
1514 Err(_) => {
1515 dev_log!("metrics", "error: [Metrics] Metrics export panicked");
1516
1517 format!("# ERROR: Metrics export failed due to internal error\n")
1518 },
1519 }
1520}
1521
1522async fn Main() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
1563 CommonLibrary::Telemetry::Initialize::Fn(CommonLibrary::Telemetry::Tier::Tier::Air).await;
1569
1570 InitializeLogging();
1574
1575 dev_log!("lifecycle", "[Boot] ===========================================");
1576
1577 dev_log!("lifecycle", "[Boot] Starting Air Daemon");
1578
1579 dev_log!("lifecycle", "[Boot] ===========================================");
1580
1581 dev_log!(
1582 "lifecycle",
1583 "[Boot] Version: {} ({})",
1584 env!("CARGO_PKG_VERSION"),
1585 env!("CARGO_PKG_NAME")
1586 );
1587
1588 let build_timestamp = env::var("BUILD_TIMESTAMP").unwrap_or_else(|_| "unknown".to_string());
1589
1590 dev_log!("lifecycle", "[Boot] Build: {}", build_timestamp);
1591
1592 dev_log!(
1593 "lifecycle",
1594 "[Boot] Target: {}-{}",
1595 std::env::consts::OS,
1596 std::env::consts::ARCH
1597 );
1598
1599 dev_log!("lifecycle", "[Boot] Validating environment...");
1603
1604 if let Err(e) = validate_environment().await {
1605 dev_log!("lifecycle", "error: [Boot] Environment validation failed: {}", e);
1606
1607 return Err(format!("Environment validation failed: {}", e).into());
1608 }
1609
1610 dev_log!("lifecycle", "[Boot] Environment validation passed");
1611
1612 Trace!("[Boot] [Observability] Initializing observability systems...");
1616
1617 if let Err(e) = Metrics::InitializeMetrics() {
1619 dev_log!("lifecycle", "error: [Boot] Failed to initialize metrics: {}", e);
1620
1621 } else {
1623 dev_log!("lifecycle", "[Boot] [Observability] Metrics system initialized");
1624 }
1625
1626 if let Err(e) = Tracing::initialize_tracing(None) {
1628 dev_log!("lifecycle", "error: [Boot] Failed to initialize tracing: {}", e);
1629
1630 } else {
1632 dev_log!("lifecycle", "[Boot] [Observability] Tracing system initialized");
1633 }
1634
1635 dev_log!("lifecycle", "[Boot] [Observability] Observability systems initialized");
1636
1637 Trace!("[Boot] [Args] Parsing command line arguments...");
1641
1642 let (config_path, bind_address, cli_command) = ParseArguments();
1643
1644 if let Some(cmd) = cli_command {
1646 dev_log!("lifecycle", "[Boot] CLI command detected, executing...");
1647
1648 let result = HandleCommand(cmd).await;
1649
1650 match &result {
1651 Ok(_) => {
1652 dev_log!("lifecycle", "[Boot] CLI command completed successfully");
1653
1654 std::process::exit(0);
1655 },
1656
1657 Err(e) => {
1658 dev_log!("lifecycle", "error: [Boot] CLI command failed: {}", e);
1659
1660 std::process::exit(1);
1661 },
1662 }
1663 }
1664
1665 Trace!("[Boot] [Configuration] Loading configuration...");
1669
1670 let config_manager = match ConfigurationManager::New(config_path) {
1671 Ok(cm) => cm,
1672
1673 Err(e) => {
1674 dev_log!("lifecycle", "error: [Boot] Failed to create configuration manager: {}", e);
1675
1676 return Err(format!("Configuration manager initialization failed: {}", e).into());
1677 },
1678 };
1679
1680 let configuration:std::sync::Arc<AirLibrary::Configuration::AirConfiguration> =
1682 match tokio::time::timeout(Duration::from_secs(10), config_manager.LoadConfiguration()).await {
1683 Ok(Ok(config)) => {
1684 dev_log!("lifecycle", "[Boot] [Configuration] Configuration loaded successfully");
1685
1686 std::sync::Arc::new(config)
1687 },
1688
1689 Ok(Err(e)) => {
1690 dev_log!("lifecycle", "error: [Boot] Failed to load configuration: {}", e);
1691
1692 return Err(format!("Configuration load failed: {}", e).into());
1693 },
1694
1695 Err(_) => {
1696 dev_log!("lifecycle", "error: [Boot] Configuration load timed out");
1697
1698 return Err("Configuration load timed out".into());
1699 },
1700 };
1701
1702 validate_configuration(&configuration)?;
1704
1705 Trace!("[Boot] [Daemon] Initializing daemon lifecycle management...");
1709
1710 let daemon_manager = match DaemonManager::New(None) {
1711 Ok(dm) => dm,
1712
1713 Err(e) => {
1714 dev_log!("lifecycle", "error: [Boot] Failed to create daemon manager: {}", e);
1715
1716 return Err(format!("Daemon manager initialization failed: {}", e).into());
1717 },
1718 };
1719
1720 match tokio::time::timeout(Duration::from_secs(5), daemon_manager.AcquireLock()).await {
1722 Ok(Ok(_)) => {
1723 dev_log!("lifecycle", "[Boot] [Daemon] Daemon lock acquired successfully");
1724 },
1725
1726 Ok(Err(e)) => {
1727 dev_log!("lifecycle", "error: [Boot] Failed to acquire daemon lock: {}", e);
1728
1729 dev_log!("lifecycle", "error: [Boot] Another instance may already be running");
1730
1731 return Err(format!("Daemon lock acquisition failed: {}", e).into());
1732 },
1733
1734 Err(_) => {
1735 dev_log!("lifecycle", "error: [Boot] Daemon lock acquisition timed out");
1736
1737 return Err("Daemon lock acquisition timed out".into());
1738 },
1739 }
1740
1741 Trace!("[Boot] [Health] Initializing health check system...");
1745
1746 let health_manager:std::sync::Arc<HealthCheckManager> = Arc::new(HealthCheckManager::new(None));
1747
1748 dev_log!("lifecycle", "[Boot] [Health] Health check system initialized");
1749
1750 Trace!("[Boot] [State] Initializing application state...");
1754
1755 let AppState:std::sync::Arc<ApplicationState> =
1756 match tokio::time::timeout(Duration::from_secs(10), ApplicationState::New(configuration.clone())).await {
1757 Ok(Ok(state)) => {
1758 dev_log!("lifecycle", "[Boot] [State] Application state initialized");
1759
1760 Arc::new(state)
1761 },
1762
1763 Ok(Err(e)) => {
1764 dev_log!("lifecycle", "error: [Boot] Failed to initialize application state: {}", e);
1765
1766 let _ = daemon_manager.ReleaseLock().await;
1768
1769 return Err(format!("Application state initialization failed: {}", e).into());
1770 },
1771
1772 Err(_) => {
1773 dev_log!("lifecycle", "error: [Boot] Application state initialization timed out");
1774
1775 let _ = daemon_manager.ReleaseLock().await;
1776
1777 return Err("Application state initialization timed out".into());
1778 },
1779 };
1780
1781 Trace!("[Boot] [Services] Initializing core services...");
1785
1786 let auth_service:std::sync::Arc<AuthenticationService> =
1788 match tokio::time::timeout(Duration::from_secs(10), AuthenticationService::new(AppState.clone())).await {
1789 Ok(Ok(svc)) => Arc::new(svc),
1790
1791 Ok(Err(e)) => {
1792 dev_log!("lifecycle", "error: [Boot] Failed to initialize authentication service: {}", e);
1793
1794 return Err(format!("Authentication service initialization failed: {}", e).into());
1795 },
1796
1797 Err(_) => {
1798 dev_log!("lifecycle", "error: [Boot] Authentication service initialization timed out");
1799
1800 return Err("Authentication service initialization timed out".into());
1801 },
1802 };
1803
1804 let update_manager:std::sync::Arc<UpdateManager> =
1805 match tokio::time::timeout(Duration::from_secs(10), UpdateManager::new(AppState.clone())).await {
1806 Ok(Ok(svc)) => Arc::new(svc),
1807
1808 Ok(Err(e)) => {
1809 dev_log!("lifecycle", "error: [Boot] Failed to initialize update manager: {}", e);
1810
1811 return Err(format!("Update manager initialization failed: {}", e).into());
1812 },
1813
1814 Err(_) => {
1815 dev_log!("lifecycle", "error: [Boot] Update manager initialization timed out");
1816
1817 return Err("Update manager initialization timed out".into());
1818 },
1819 };
1820
1821 let download_manager:std::sync::Arc<DownloadManager> =
1822 match tokio::time::timeout(Duration::from_secs(10), DownloadManager::new(AppState.clone())).await {
1823 Ok(Ok(svc)) => Arc::new(svc),
1824
1825 Ok(Err(e)) => {
1826 dev_log!("lifecycle", "error: [Boot] Failed to initialize download manager: {}", e);
1827
1828 return Err(format!("Download manager initialization failed: {}", e).into());
1829 },
1830
1831 Err(_) => {
1832 dev_log!("lifecycle", "error: [Boot] Download manager initialization timed out");
1833
1834 return Err("Download manager initialization timed out".into());
1835 },
1836 };
1837
1838 let file_indexer:std::sync::Arc<FileIndexer> =
1839 match tokio::time::timeout(Duration::from_secs(10), FileIndexer::new(AppState.clone())).await {
1840 Ok(Ok(svc)) => Arc::new(svc),
1841
1842 Ok(Err(e)) => {
1843 dev_log!("lifecycle", "error: [Boot] Failed to initialize file indexer: {}", e);
1844
1845 return Err(format!("File indexer initialization failed: {}", e).into());
1846 },
1847
1848 Err(_) => {
1849 dev_log!("lifecycle", "error: [Boot] File indexer initialization timed out");
1850
1851 return Err("File indexer initialization timed out".into());
1852 },
1853 };
1854
1855 dev_log!("lifecycle", "[Boot] [Services] All core services initialized successfully");
1856
1857 Trace!("[Boot] [Health] Registering services for health monitoring...");
1861
1862 let service_registrations = vec![
1864 ("authentication", HealthCheckLevel::Functional),
1865 ("updates", HealthCheckLevel::Functional),
1866 ("downloader", HealthCheckLevel::Functional),
1867 ("indexing", HealthCheckLevel::Functional),
1868 ("grpc", HealthCheckLevel::Responsive),
1869 ("connections", HealthCheckLevel::Alive),
1870 ];
1871
1872 for (service_name, level) in service_registrations {
1873 match tokio::time::timeout(
1874 Duration::from_secs(5),
1875 health_manager.RegisterService(service_name.to_string(), level),
1876 )
1877 .await
1878 {
1879 Ok(result) => {
1880 match result {
1881 Ok(_) => {
1882 dev_log!("lifecycle", "[Boot] [Health] Registered service: {}", service_name);
1883 },
1884
1885 Err(e) => {
1886 dev_log!("lifecycle", "warn: [Boot] Failed to register service {}: {}", service_name, e);
1887
1888 },
1891 }
1892 },
1893
1894 Err(_) => {
1895 dev_log!("lifecycle", "warn: [Boot] Service registration timed out: {}", service_name);
1896 },
1897 }
1898 }
1899
1900 dev_log!("lifecycle", "[Boot] [Health] Service health monitoring configured");
1901
1902 Trace!("[Boot] [Vine] Initializing gRPC server...");
1906
1907 let bind_addr:SocketAddr = match bind_address {
1909 Some(addr) => {
1910 match addr.parse() {
1911 Ok(parsed) => {
1912 dev_log!("lifecycle", "[Boot] [Vine] Using custom bind address: {}", parsed);
1913
1914 parsed
1915 },
1916
1917 Err(e) => {
1918 dev_log!("lifecycle", "error: [Boot] Invalid bind address '{}': {}", addr, e);
1919
1920 return Err(format!("Invalid bind address: {}", e).into());
1921 },
1922 }
1923 },
1924
1925 None => {
1926 match DefaultBindAddress.parse() {
1927 Ok(parsed) => parsed,
1928
1929 Err(e) => {
1930 dev_log!(
1931 "lifecycle",
1932 "error: [Boot] Invalid default bind address '{}': {}",
1933 DefaultBindAddress,
1934 e
1935 );
1936
1937 return Err(format!("Invalid default bind address: {}", e).into());
1938 },
1939 }
1940 },
1941 };
1942
1943 dev_log!("lifecycle", "[Boot] [Vine] Configuring gRPC server on {}", bind_addr);
1944
1945 let vine_service = AirVinegRPCService::new(
1947 AppState.clone(),
1948 auth_service.clone(),
1949 update_manager.clone(),
1950 download_manager.clone(),
1951 file_indexer.clone(),
1952 );
1953
1954 let (shutdown_tx, shutdown_rx) = tokio::sync::oneshot::channel::<()>();
1956
1957 let server_handle:tokio::task::JoinHandle<Result<(), Box<dyn std::error::Error + Send + Sync>>> =
1959 tokio::spawn(async move {
1960 dev_log!("lifecycle", "[Vine] Starting gRPC server on {}", bind_addr);
1961
1962 let svc = AirServiceServer::new(vine_service);
1963
1964 let server = tonic::transport::Server::builder()
1965 .add_service(svc)
1966 .serve_with_shutdown(bind_addr, async {
1967 let _ = shutdown_rx.await;
1969
1970 dev_log!("lifecycle", "[Vine] Shutdown signal received, stopping server...");
1971 });
1972
1973 dev_log!("lifecycle", "[Vine] gRPC server listening on {}", bind_addr);
1974
1975 match server.await {
1976 Ok(_) => {
1977 dev_log!("lifecycle", "[Vine] gRPC server stopped cleanly");
1978
1979 Ok(())
1980 },
1981 Err(e) => {
1982 dev_log!("grpc", "error: [Vine] gRPC server error: {}", e);
1983
1984 Err(e.into())
1985 },
1986 }
1987 });
1988
1989 tokio::time::sleep(Duration::from_millis(100)).await;
1991
1992 if server_handle.is_finished() {
1994 dev_log!("lifecycle", "error: [Boot] gRPC server failed to start");
1995
1996 let _ = daemon_manager.ReleaseLock().await;
1997
1998 return Err("gRPC server failed to start".into());
1999 }
2000
2001 Trace!("[Boot] [Monitoring] Starting background monitoring tasks...");
2005
2006 let connection_monitor_handle:tokio::task::JoinHandle<()> = tokio::spawn({
2008 let AppState = AppState.clone();
2009
2010 let health_manager = health_manager.clone();
2011
2012 async move {
2013 let mut interval = interval(Duration::from_secs(60)); loop {
2016 interval.tick().await;
2017
2018 if let Err(e) = AppState.UpdateResourceUsage().await {
2020 dev_log!("lifecycle", "warn: [ConnectionMonitor] Failed to update resource usage: {}", e);
2021 }
2022
2023 let resources = AppState.GetResourceUsage().await;
2025
2026 let metrics_collector = Metrics::GetMetrics();
2028
2029 metrics_collector.UpdateResourceMetrics(
2030 (resources.MemoryUsageMb * 1024.0 * 1024.0) as u64, resources.CPUUsagePercent,
2032 AppState.GetActiveConnectionCount().await as u64,
2033 0, );
2035
2036 if let Err(e) = AppState.CleanupStaleConnections(300).await {
2038 dev_log!(
2039 "lifecycle",
2040 "warn: [ConnectionMonitor] Failed to cleanup stale connections: {}",
2041 e
2042 );
2043 }
2044
2045 match health_manager.CheckService("connections").await {
2047 Ok(_) => {},
2048 Err(e) => {
2049 dev_log!("lifecycle", "warn: [ConnectionMonitor] Health check failed: {}", e);
2050
2051 let metrics_collector = Metrics::GetMetrics();
2053
2054 metrics_collector.RecordRequestFailure("health_check_failed", 0.0);
2055 },
2056 }
2057
2058 dev_log!(
2059 "lifecycle",
2060 "[ConnectionMonitor] Active connections: {}",
2061 AppState.GetActiveConnectionCount().await
2062 );
2063 }
2064 }
2065 });
2066
2067 if let Err(e) = AppState.RegisterBackgroundTask(connection_monitor_handle).await {
2069 dev_log!("lifecycle", "warn: [Boot] Failed to register connection monitor: {}", e);
2070
2071 }
2073
2074 let health_monitor_handle:tokio::task::JoinHandle<()> = tokio::spawn({
2076 let health_manager = health_manager.clone();
2077
2078 async move {
2079 let mut interval = interval(Duration::from_secs(30)); loop {
2082 interval.tick().await;
2083
2084 let services = ["authentication", "updates", "downloader", "indexing", "grpc"];
2086
2087 for service in services.iter() {
2088 if let Err(e) = health_manager.CheckService(service).await {
2089 dev_log!("lifecycle", "warn: [HealthMonitor] Health check failed for {}: {}", service, e);
2090 }
2091 }
2092
2093 let overall_health = health_manager.GetOverallHealth().await;
2095
2096 dev_log!("lifecycle", "[HealthMonitor] Overall health: {:?}", overall_health);
2097 }
2098 }
2099 });
2100
2101 if let Err(e) = AppState.RegisterBackgroundTask(health_monitor_handle).await {
2103 dev_log!("lifecycle", "warn: [Boot] Failed to register health monitor: {}", e);
2104
2105 }
2107
2108 Trace!("[Boot] [Startup] Starting background services...");
2112
2113 let _ = auth_service.StartBackgroundTasks().await?;
2115
2116 let _ = update_manager.StartBackgroundTasks().await?;
2117
2118 let _ = download_manager.StartBackgroundTasks().await?;
2119
2120 let _indexing_handle = None::<tokio::task::JoinHandle<()>>;
2122
2123 dev_log!("lifecycle", "[Boot] [Startup] All services started successfully");
2124
2125 dev_log!("lifecycle", "===========================================");
2129
2130 dev_log!("lifecycle", "[Runtime] Air Daemon is now running");
2131
2132 dev_log!("lifecycle", "[Runtime] Listening on {} for Mountain connections", bind_addr);
2133
2134 dev_log!("lifecycle", "[Runtime] Protocol Version: {}", ProtocolVersion);
2135
2136 dev_log!("lifecycle", "[Runtime] Cocoon Port: 50052");
2137
2138 dev_log!("lifecycle", "===========================================");
2139
2140 dev_log!("lifecycle", "");
2141
2142 dev_log!("lifecycle", "Running. Press Ctrl+C to stop.");
2143
2144 dev_log!("lifecycle", "");
2145
2146 WaitForShutdownSignal().await;
2148
2149 dev_log!("lifecycle", "[Shutdown] Signaling gRPC server to stop...");
2151
2152 let _ = shutdown_tx.send(());
2153
2154 match tokio::time::timeout(Duration::from_secs(30), server_handle).await {
2156 Ok(Ok(Ok(_))) => {
2157 dev_log!("lifecycle", "[Shutdown] gRPC server stopped normally");
2158 },
2159
2160 Ok(Ok(Err(e))) => {
2161 dev_log!("lifecycle", "warn: [Shutdown] gRPC server stopped with error: {}", e);
2162 },
2163
2164 Ok(Err(e)) => {
2165 dev_log!("lifecycle", "warn: [Shutdown] gRPC server task panicked: {:?}", e);
2166 },
2167
2168 Err(_) => {
2169 dev_log!("lifecycle", "warn: [Shutdown] gRPC server shutdown timed out");
2170 },
2171 }
2172
2173 dev_log!("lifecycle", "===========================================");
2177
2178 dev_log!("lifecycle", "[Shutdown] Initiating graceful shutdown...");
2179
2180 dev_log!("lifecycle", "===========================================");
2181
2182 dev_log!("lifecycle", "[Shutdown] Stopping background tasks...");
2184
2185 if let Err(_) =
2186 tokio::time::timeout(Duration::from_secs(10), async { AppState.StopAllBackgroundTasks().await }).await
2187 {
2188 dev_log!("lifecycle", "warn: [Shutdown] Background tasks stop timed out or failed");
2189 }
2190
2191 dev_log!("lifecycle", "[Shutdown] Stopping background services...");
2193
2194 auth_service.StopBackgroundTasks().await;
2195
2196 update_manager.StopBackgroundTasks().await;
2197
2198 download_manager.StopBackgroundTasks().await;
2199
2200 dev_log!("lifecycle", "[Shutdown] Collecting final statistics...");
2202
2203 let metrics = AppState.GetMetrics().await;
2204
2205 let resources = AppState.GetResourceUsage().await;
2206
2207 let health_stats:HealthStatistics = health_manager.GetHealthStatistics().await;
2208
2209 let metrics_data = Metrics::GetMetrics().GetMetricsData();
2211
2212 dev_log!("lifecycle", "===========================================");
2213
2214 dev_log!("lifecycle", "[Shutdown] Final Statistics");
2215
2216 dev_log!("lifecycle", "===========================================");
2217
2218 dev_log!("lifecycle", "[Shutdown] Requests:");
2219
2220 dev_log!("lifecycle", " - Successful: {}", metrics.SuccessfulRequest);
2221
2222 dev_log!("lifecycle", " - Failed: {}", metrics.FailedRequest);
2223
2224 dev_log!("lifecycle", "[Shutdown] Metrics:");
2225
2226 dev_log!("lifecycle", " - Success rate: {:.2}%", metrics_data.SuccessRate());
2227
2228 dev_log!("lifecycle", " - Error rate: {:.2}%", metrics_data.ErrorRate());
2229
2230 dev_log!("lifecycle", "[Shutdown] Resources:");
2231
2232 dev_log!("lifecycle", " - Memory: {:.2} MB", resources.MemoryUsageMb);
2233
2234 dev_log!("lifecycle", " - CPU: {:.2}%", resources.CPUUsagePercent);
2235
2236 dev_log!("lifecycle", "[Shutdown] Health:");
2237
2238 dev_log!("lifecycle", " - Overall: {:.2}%", health_stats.OverallHealthPercentage());
2239
2240 dev_log!(
2241 "lifecycle",
2242 " - Healthy services: {}/{}",
2243 health_stats.HealthyServices,
2244 health_stats.TotalServices
2245 );
2246
2247 dev_log!("lifecycle", "===========================================");
2248
2249 dev_log!("lifecycle", "[Shutdown] Releasing daemon lock...");
2251
2252 if let Err(e) = daemon_manager.ReleaseLock().await {
2253 dev_log!("lifecycle", "warn: [Shutdown] Failed to release daemon lock: {}", e);
2254 }
2255
2256 dev_log!("lifecycle", "[Shutdown] All services stopped");
2257
2258 dev_log!("lifecycle", "[Shutdown] Air Daemon has shut down gracefully");
2259
2260 dev_log!("lifecycle", "===========================================");
2261
2262 Ok(())
2263}
2264
2265async fn validate_environment() -> Result<(), String> {
2274 dev_log!(
2276 "lifecycle",
2277 "[Environment] OS: {}, Arch: {}",
2278 std::env::consts::OS,
2279 std::env::consts::ARCH
2280 );
2281
2282 if let Ok(home) = std::env::var("HOME") {
2284 if home.is_empty() {
2285 return Err("HOME environment variable is not set".to_string());
2286 }
2287 }
2288
2289 let lock_path = "/tmp/Air-test-lock.tmp";
2291
2292 if std::fs::write(lock_path, b"test").is_err() {
2293 return Err("Cannot write to /tmp directory".to_string());
2294 }
2295
2296 let _ = std::fs::remove_file(lock_path);
2297
2298 Ok(())
2299}
2300
2301fn validate_configuration(_config:&AirConfiguration) -> Result<(), String> {
2310 dev_log!("lifecycle", "[Config] Configuration passed basic validation");
2312
2313 Ok(())
2314}
2315
2316#[tokio::main]
2317async fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync>> { Main().await }