package main import ( "fmt" "log" "time" "nannyagentv2/internal/auth" "nannyagentv2/internal/config" "nannyagentv2/internal/metrics" "nannyagentv2/internal/types" ) const Version = "v2.0.0" func main() { fmt.Printf("🚀 NannyAgent v%s starting...\n", Version) // Load configuration cfg, err := config.LoadConfig() if err != nil { log.Fatalf("❌ Failed to load configuration: %v", err) } cfg.PrintConfig() // Initialize components authManager := auth.NewAuthManager(cfg) metricsCollector := metrics.NewCollector(Version) // Ensure authentication token, err := authManager.EnsureAuthenticated() if err != nil { log.Fatalf("❌ Authentication failed: %v", err) } fmt.Println("✅ Authentication successful!") // Start metrics collection and heartbeat loop fmt.Println("❤️ Starting metrics collection and heartbeat...") ticker := time.NewTicker(time.Duration(cfg.MetricsInterval) * time.Second) defer ticker.Stop() // Send initial heartbeat if err := sendHeartbeat(cfg, token, metricsCollector); err != nil { log.Printf("⚠️ Initial heartbeat failed: %v", err) } // Main heartbeat loop for { select { case <-ticker.C: // Check if token needs refresh if authManager.IsTokenExpired(token) { fmt.Println("🔄 Token expiring soon, refreshing...") newToken, refreshErr := authManager.EnsureAuthenticated() if refreshErr != nil { log.Printf("❌ Token refresh failed: %v", refreshErr) continue } token = newToken fmt.Println("✅ Token refreshed successfully") } // Send heartbeat if err := sendHeartbeat(cfg, token, metricsCollector); err != nil { log.Printf("⚠️ Heartbeat failed: %v", err) // If unauthorized, try to refresh token if err.Error() == "unauthorized" { fmt.Println("🔄 Unauthorized, attempting token refresh...") newToken, refreshErr := authManager.EnsureAuthenticated() if refreshErr != nil { log.Printf("❌ Token refresh failed: %v", refreshErr) continue } token = newToken // Retry heartbeat with new token (silently) if retryErr := sendHeartbeat(cfg, token, metricsCollector); retryErr != nil { log.Printf("⚠️ Retry heartbeat failed: %v", retryErr) } } } // No logging for successful heartbeats - they should be silent } } } // sendHeartbeat collects metrics and sends heartbeat to the server func sendHeartbeat(cfg *config.Config, token *types.AuthToken, collector *metrics.Collector) error { // Collect system metrics systemMetrics, err := collector.GatherSystemMetrics() if err != nil { return fmt.Errorf("failed to gather system metrics: %w", err) } // Send metrics using the collector with correct agent_id from token return collector.SendMetrics(cfg.AgentAuthURL, token.AccessToken, token.AgentID, systemMetrics) }