From a304c24b32c0327436bbd8c2853e60668e161b42 Mon Sep 17 00:00:00 2001 From: Ariel Costas Guerrero Date: Mon, 29 Dec 2025 00:41:52 +0100 Subject: Rename a lot of stuff, add Santiago real time --- .../Processors/SantiagoRealTimeProcessor.cs | 88 ++++++++++++++++++++++ 1 file changed, 88 insertions(+) create mode 100644 src/Enmarcha.Backend/Services/Processors/SantiagoRealTimeProcessor.cs (limited to 'src/Enmarcha.Backend/Services/Processors/SantiagoRealTimeProcessor.cs') diff --git a/src/Enmarcha.Backend/Services/Processors/SantiagoRealTimeProcessor.cs b/src/Enmarcha.Backend/Services/Processors/SantiagoRealTimeProcessor.cs new file mode 100644 index 0000000..28b38a9 --- /dev/null +++ b/src/Enmarcha.Backend/Services/Processors/SantiagoRealTimeProcessor.cs @@ -0,0 +1,88 @@ +using Enmarcha.Sources.OpenTripPlannerGql.Queries; +using Enmarcha.Sources.TranviasCoruna; +using Enmarcha.Backend.Types; +using Enmarcha.Backend.Types.Arrivals; +using Enmarcha.Sources.Tussa; +using Arrival = Enmarcha.Backend.Types.Arrivals.Arrival; + +namespace Enmarcha.Backend.Services.Processors; + +public class SantiagoRealTimeProcessor : AbstractRealTimeProcessor +{ + private readonly SantiagoRealtimeEstimatesProvider _realtime; + private readonly FeedService _feedService; + private readonly ILogger _logger; + + public SantiagoRealTimeProcessor( + HttpClient http, + FeedService feedService, + ILogger logger) + { + _realtime = new SantiagoRealtimeEstimatesProvider(http); + _feedService = feedService; + _logger = logger; + } + + public override async Task ProcessAsync(ArrivalsContext context) + { + if (!context.StopId.StartsWith("tussa:")) return; + + var normalizedCode = _feedService.NormalizeStopCode("tussa", context.StopCode); + if (!int.TryParse(normalizedCode, out var numericStopId)) return; + + try + { + var realtime = await _realtime.GetEstimatesForStop(numericStopId); + + var usedTripIds = new HashSet(); + var newArrivals = new List(); + + foreach (var estimate in realtime) + { + var bestMatch = context.Arrivals + .Where(a => !usedTripIds.Contains(a.TripId)) + .Where(a => a.Route.RouteIdInGtfs.Trim() == estimate.RouteId.Trim()) + .Select(a => + { + return new + { + Arrival = a, + TimeDiff = estimate.Minutes - a.Estimate.Minutes, // RealTime - Schedule + RouteMatch = true + }; + }) + .Where(x => x.RouteMatch) // Strict route matching + .Where(x => x.TimeDiff >= -7 && x.TimeDiff <= 75) // Allow 7m early (RealTime < Schedule) or 75m late (RealTime > Schedule) + .OrderBy(x => Math.Abs(x.TimeDiff)) // Best time fit + .FirstOrDefault(); + + if (bestMatch == null) + { + continue; + } + + var arrival = bestMatch.Arrival; + + var scheduledMinutes = arrival.Estimate.Minutes; + arrival.Estimate.Minutes = estimate.Minutes; + arrival.Estimate.Precision = ArrivalPrecision.Confident; + + // Calculate delay badge + var delayMinutes = estimate.Minutes - scheduledMinutes; + if (delayMinutes != 0) + { + arrival.Delay = new DelayBadge { Minutes = delayMinutes }; + } + + usedTripIds.Add(arrival.TripId); + } + + context.Arrivals.AddRange(newArrivals); + } + catch (Exception ex) + { + _logger.LogError(ex, "Error fetching Vitrasa real-time data for stop {StopId}", context.StopId); + } + } + +} -- cgit v1.3