Files
satellite-provider/SatelliteProvider.Services.RouteManagement/RouteValidator.cs
T
Oleksandr Bezdieniezhnykh 1dcd089d39 [AZ-371] Refactor C18: magic numbers to ProcessingConfig/MapConfig
Promotes 8 operational levers into config keys with defaults that match
the prior source literals byte-for-byte:
  ProcessingConfig: RegionProcessingTimeoutSeconds (300),
  RouteProcessingPollIntervalSeconds (5),
  MaxRoutePointSpacingMeters (200), LatLonTolerance (0.0001).
  MapConfig: TileSizePixels (256), AllowedZoomLevels ([15..19]),
  RetryBaseDelaySeconds (1), RetryMaxDelaySeconds (30).

Sites updated: RegionService, RouteProcessingService,
RoutePointGraphBuilder, RouteValidator, RouteService 4-arg ctor,
RouteImageRenderer, GoogleMapsDownloaderV2, TileService. Closes LF-2 by
forwarding HttpContext.RequestAborted from GetTileByLatLon into the
downloader. appsettings.json gains the 8 new keys at default values.

Tests: 141 / 141 unit + 5 / 5 smoke green. New ConfigDefaultsTests pins
defaults to original literals; new TileService unit test asserts CT
identity from caller to downloader (AZ-371 AC-3).

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-11 03:30:07 +03:00

83 lines
2.4 KiB
C#

using Microsoft.Extensions.Options;
using SatelliteProvider.Common.Configs;
using SatelliteProvider.Common.DTO;
namespace SatelliteProvider.Services.RouteManagement;
public class RouteValidator
{
private readonly double _latLonTolerance;
public RouteValidator(IOptions<ProcessingConfig> processingConfig)
{
ArgumentNullException.ThrowIfNull(processingConfig);
_latLonTolerance = processingConfig.Value.LatLonTolerance;
}
public void Validate(CreateRouteRequest request)
{
ArgumentNullException.ThrowIfNull(request);
var errors = new List<string>();
if (request.Points is null || request.Points.Count < 2)
{
errors.Add("Route must have at least 2 points");
}
if (request.RegionSizeMeters < 100 || request.RegionSizeMeters > 10000)
{
errors.Add("Region size must be between 100 and 10000 meters");
}
if (string.IsNullOrWhiteSpace(request.Name))
{
errors.Add("Route name is required");
}
if (request.Geofences?.Polygons is { Count: > 0 } polygons)
{
for (int i = 0; i < polygons.Count; i++)
{
ValidatePolygon(polygons[i], errors);
}
}
if (errors.Count > 0)
{
throw new ArgumentException(string.Join("; ", errors));
}
}
private void ValidatePolygon(GeofencePolygon polygon, List<string> errors)
{
if (polygon.NorthWest is null || polygon.SouthEast is null)
{
errors.Add("Geofence polygon coordinates are required");
return;
}
var nw = polygon.NorthWest;
var se = polygon.SouthEast;
if ((Math.Abs(nw.Lat) < _latLonTolerance && Math.Abs(nw.Lon) < _latLonTolerance) ||
(Math.Abs(se.Lat) < _latLonTolerance && Math.Abs(se.Lon) < _latLonTolerance))
{
errors.Add("Geofence polygon coordinates cannot be (0,0)");
}
if (nw.Lat < -90 || nw.Lat > 90 ||
se.Lat < -90 || se.Lat > 90 ||
nw.Lon < -180 || nw.Lon > 180 ||
se.Lon < -180 || se.Lon > 180)
{
errors.Add("Geofence polygon coordinates must be valid (lat: -90 to 90, lon: -180 to 180)");
}
if (nw.Lat <= se.Lat)
{
errors.Add("Geofence northWest latitude must be greater than southEast latitude");
}
}
}