mirror of
https://github.com/azaion/satellite-provider.git
synced 2026-04-22 09:16:39 +00:00
zip file for tiles
This commit is contained in:
@@ -16,5 +16,6 @@ public class CreateRouteRequest
|
|||||||
public Geofences? Geofences { get; set; }
|
public Geofences? Geofences { get; set; }
|
||||||
|
|
||||||
public bool RequestMaps { get; set; } = false;
|
public bool RequestMaps { get; set; } = false;
|
||||||
|
public bool CreateTilesZip { get; set; } = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ public class RouteResponse
|
|||||||
public string? CsvFilePath { get; set; }
|
public string? CsvFilePath { get; set; }
|
||||||
public string? SummaryFilePath { get; set; }
|
public string? SummaryFilePath { get; set; }
|
||||||
public string? StitchedImagePath { get; set; }
|
public string? StitchedImagePath { get; set; }
|
||||||
|
public string? TilesZipPath { get; set; }
|
||||||
public DateTime CreatedAt { get; set; }
|
public DateTime CreatedAt { get; set; }
|
||||||
public DateTime UpdatedAt { get; set; }
|
public DateTime UpdatedAt { get; set; }
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,4 @@
|
|||||||
|
ALTER TABLE routes
|
||||||
|
ADD COLUMN create_tiles_zip BOOLEAN NOT NULL DEFAULT FALSE,
|
||||||
|
ADD COLUMN tiles_zip_path VARCHAR(500);
|
||||||
|
|
||||||
@@ -11,9 +11,11 @@ public class RouteEntity
|
|||||||
public int TotalPoints { get; set; }
|
public int TotalPoints { get; set; }
|
||||||
public bool RequestMaps { get; set; }
|
public bool RequestMaps { get; set; }
|
||||||
public bool MapsReady { get; set; }
|
public bool MapsReady { get; set; }
|
||||||
|
public bool CreateTilesZip { get; set; }
|
||||||
public string? CsvFilePath { get; set; }
|
public string? CsvFilePath { get; set; }
|
||||||
public string? SummaryFilePath { get; set; }
|
public string? SummaryFilePath { get; set; }
|
||||||
public string? StitchedImagePath { get; set; }
|
public string? StitchedImagePath { get; set; }
|
||||||
|
public string? TilesZipPath { get; set; }
|
||||||
public DateTime CreatedAt { get; set; }
|
public DateTime CreatedAt { get; set; }
|
||||||
public DateTime UpdatedAt { get; set; }
|
public DateTime UpdatedAt { get; set; }
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,8 +23,10 @@ public class RouteRepository : IRouteRepository
|
|||||||
SELECT id, name, description, region_size_meters as RegionSizeMeters,
|
SELECT id, name, description, region_size_meters as RegionSizeMeters,
|
||||||
zoom_level as ZoomLevel, total_distance_meters as TotalDistanceMeters,
|
zoom_level as ZoomLevel, total_distance_meters as TotalDistanceMeters,
|
||||||
total_points as TotalPoints, request_maps as RequestMaps,
|
total_points as TotalPoints, request_maps as RequestMaps,
|
||||||
maps_ready as MapsReady, csv_file_path as CsvFilePath,
|
maps_ready as MapsReady, create_tiles_zip as CreateTilesZip,
|
||||||
|
csv_file_path as CsvFilePath,
|
||||||
summary_file_path as SummaryFilePath, stitched_image_path as StitchedImagePath,
|
summary_file_path as SummaryFilePath, stitched_image_path as StitchedImagePath,
|
||||||
|
tiles_zip_path as TilesZipPath,
|
||||||
created_at as CreatedAt, updated_at as UpdatedAt
|
created_at as CreatedAt, updated_at as UpdatedAt
|
||||||
FROM routes
|
FROM routes
|
||||||
WHERE id = @Id";
|
WHERE id = @Id";
|
||||||
@@ -53,12 +55,12 @@ public class RouteRepository : IRouteRepository
|
|||||||
const string sql = @"
|
const string sql = @"
|
||||||
INSERT INTO routes (id, name, description, region_size_meters, zoom_level,
|
INSERT INTO routes (id, name, description, region_size_meters, zoom_level,
|
||||||
total_distance_meters, total_points, request_maps, maps_ready,
|
total_distance_meters, total_points, request_maps, maps_ready,
|
||||||
csv_file_path, summary_file_path, stitched_image_path,
|
create_tiles_zip, csv_file_path, summary_file_path, stitched_image_path,
|
||||||
created_at, updated_at)
|
tiles_zip_path, created_at, updated_at)
|
||||||
VALUES (@Id, @Name, @Description, @RegionSizeMeters, @ZoomLevel,
|
VALUES (@Id, @Name, @Description, @RegionSizeMeters, @ZoomLevel,
|
||||||
@TotalDistanceMeters, @TotalPoints, @RequestMaps, @MapsReady,
|
@TotalDistanceMeters, @TotalPoints, @RequestMaps, @MapsReady,
|
||||||
@CsvFilePath, @SummaryFilePath, @StitchedImagePath,
|
@CreateTilesZip, @CsvFilePath, @SummaryFilePath, @StitchedImagePath,
|
||||||
@CreatedAt, @UpdatedAt)
|
@TilesZipPath, @CreatedAt, @UpdatedAt)
|
||||||
RETURNING id";
|
RETURNING id";
|
||||||
|
|
||||||
return await connection.ExecuteScalarAsync<Guid>(sql, route);
|
return await connection.ExecuteScalarAsync<Guid>(sql, route);
|
||||||
@@ -90,9 +92,11 @@ public class RouteRepository : IRouteRepository
|
|||||||
total_points = @TotalPoints,
|
total_points = @TotalPoints,
|
||||||
request_maps = @RequestMaps,
|
request_maps = @RequestMaps,
|
||||||
maps_ready = @MapsReady,
|
maps_ready = @MapsReady,
|
||||||
|
create_tiles_zip = @CreateTilesZip,
|
||||||
csv_file_path = @CsvFilePath,
|
csv_file_path = @CsvFilePath,
|
||||||
summary_file_path = @SummaryFilePath,
|
summary_file_path = @SummaryFilePath,
|
||||||
stitched_image_path = @StitchedImagePath,
|
stitched_image_path = @StitchedImagePath,
|
||||||
|
tiles_zip_path = @TilesZipPath,
|
||||||
updated_at = @UpdatedAt
|
updated_at = @UpdatedAt
|
||||||
WHERE id = @Id";
|
WHERE id = @Id";
|
||||||
|
|
||||||
@@ -146,8 +150,10 @@ public class RouteRepository : IRouteRepository
|
|||||||
SELECT id, name, description, region_size_meters as RegionSizeMeters,
|
SELECT id, name, description, region_size_meters as RegionSizeMeters,
|
||||||
zoom_level as ZoomLevel, total_distance_meters as TotalDistanceMeters,
|
zoom_level as ZoomLevel, total_distance_meters as TotalDistanceMeters,
|
||||||
total_points as TotalPoints, request_maps as RequestMaps,
|
total_points as TotalPoints, request_maps as RequestMaps,
|
||||||
maps_ready as MapsReady, csv_file_path as CsvFilePath,
|
maps_ready as MapsReady, create_tiles_zip as CreateTilesZip,
|
||||||
|
csv_file_path as CsvFilePath,
|
||||||
summary_file_path as SummaryFilePath, stitched_image_path as StitchedImagePath,
|
summary_file_path as SummaryFilePath, stitched_image_path as StitchedImagePath,
|
||||||
|
tiles_zip_path as TilesZipPath,
|
||||||
created_at as CreatedAt, updated_at as UpdatedAt
|
created_at as CreatedAt, updated_at as UpdatedAt
|
||||||
FROM routes
|
FROM routes
|
||||||
WHERE request_maps = true AND maps_ready = false";
|
WHERE request_maps = true AND maps_ready = false";
|
||||||
|
|||||||
@@ -78,6 +78,7 @@ public class CreateRouteRequest
|
|||||||
[System.Text.Json.Serialization.JsonPropertyName("geofences")]
|
[System.Text.Json.Serialization.JsonPropertyName("geofences")]
|
||||||
public GeofencesInput? Geofences { get; set; }
|
public GeofencesInput? Geofences { get; set; }
|
||||||
public bool RequestMaps { get; set; } = false;
|
public bool RequestMaps { get; set; } = false;
|
||||||
|
public bool CreateTilesZip { get; set; } = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public class RoutePointModel
|
public class RoutePointModel
|
||||||
@@ -105,6 +106,7 @@ public class RouteResponseModel
|
|||||||
public string? CsvFilePath { get; set; }
|
public string? CsvFilePath { get; set; }
|
||||||
public string? SummaryFilePath { get; set; }
|
public string? SummaryFilePath { get; set; }
|
||||||
public string? StitchedImagePath { get; set; }
|
public string? StitchedImagePath { get; set; }
|
||||||
|
public string? TilesZipPath { get; set; }
|
||||||
public DateTime CreatedAt { get; set; }
|
public DateTime CreatedAt { get; set; }
|
||||||
public DateTime UpdatedAt { get; set; }
|
public DateTime UpdatedAt { get; set; }
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -36,6 +36,8 @@ class Program
|
|||||||
|
|
||||||
await RouteTests.RunRouteWithRegionProcessingAndStitching(httpClient);
|
await RouteTests.RunRouteWithRegionProcessingAndStitching(httpClient);
|
||||||
|
|
||||||
|
await RouteTests.RunRouteWithTilesZipTest(httpClient);
|
||||||
|
|
||||||
await RouteTests.RunComplexRouteWithStitching(httpClient);
|
await RouteTests.RunComplexRouteWithStitching(httpClient);
|
||||||
await RouteTests.RunComplexRouteWithStitchingAndGeofences(httpClient);
|
await RouteTests.RunComplexRouteWithStitchingAndGeofences(httpClient);
|
||||||
await RouteTests.RunExtendedRouteEast(httpClient);
|
await RouteTests.RunExtendedRouteEast(httpClient);
|
||||||
|
|||||||
@@ -989,5 +989,220 @@ public static class RouteTests
|
|||||||
|
|
||||||
Console.WriteLine("✓ Extended Route with 20 Points (10km East) Test: PASSED");
|
Console.WriteLine("✓ Extended Route with 20 Points (10km East) Test: PASSED");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static async Task RunRouteWithTilesZipTest(HttpClient httpClient)
|
||||||
|
{
|
||||||
|
Console.WriteLine();
|
||||||
|
Console.WriteLine("Test: Route with Tiles ZIP File Creation");
|
||||||
|
Console.WriteLine("=========================================");
|
||||||
|
Console.WriteLine();
|
||||||
|
|
||||||
|
var routeId = Guid.NewGuid();
|
||||||
|
var request = new CreateRouteRequest
|
||||||
|
{
|
||||||
|
Id = routeId,
|
||||||
|
Name = "Route with Tiles ZIP",
|
||||||
|
Description = "Test route with tiles zip file creation",
|
||||||
|
RegionSizeMeters = 500.0,
|
||||||
|
ZoomLevel = 18,
|
||||||
|
RequestMaps = true,
|
||||||
|
CreateTilesZip = true,
|
||||||
|
Points = new List<RoutePointInput>
|
||||||
|
{
|
||||||
|
new() { Lat = 48.276067180586544, Lon = 37.38445758819581 },
|
||||||
|
new() { Lat = 48.27074009522731, Lon = 37.374029159545906 }
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Console.WriteLine($"Creating route with 2 points:");
|
||||||
|
Console.WriteLine($" Start: ({request.Points[0].Lat}, {request.Points[0].Lon})");
|
||||||
|
Console.WriteLine($" End: ({request.Points[1].Lat}, {request.Points[1].Lon})");
|
||||||
|
Console.WriteLine($" Region Size: {request.RegionSizeMeters}m");
|
||||||
|
Console.WriteLine($" Zoom Level: {request.ZoomLevel}");
|
||||||
|
Console.WriteLine($" Request Maps: {request.RequestMaps}");
|
||||||
|
Console.WriteLine($" Create Tiles ZIP: {request.CreateTilesZip}");
|
||||||
|
Console.WriteLine();
|
||||||
|
|
||||||
|
var response = await httpClient.PostAsJsonAsync("/api/satellite/route", request, JsonWriteOptions);
|
||||||
|
|
||||||
|
if (!response.IsSuccessStatusCode)
|
||||||
|
{
|
||||||
|
var errorContent = await response.Content.ReadAsStringAsync();
|
||||||
|
throw new Exception($"API returned error status {response.StatusCode}: {errorContent}");
|
||||||
|
}
|
||||||
|
|
||||||
|
var route = await response.Content.ReadFromJsonAsync<RouteResponseModel>(JsonOptions);
|
||||||
|
|
||||||
|
if (route == null)
|
||||||
|
{
|
||||||
|
throw new Exception("No route data returned from API");
|
||||||
|
}
|
||||||
|
|
||||||
|
Console.WriteLine("Route Details:");
|
||||||
|
Console.WriteLine($" ID: {route.Id}");
|
||||||
|
Console.WriteLine($" Name: {route.Name}");
|
||||||
|
Console.WriteLine($" Total Points: {route.TotalPoints}");
|
||||||
|
Console.WriteLine($" Total Distance: {route.TotalDistanceMeters:F2}m");
|
||||||
|
Console.WriteLine($" Request Maps: {route.RequestMaps}");
|
||||||
|
Console.WriteLine($" Maps Ready: {route.MapsReady}");
|
||||||
|
Console.WriteLine();
|
||||||
|
|
||||||
|
if (!route.RequestMaps)
|
||||||
|
{
|
||||||
|
throw new Exception("Expected RequestMaps to be true");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (route.MapsReady)
|
||||||
|
{
|
||||||
|
throw new Exception("Expected MapsReady to be false initially");
|
||||||
|
}
|
||||||
|
|
||||||
|
Console.WriteLine("Step 2: Waiting for route maps and zip file to be ready");
|
||||||
|
Console.WriteLine(" (Service is processing regions SEQUENTIALLY to avoid API throttling)");
|
||||||
|
Console.WriteLine();
|
||||||
|
|
||||||
|
RouteResponseModel? finalRoute = null;
|
||||||
|
int maxAttempts = 180;
|
||||||
|
int pollInterval = 3000;
|
||||||
|
|
||||||
|
for (int attempt = 0; attempt < maxAttempts; attempt++)
|
||||||
|
{
|
||||||
|
await Task.Delay(pollInterval);
|
||||||
|
|
||||||
|
var getResponse = await httpClient.GetAsync($"/api/satellite/route/{routeId}");
|
||||||
|
|
||||||
|
if (!getResponse.IsSuccessStatusCode)
|
||||||
|
{
|
||||||
|
throw new Exception($"Failed to get route status: {getResponse.StatusCode}");
|
||||||
|
}
|
||||||
|
|
||||||
|
var currentRoute = await getResponse.Content.ReadFromJsonAsync<RouteResponseModel>(JsonOptions);
|
||||||
|
|
||||||
|
if (currentRoute == null)
|
||||||
|
{
|
||||||
|
throw new Exception("No route returned");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (currentRoute.MapsReady)
|
||||||
|
{
|
||||||
|
finalRoute = currentRoute;
|
||||||
|
Console.WriteLine($"✓ Route maps ready in approximately {attempt * pollInterval / 1000}s");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (attempt % 5 == 0)
|
||||||
|
{
|
||||||
|
Console.WriteLine($" Waiting... (attempt {attempt + 1}/{maxAttempts})");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (attempt == maxAttempts - 1)
|
||||||
|
{
|
||||||
|
throw new Exception($"Timeout: Route maps did not become ready in {maxAttempts * pollInterval / 1000}s");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (finalRoute == null)
|
||||||
|
{
|
||||||
|
throw new Exception("Final route is null");
|
||||||
|
}
|
||||||
|
|
||||||
|
Console.WriteLine();
|
||||||
|
|
||||||
|
Console.WriteLine("Step 3: Verifying generated files including ZIP");
|
||||||
|
|
||||||
|
if (string.IsNullOrEmpty(finalRoute.CsvFilePath))
|
||||||
|
{
|
||||||
|
throw new Exception("CSV file path is null or empty");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (string.IsNullOrEmpty(finalRoute.SummaryFilePath))
|
||||||
|
{
|
||||||
|
throw new Exception("Summary file path is null or empty");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (string.IsNullOrEmpty(finalRoute.StitchedImagePath))
|
||||||
|
{
|
||||||
|
throw new Exception("Stitched image path is null or empty");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (string.IsNullOrEmpty(finalRoute.TilesZipPath))
|
||||||
|
{
|
||||||
|
throw new Exception("Tiles ZIP file path is null or empty");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!File.Exists(finalRoute.CsvFilePath))
|
||||||
|
{
|
||||||
|
throw new Exception($"CSV file not found: {finalRoute.CsvFilePath}");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!File.Exists(finalRoute.SummaryFilePath))
|
||||||
|
{
|
||||||
|
throw new Exception($"Summary file not found: {finalRoute.SummaryFilePath}");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!File.Exists(finalRoute.StitchedImagePath))
|
||||||
|
{
|
||||||
|
throw new Exception($"Stitched image not found: {finalRoute.StitchedImagePath}");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!File.Exists(finalRoute.TilesZipPath))
|
||||||
|
{
|
||||||
|
throw new Exception($"Tiles ZIP file not found: {finalRoute.TilesZipPath}");
|
||||||
|
}
|
||||||
|
|
||||||
|
var csvLines = await File.ReadAllLinesAsync(finalRoute.CsvFilePath);
|
||||||
|
var uniqueTileCount = csvLines.Length - 1;
|
||||||
|
|
||||||
|
var stitchedInfo = new FileInfo(finalRoute.StitchedImagePath);
|
||||||
|
var zipInfo = new FileInfo(finalRoute.TilesZipPath);
|
||||||
|
|
||||||
|
Console.WriteLine("Files Generated:");
|
||||||
|
Console.WriteLine($" ✓ CSV: {Path.GetFileName(finalRoute.CsvFilePath)} ({uniqueTileCount} tiles)");
|
||||||
|
Console.WriteLine($" ✓ Summary: {Path.GetFileName(finalRoute.SummaryFilePath)}");
|
||||||
|
Console.WriteLine($" ✓ Stitched Map: {Path.GetFileName(finalRoute.StitchedImagePath)} ({stitchedInfo.Length / 1024:F2} KB)");
|
||||||
|
Console.WriteLine($" ✓ Tiles ZIP: {Path.GetFileName(finalRoute.TilesZipPath)} ({zipInfo.Length / 1024:F2} KB)");
|
||||||
|
Console.WriteLine();
|
||||||
|
|
||||||
|
Console.WriteLine("Verifying ZIP file contents:");
|
||||||
|
using (var zipArchive = System.IO.Compression.ZipFile.OpenRead(finalRoute.TilesZipPath))
|
||||||
|
{
|
||||||
|
Console.WriteLine($" ZIP contains {zipArchive.Entries.Count} files");
|
||||||
|
|
||||||
|
if (zipArchive.Entries.Count == 0)
|
||||||
|
{
|
||||||
|
throw new Exception("ZIP file is empty");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (zipArchive.Entries.Count != uniqueTileCount)
|
||||||
|
{
|
||||||
|
throw new Exception($"ZIP contains {zipArchive.Entries.Count} files but CSV lists {uniqueTileCount} tiles");
|
||||||
|
}
|
||||||
|
|
||||||
|
var firstEntry = zipArchive.Entries[0];
|
||||||
|
Console.WriteLine($" First entry: {firstEntry.Name} ({firstEntry.Length} bytes)");
|
||||||
|
|
||||||
|
if (firstEntry.Length == 0)
|
||||||
|
{
|
||||||
|
throw new Exception("First entry in ZIP is empty");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Console.WriteLine();
|
||||||
|
Console.WriteLine("Route Summary:");
|
||||||
|
Console.WriteLine($" Route ID: {finalRoute.Id}");
|
||||||
|
Console.WriteLine($" Route Points: {finalRoute.TotalPoints}");
|
||||||
|
Console.WriteLine($" Distance: {finalRoute.TotalDistanceMeters:F2}m");
|
||||||
|
Console.WriteLine($" Unique Tiles: {uniqueTileCount}");
|
||||||
|
Console.WriteLine($" ZIP File Size: {zipInfo.Length / 1024:F2} KB");
|
||||||
|
Console.WriteLine($" Maps Ready: {finalRoute.MapsReady}");
|
||||||
|
Console.WriteLine();
|
||||||
|
|
||||||
|
if (zipInfo.Length < 1024)
|
||||||
|
{
|
||||||
|
throw new Exception($"ZIP file seems too small: {zipInfo.Length} bytes");
|
||||||
|
}
|
||||||
|
|
||||||
|
Console.WriteLine("✓ Route with Tiles ZIP File Test: PASSED");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
using System.IO.Compression;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
using Microsoft.Extensions.Hosting;
|
using Microsoft.Extensions.Hosting;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
@@ -307,13 +308,21 @@ public class RouteProcessingService : BackgroundService
|
|||||||
await StitchRouteTilesAsync(allTiles.Values.ToList(), stitchedImagePath, route.ZoomLevel, geofencePolygonBounds, routePoints, cancellationToken);
|
await StitchRouteTilesAsync(allTiles.Values.ToList(), stitchedImagePath, route.ZoomLevel, geofencePolygonBounds, routePoints, cancellationToken);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
string? tilesZipPath = null;
|
||||||
|
if (route.CreateTilesZip)
|
||||||
|
{
|
||||||
|
tilesZipPath = Path.Combine(readyDir, $"route_{routeId}_tiles.zip");
|
||||||
|
await CreateTilesZipAsync(tilesZipPath, allTiles.Values, cancellationToken);
|
||||||
|
}
|
||||||
|
|
||||||
var summaryPath = Path.Combine(readyDir, $"route_{routeId}_summary.txt");
|
var summaryPath = Path.Combine(readyDir, $"route_{routeId}_summary.txt");
|
||||||
await GenerateRouteSummaryAsync(summaryPath, route, allTiles.Count, totalTilesFromRegions, duplicateTiles, cancellationToken);
|
await GenerateRouteSummaryAsync(summaryPath, route, allTiles.Count, totalTilesFromRegions, duplicateTiles, tilesZipPath, cancellationToken);
|
||||||
|
|
||||||
route.MapsReady = true;
|
route.MapsReady = true;
|
||||||
route.CsvFilePath = csvPath;
|
route.CsvFilePath = csvPath;
|
||||||
route.SummaryFilePath = summaryPath;
|
route.SummaryFilePath = summaryPath;
|
||||||
route.StitchedImagePath = stitchedImagePath;
|
route.StitchedImagePath = stitchedImagePath;
|
||||||
|
route.TilesZipPath = tilesZipPath;
|
||||||
route.UpdatedAt = DateTime.UtcNow;
|
route.UpdatedAt = DateTime.UtcNow;
|
||||||
|
|
||||||
await _routeRepository.UpdateRouteAsync(route);
|
await _routeRepository.UpdateRouteAsync(route);
|
||||||
@@ -400,6 +409,7 @@ public class RouteProcessingService : BackgroundService
|
|||||||
int uniqueTiles,
|
int uniqueTiles,
|
||||||
int totalTilesFromRegions,
|
int totalTilesFromRegions,
|
||||||
int duplicateTiles,
|
int duplicateTiles,
|
||||||
|
string? tilesZipPath,
|
||||||
CancellationToken cancellationToken)
|
CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
var summary = new System.Text.StringBuilder();
|
var summary = new System.Text.StringBuilder();
|
||||||
@@ -428,6 +438,10 @@ public class RouteProcessingService : BackgroundService
|
|||||||
{
|
{
|
||||||
summary.AppendLine($"- Stitched Map: route_{route.Id}_stitched.jpg");
|
summary.AppendLine($"- Stitched Map: route_{route.Id}_stitched.jpg");
|
||||||
}
|
}
|
||||||
|
if (tilesZipPath != null)
|
||||||
|
{
|
||||||
|
summary.AppendLine($"- Tiles ZIP: route_{route.Id}_tiles.zip");
|
||||||
|
}
|
||||||
summary.AppendLine();
|
summary.AppendLine();
|
||||||
summary.AppendLine($"Completed: {DateTime.UtcNow:yyyy-MM-dd HH:mm:ss} UTC");
|
summary.AppendLine($"Completed: {DateTime.UtcNow:yyyy-MM-dd HH:mm:ss} UTC");
|
||||||
|
|
||||||
@@ -670,6 +684,52 @@ public class RouteProcessingService : BackgroundService
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Task CreateTilesZipAsync(
|
||||||
|
string zipFilePath,
|
||||||
|
IEnumerable<TileInfo> tiles,
|
||||||
|
CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
return Task.Run(() =>
|
||||||
|
{
|
||||||
|
if (File.Exists(zipFilePath))
|
||||||
|
{
|
||||||
|
File.Delete(zipFilePath);
|
||||||
|
}
|
||||||
|
|
||||||
|
using var zipArchive = ZipFile.Open(zipFilePath, ZipArchiveMode.Create);
|
||||||
|
int addedFiles = 0;
|
||||||
|
int missingFiles = 0;
|
||||||
|
|
||||||
|
foreach (var tile in tiles)
|
||||||
|
{
|
||||||
|
if (cancellationToken.IsCancellationRequested)
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (File.Exists(tile.FilePath))
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var fileName = Path.GetFileName(tile.FilePath);
|
||||||
|
zipArchive.CreateEntryFromFile(tile.FilePath, fileName, CompressionLevel.Optimal);
|
||||||
|
addedFiles++;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogWarning(ex, "Failed to add tile to zip: {FilePath}", tile.FilePath);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_logger.LogWarning("Tile file not found for zip: {FilePath}", tile.FilePath);
|
||||||
|
missingFiles++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_logger.LogInformation("Tiles zip created: {ZipPath} with {AddedFiles} tiles ({MissingFiles} missing)",
|
||||||
|
zipFilePath, addedFiles, missingFiles);
|
||||||
|
}, cancellationToken);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public class TileInfo
|
public class TileInfo
|
||||||
|
|||||||
@@ -117,6 +117,7 @@ public class RouteService : IRouteService
|
|||||||
TotalDistanceMeters = totalDistance,
|
TotalDistanceMeters = totalDistance,
|
||||||
TotalPoints = allPoints.Count,
|
TotalPoints = allPoints.Count,
|
||||||
RequestMaps = request.RequestMaps,
|
RequestMaps = request.RequestMaps,
|
||||||
|
CreateTilesZip = request.CreateTilesZip,
|
||||||
MapsReady = false,
|
MapsReady = false,
|
||||||
CreatedAt = now,
|
CreatedAt = now,
|
||||||
UpdatedAt = now
|
UpdatedAt = now
|
||||||
@@ -203,6 +204,7 @@ public class RouteService : IRouteService
|
|||||||
CsvFilePath = routeEntity.CsvFilePath,
|
CsvFilePath = routeEntity.CsvFilePath,
|
||||||
SummaryFilePath = routeEntity.SummaryFilePath,
|
SummaryFilePath = routeEntity.SummaryFilePath,
|
||||||
StitchedImagePath = routeEntity.StitchedImagePath,
|
StitchedImagePath = routeEntity.StitchedImagePath,
|
||||||
|
TilesZipPath = routeEntity.TilesZipPath,
|
||||||
CreatedAt = routeEntity.CreatedAt,
|
CreatedAt = routeEntity.CreatedAt,
|
||||||
UpdatedAt = routeEntity.UpdatedAt
|
UpdatedAt = routeEntity.UpdatedAt
|
||||||
};
|
};
|
||||||
@@ -241,6 +243,7 @@ public class RouteService : IRouteService
|
|||||||
CsvFilePath = route.CsvFilePath,
|
CsvFilePath = route.CsvFilePath,
|
||||||
SummaryFilePath = route.SummaryFilePath,
|
SummaryFilePath = route.SummaryFilePath,
|
||||||
StitchedImagePath = route.StitchedImagePath,
|
StitchedImagePath = route.StitchedImagePath,
|
||||||
|
TilesZipPath = route.TilesZipPath,
|
||||||
CreatedAt = route.CreatedAt,
|
CreatedAt = route.CreatedAt,
|
||||||
UpdatedAt = route.UpdatedAt
|
UpdatedAt = route.UpdatedAt
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user