Add TileProvision configuration and gRPC service for tile delivery
ci/woodpecker/push/01-test Pipeline failed
ci/woodpecker/push/02-build-push unknown status

- Introduced new TileProvision settings in appsettings.json, including MaxTilesPerBatch and ProgressEmitIntervalSeconds.
- Configured TileProvisionConfig in Program.cs to bind the new settings.
- Added gRPC service for RouteTileDelivery in Program.cs to handle tile delivery requests.
- Updated SatelliteProvider.Api.csproj to include Grpc.AspNetCore package and added protobuf file for tile provision.
- Enhanced AuthenticationServiceCollectionExtensions to handle JWT token extraction from the Authorization header.
- Registered additional services in RouteManagementServiceCollectionExtensions for tile processing.

These changes enhance the API's capability to manage tile provisioning and delivery efficiently.
This commit is contained in:
Oleksandr Bezdieniezhnykh
2026-06-23 13:18:59 +03:00
parent 62d6b8310a
commit 275ee1b554
22 changed files with 1469 additions and 3 deletions
@@ -0,0 +1,116 @@
using Microsoft.Extensions.Options;
using SatelliteProvider.Common.Configs;
using SatelliteProvider.Common.DTO;
using SatelliteProvider.Common.Utils;
namespace SatelliteProvider.Services.RouteManagement.TileProvision;
public sealed class RouteTileExpander
{
private readonly RoutePointGraphBuilder _pointGraphBuilder;
private readonly GeofenceGridCalculator _geofenceGridCalculator;
public RouteTileExpander(
RoutePointGraphBuilder pointGraphBuilder,
GeofenceGridCalculator geofenceGridCalculator)
{
_pointGraphBuilder = pointGraphBuilder;
_geofenceGridCalculator = geofenceGridCalculator;
}
public IReadOnlyList<RouteTileCandidate> Expand(
IReadOnlyList<(double Lat, double Lon)> waypoints,
double regionSizeMeters,
int zoom,
IReadOnlyList<IReadOnlyList<(double Lat, double Lon)>> geofenceVertices,
bool includeGeofenceTiles)
{
if (waypoints.Count < 2)
{
throw new ArgumentException("Route must have at least 2 waypoints", nameof(waypoints));
}
if (regionSizeMeters <= 0)
{
throw new ArgumentOutOfRangeException(nameof(regionSizeMeters), "Region size must be positive");
}
var routePoints = waypoints
.Select(w => new RoutePoint { Latitude = w.Lat, Longitude = w.Lon })
.ToList();
var graph = _pointGraphBuilder.Build(routePoints);
var tiles = new Dictionary<(int Z, int X, int Y), uint>();
for (var priority = 0; priority < graph.Points.Count; priority++)
{
var point = graph.Points[priority];
AddCorridorTiles(
tiles,
new GeoPoint(point.Latitude, point.Longitude),
regionSizeMeters,
zoom,
(uint)priority);
}
if (includeGeofenceTiles)
{
var geofencePriority = (uint)graph.Points.Count;
foreach (var vertices in geofenceVertices)
{
if (vertices.Count < 3)
{
continue;
}
var minLat = vertices.Min(v => v.Lat);
var maxLat = vertices.Max(v => v.Lat);
var minLon = vertices.Min(v => v.Lon);
var maxLon = vertices.Max(v => v.Lon);
var northWest = new GeoPoint(maxLat, minLon);
var southEast = new GeoPoint(minLat, maxLon);
var centers = _geofenceGridCalculator.GenerateRegions(northWest, southEast, regionSizeMeters);
foreach (var center in centers)
{
AddCorridorTiles(tiles, center, regionSizeMeters, zoom, geofencePriority);
}
geofencePriority++;
}
}
return tiles
.OrderBy(t => t.Value)
.ThenBy(t => t.Key.Y)
.ThenBy(t => t.Key.X)
.Select(t => new RouteTileCandidate(t.Key.Z, t.Key.X, t.Key.Y, t.Value))
.ToList();
}
private static void AddCorridorTiles(
Dictionary<(int Z, int X, int Y), uint> tiles,
GeoPoint center,
double regionSizeMeters,
int zoom,
uint routePriority)
{
var radiusMeters = regionSizeMeters / 2.0;
var (latMin, latMax, lonMin, lonMax) = GeoUtils.GetBoundingBox(center, radiusMeters);
var (xMin, yMin) = GeoUtils.WorldToTilePos(new GeoPoint(latMax, lonMin), zoom);
var (xMax, yMax) = GeoUtils.WorldToTilePos(new GeoPoint(latMin, lonMax), zoom);
for (var y = yMin; y <= yMax; y++)
{
for (var x = xMin; x <= xMax; x++)
{
var key = (zoom, x, y);
if (!tiles.TryGetValue(key, out var existing) || routePriority < existing)
{
tiles[key] = routePriority;
}
}
}
}
}