using Flurl.Http; using Newtonsoft.Json.Linq; namespace InnovEnergy.App.Backend.Services; /// /// Fetches and caches the list of Swiss electricity network providers (Netzbetreiber) /// from the ELCOM/LINDAS SPARQL endpoint. Refreshes every 24 hours. /// public static class NetworkProviderService { private static IReadOnlyList _providers = Array.Empty(); private static Timer? _refreshTimer; private const string SparqlEndpoint = "https://ld.admin.ch/query"; private const string SparqlQuery = @" PREFIX schema: SELECT DISTINCT ?name FROM WHERE { ?operator a schema:Organization ; schema:name ?name . } ORDER BY ?name"; public static void Initialize() { // Fire-and-forget initial load Task.Run(RefreshAsync); // Refresh every 24 hours _refreshTimer = new Timer( _ => Task.Run(RefreshAsync), null, TimeSpan.FromHours(24), TimeSpan.FromHours(24) ); Console.WriteLine("[NetworkProviderService] initialised."); } public static IReadOnlyList GetProviders() => _providers; private static async Task RefreshAsync() { try { var response = await SparqlEndpoint .WithHeader("Accept", "application/sparql-results+json") .PostUrlEncodedAsync(new { query = SparqlQuery }); var json = await response.GetStringAsync(); var parsed = JObject.Parse(json); var names = parsed["results"]?["bindings"]? .Select(b => b["name"]?["value"]?.ToString()) .Where(n => !string.IsNullOrWhiteSpace(n)) .Distinct() .OrderBy(n => n) .ToList(); if (names is { Count: > 0 }) { _providers = names!; Console.WriteLine($"[NetworkProviderService] Loaded {names.Count} providers from ELCOM."); } else { Console.Error.WriteLine("[NetworkProviderService] SPARQL query returned no results."); } } catch (Exception ex) { Console.Error.WriteLine($"[NetworkProviderService] Failed to fetch providers: {ex.Message}"); } } }