using System.Net.Http.Headers; using System.Net.Http.Json; using Nexus.Api.DTOs; namespace Nexus.Api.Services; public sealed class CalendarService( IHttpClientFactory httpClientFactory, IConfiguration configuration, ILogger logger) : ICalendarService { public async Task> GetCronJobsAsync(CancellationToken ct = default) { try { var client = CreateGatewayClient(); var response = await client.GetAsync("/api/cron", ct); if (response.IsSuccessStatusCode) { var data = await response.Content.ReadFromJsonAsync>(ct); return data ?? new List(); } } catch (Exception ex) { logger.LogDebug(ex, "Gateway cron endpoint not reachable, using fallback data"); } return BuildFallbackCronJobs(); } public async Task> GetUpcomingCronJobsAsync(CancellationToken ct = default) { try { var client = CreateGatewayClient(); var response = await client.GetAsync("/api/cron/upcoming", ct); if (response.IsSuccessStatusCode) { var data = await response.Content.ReadFromJsonAsync>(ct); return data ?? new List(); } } catch (Exception ex) { logger.LogDebug(ex, "Gateway upcoming cron endpoint not reachable, using fallback data"); } return BuildFallbackUpcomingJobs(); } private HttpClient CreateGatewayClient() { var client = httpClientFactory.CreateClient("gateway"); var token = configuration["Integrations:OpenClaw:Token"]; if (!string.IsNullOrWhiteSpace(token)) client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token); return client; } private static IReadOnlyList BuildFallbackCronJobs() { var now = DateTimeOffset.UtcNow; return [ new("health-check", "Health Check", "*/5 * * * *", now.AddMinutes(-3).ToString("O"), now.AddMinutes(2).ToString("O"), "completed"), new("memory-sync", "Memory Sync", "0 */6 * * *", now.AddHours(-2).ToString("O"), now.AddHours(4).ToString("O"), "completed"), new("task-cleanup", "Task Cleanup", "0 3 * * *", now.AddDays(-1).ToString("O"), now.AddDays(1).AddHours(3).ToString("O"), "completed"), new("backup", "Database Backup", "0 4 * * *", now.AddDays(-1).AddHours(-1).ToString("O"), now.AddDays(1).AddHours(4).ToString("O"), "completed"), new("model-routing-refresh", "Model Routing Refresh", "*/30 * * * *", now.AddMinutes(-12).ToString("O"), now.AddMinutes(18).ToString("O"), "running") ]; } private static IReadOnlyList BuildFallbackUpcomingJobs() { var now = DateTimeOffset.UtcNow; return [ new("health-check", "Health Check", now.AddMinutes(2).ToString("O"), "*/5 * * * *"), new("model-routing-refresh", "Model Routing Refresh", now.AddMinutes(18).ToString("O"), "*/30 * * * *"), new("memory-sync", "Memory Sync", now.AddHours(4).ToString("O"), "0 */6 * * *"), new("task-cleanup", "Task Cleanup", now.AddDays(1).AddHours(3).ToString("O"), "0 3 * * *"), new("backup", "Database Backup", now.AddDays(1).AddHours(4).ToString("O"), "0 4 * * *") ]; } }