aboutsummaryrefslogtreecommitdiff
path: root/src/Enmarcha.Backend/Controllers/RoutePlannerController.cs
diff options
context:
space:
mode:
authorAriel Costas Guerrero <ariel@costas.dev>2026-03-21 00:36:25 +0100
committerAriel Costas Guerrero <ariel@costas.dev>2026-03-21 00:36:25 +0100
commitf1b0b5f7ceaf6d23ae347e12cf29eef617c7dc9b (patch)
treed92c6075d019d87fd03482774050d7fc8981a5aa /src/Enmarcha.Backend/Controllers/RoutePlannerController.cs
parent2ef155c0c68208eccf968919fea12133698b50a9 (diff)
feat: enhance geocoding and stop search with performance metrics and improved response handling
Diffstat (limited to 'src/Enmarcha.Backend/Controllers/RoutePlannerController.cs')
-rw-r--r--src/Enmarcha.Backend/Controllers/RoutePlannerController.cs64
1 files changed, 43 insertions, 21 deletions
diff --git a/src/Enmarcha.Backend/Controllers/RoutePlannerController.cs b/src/Enmarcha.Backend/Controllers/RoutePlannerController.cs
index 489f264..426170d 100644
--- a/src/Enmarcha.Backend/Controllers/RoutePlannerController.cs
+++ b/src/Enmarcha.Backend/Controllers/RoutePlannerController.cs
@@ -53,16 +53,45 @@ public partial class RoutePlannerController : ControllerBase
return BadRequest("Query cannot be empty");
}
- var nominatimTask = _geocodingService.GetAutocompleteAsync(query);
- var stopsTask = GetCachedStopsAsync();
+ DateTime startTime = DateTime.UtcNow;
+ var geocodingTask = _geocodingService.GetAutocompleteAsync(query).ContinueWith(t =>
+ {
+ var duration = DateTime.UtcNow - startTime;
+ Response.Headers.Append("Server-Timing", $"geocoding;dur={(int)duration.TotalMilliseconds}");
+ return t.Result;
+ });
+ var stopTask = SearchStops(query).ContinueWith(t =>
+ {
+ var duration = DateTime.UtcNow - startTime;
+ Response.Headers.Append("Server-Timing", $"stop_search;dur={(int)duration.TotalMilliseconds}");
+ return t.Result;
+ });
+
+ await Task.WhenAll(geocodingTask, stopTask);
+
+ var geocodingResults = await geocodingTask;
+ var stopResults = await stopTask;
+
+ // Merge results: geocoding first, then stops, deduplicating by coordinates (approx)
+ var finalResults = new List<PlannerSearchResult>(geocodingResults);
+
+ foreach (var res in stopResults)
+ {
+ if (!finalResults.Any(f => Math.Abs(f.Lat - res.Lat) < 0.0001 && Math.Abs(f.Lon - res.Lon) < 0.0001))
+ {
+ finalResults.Add(res);
+ }
+ }
- await Task.WhenAll(nominatimTask, stopsTask);
+ return Ok(finalResults);
+ }
- var geocodingResults = await nominatimTask;
- var allStops = await stopsTask;
+ private async Task<List<PlannerSearchResult>> SearchStops(string query)
+ {
+ var stops = await GetCachedStopsAsync();
// 1. Exact or prefix matches by stop code
- var codeMatches = allStops
+ var codeMatches = stops
.Where(s => s.StopCode != null && s.StopCode.StartsWith(query, StringComparison.OrdinalIgnoreCase))
.OrderBy(s => s.StopCode?.Length) // Shorter codes (more exact matches) first
.Take(5)
@@ -71,9 +100,13 @@ public partial class RoutePlannerController : ControllerBase
// 2. Fuzzy search stops by label (Name + Code)
var fuzzyResults = Process.ExtractSorted(
query,
- allStops.Select(s => s.Label ?? string.Empty),
+ stops.Select(s => s.Label ?? string.Empty),
cutoff: 60
- ).Take(6).Select(r => allStops[r.Index]).ToList();
+ )
+ .OrderByDescending(r => r.Score)
+ .Take(6)
+ .Select(r => stops[r.Index])
+ .ToList();
// Merge stops, prioritizing code matches
var stopResults = codeMatches.Concat(fuzzyResults)
@@ -82,18 +115,7 @@ public partial class RoutePlannerController : ControllerBase
.Take(6)
.ToList();
- // Merge results: geocoding first, then stops, deduplicating by coordinates (approx)
- var finalResults = new List<PlannerSearchResult>(geocodingResults);
-
- foreach (var res in stopResults)
- {
- if (!finalResults.Any(f => Math.Abs(f.Lat - res.Lat) < 0.00001 && Math.Abs(f.Lon - res.Lon) < 0.00001))
- {
- finalResults.Add(res);
- }
- }
-
- return Ok(finalResults);
+ return stopResults;
}
[HttpGet("reverse")]
@@ -169,7 +191,7 @@ public partial class RoutePlannerController : ControllerBase
return new PlannerSearchResult
{
Name = name,
- Label = string.IsNullOrWhiteSpace(code) ? name : $"{name} ({code})",
+ Label = string.IsNullOrWhiteSpace(code) ? name : $"{name} ({feedId} {code}) -- {s.Desc}",
Lat = s.Lat,
Lon = s.Lon,
Layer = "stop",