v-20260916a
- restaurar derivaciones - añadido la pedida de anchura de calles y cariiles - correcion paradas bus - desglose del score - historial no cambia la hora - resuarar no cambia modo de historial
This commit is contained in:
136
RutasDBUS/Servicios/Caminata/ClienteAtributosOsm.cs
Normal file
136
RutasDBUS/Servicios/Caminata/ClienteAtributosOsm.cs
Normal file
@@ -0,0 +1,136 @@
|
||||
using System.Net.Http.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
using Microsoft.Extensions.Caching.Memory;
|
||||
|
||||
namespace RutasDBUS.Servicios.Caminata;
|
||||
|
||||
public sealed class ClienteAtributosOsm : IClienteAtributosOsm
|
||||
{
|
||||
private const int MaximoCaminosPorConsulta = 100;
|
||||
private readonly HttpClient _httpClient;
|
||||
private readonly IMemoryCache _cache;
|
||||
private readonly string _baseUrl;
|
||||
|
||||
public ClienteAtributosOsm(
|
||||
HttpClient httpClient,
|
||||
IMemoryCache cache,
|
||||
IConfiguration configuracion)
|
||||
{
|
||||
_httpClient = httpClient;
|
||||
_cache = cache;
|
||||
_baseUrl = (configuracion["Caminata:Osm:BaseUrl"]
|
||||
?? "https://api.openstreetmap.org/api/0.6").Trim().TrimEnd('/');
|
||||
}
|
||||
|
||||
public async Task<IReadOnlyDictionary<long, AnchuraViaOsm>> ObtenerAnchurasAsync(
|
||||
IEnumerable<long> idsCamino,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
var ids = idsCamino
|
||||
.Where(id => id > 0)
|
||||
.Distinct()
|
||||
.Take(MaximoCaminosPorConsulta)
|
||||
.ToList();
|
||||
|
||||
var resultado = new Dictionary<long, AnchuraViaOsm>();
|
||||
var pendientes = new List<long>();
|
||||
foreach (var id in ids)
|
||||
{
|
||||
if (_cache.TryGetValue<ResultadoAnchuraCache>(ClaveCache(id), out var cacheado))
|
||||
{
|
||||
if (cacheado?.Dato is not null)
|
||||
resultado[id] = cacheado.Dato;
|
||||
}
|
||||
else
|
||||
{
|
||||
pendientes.Add(id);
|
||||
}
|
||||
}
|
||||
|
||||
if (pendientes.Count == 0)
|
||||
return resultado;
|
||||
|
||||
try
|
||||
{
|
||||
using var timeout = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken);
|
||||
timeout.CancelAfter(TimeSpan.FromSeconds(4));
|
||||
|
||||
var idsConsulta = string.Join(',', pendientes);
|
||||
using var peticion = new HttpRequestMessage(
|
||||
HttpMethod.Get,
|
||||
$"{_baseUrl}/ways.json?ways={Uri.EscapeDataString(idsConsulta)}");
|
||||
peticion.Headers.UserAgent.ParseAdd("RutasDBUS/1.0");
|
||||
|
||||
using var respuesta = await _httpClient.SendAsync(peticion, timeout.Token);
|
||||
if (!respuesta.IsSuccessStatusCode)
|
||||
return resultado;
|
||||
|
||||
var datos = await respuesta.Content.ReadFromJsonAsync<RespuestaOsm>(timeout.Token);
|
||||
var encontrados = new HashSet<long>();
|
||||
foreach (var elemento in datos?.Elementos ?? [])
|
||||
{
|
||||
encontrados.Add(elemento.Id);
|
||||
var anchura = ObtenerAnchura(elemento.Etiquetas);
|
||||
GuardarCache(elemento.Id, anchura);
|
||||
if (anchura is not null)
|
||||
resultado[elemento.Id] = anchura;
|
||||
}
|
||||
|
||||
foreach (var id in pendientes.Where(id => !encontrados.Contains(id)))
|
||||
GuardarCache(id, null);
|
||||
}
|
||||
catch (OperationCanceledException) when (!cancellationToken.IsCancellationRequested)
|
||||
{
|
||||
// La anchura es informativa: un timeout no debe bloquear el tooltip.
|
||||
}
|
||||
catch (HttpRequestException)
|
||||
{
|
||||
// La información principal de v2 sigue siendo válida si OSM no responde.
|
||||
}
|
||||
catch (System.Text.Json.JsonException)
|
||||
{
|
||||
// Una respuesta no válida tampoco debe ocultar la información principal de v2.
|
||||
}
|
||||
|
||||
return resultado;
|
||||
}
|
||||
|
||||
private void GuardarCache(long id, AnchuraViaOsm? dato)
|
||||
=> _cache.Set(
|
||||
ClaveCache(id),
|
||||
new ResultadoAnchuraCache(dato),
|
||||
dato is null ? TimeSpan.FromHours(6) : TimeSpan.FromDays(1));
|
||||
|
||||
private static AnchuraViaOsm? ObtenerAnchura(Dictionary<string, string>? etiquetas)
|
||||
{
|
||||
if (etiquetas is null)
|
||||
return null;
|
||||
|
||||
if (etiquetas.TryGetValue("width", out var anchura) && !string.IsNullOrWhiteSpace(anchura))
|
||||
return new AnchuraViaOsm(anchura.Trim(), false);
|
||||
|
||||
if (etiquetas.TryGetValue("est_width", out var estimada) && !string.IsNullOrWhiteSpace(estimada))
|
||||
return new AnchuraViaOsm(estimada.Trim(), true);
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private static string ClaveCache(long id) => $"osm:anchura:{id}";
|
||||
|
||||
private sealed record ResultadoAnchuraCache(AnchuraViaOsm? Dato);
|
||||
|
||||
private sealed class RespuestaOsm
|
||||
{
|
||||
[JsonPropertyName("elements")]
|
||||
public List<ElementoOsm>? Elementos { get; set; }
|
||||
}
|
||||
|
||||
private sealed class ElementoOsm
|
||||
{
|
||||
[JsonPropertyName("id")]
|
||||
public long Id { get; set; }
|
||||
|
||||
[JsonPropertyName("tags")]
|
||||
public Dictionary<string, string>? Etiquetas { get; set; }
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user