using System.Text.Json; using PlanTempusAdmin.Models; namespace PlanTempusAdmin.Services; public class CaddyService { private readonly HttpClient _httpClient; private readonly ILogger _logger; private readonly string _caddyAdminUrl; public CaddyService(HttpClient httpClient, ILogger logger, IConfiguration configuration) { _httpClient = httpClient; _logger = logger; _caddyAdminUrl = configuration.GetValue("Caddy:AdminUrl") ?? "http://localhost:2019"; } public async Task IsRunningAsync() { try { var response = await _httpClient.GetAsync($"{_caddyAdminUrl}/config/"); return response.IsSuccessStatusCode; } catch (Exception ex) { _logger.LogWarning(ex, "Could not connect to Caddy Admin API"); return false; } } public async Task GetConfigAsync() { try { var response = await _httpClient.GetAsync($"{_caddyAdminUrl}/config/"); if (!response.IsSuccessStatusCode) { return null; } var json = await response.Content.ReadAsStringAsync(); var options = new JsonSerializerOptions { PropertyNameCaseInsensitive = true }; return JsonSerializer.Deserialize(json, options); } catch (Exception ex) { _logger.LogError(ex, "Error fetching Caddy config"); return null; } } public async Task> GetHostsAsync() { var hosts = new List(); try { var config = await GetConfigAsync(); if (config?.Apps?.Http?.Servers == null) { return hosts; } foreach (var server in config.Apps.Http.Servers.Values) { if (server.Routes == null) continue; foreach (var route in server.Routes) { if (route.Match == null) continue; foreach (var match in route.Match) { if (match.Host == null) continue; foreach (var hostname in match.Host) { var host = new CaddyHost { Hostname = hostname, Addresses = server.Listen ?? Array.Empty(), Tls = server.Listen?.Any(l => l.Contains(":443")) ?? false }; // Try to get upstream from handlers if (route.Handle != null) { var reverseProxy = route.Handle.FirstOrDefault(h => h.Handler == "reverse_proxy"); if (reverseProxy?.Upstreams?.Length > 0) { host.Upstream = reverseProxy.Upstreams[0].Dial; } } hosts.Add(host); } } } } } catch (Exception ex) { _logger.LogError(ex, "Error parsing Caddy hosts"); } return hosts; } public async Task GetRawConfigAsync() { try { var response = await _httpClient.GetAsync($"{_caddyAdminUrl}/config/"); if (!response.IsSuccessStatusCode) { return null; } return await response.Content.ReadAsStringAsync(); } catch (Exception ex) { _logger.LogError(ex, "Error fetching raw Caddy config"); return null; } } }