diff --git a/SatelliteProvider.IntegrationTests/ExtendedRouteTests.cs b/SatelliteProvider.IntegrationTests/ExtendedRouteTests.cs index a53efa8..b3eeeaa 100644 --- a/SatelliteProvider.IntegrationTests/ExtendedRouteTests.cs +++ b/SatelliteProvider.IntegrationTests/ExtendedRouteTests.cs @@ -160,12 +160,35 @@ public static class ExtendedRouteTests } var firstEntry = zipArchive.Entries[0]; - Console.WriteLine($" First entry: {firstEntry.Name} ({firstEntry.Length} bytes)"); + Console.WriteLine($" First entry: {firstEntry.FullName} ({firstEntry.Length} bytes)"); if (firstEntry.Length == 0) { throw new Exception("First entry in ZIP is empty"); } + + var entriesWithDirs = zipArchive.Entries.Where(e => e.FullName.Contains('/')).ToList(); + Console.WriteLine($" Entries with directory structure: {entriesWithDirs.Count}/{zipArchive.Entries.Count}"); + + if (entriesWithDirs.Count == 0) + { + throw new Exception("ZIP should preserve directory structure but found no entries with paths"); + } + + var samplePaths = entriesWithDirs.Take(3).Select(e => e.FullName).ToList(); + Console.WriteLine($" Sample paths:"); + foreach (var path in samplePaths) + { + Console.WriteLine($" - {path}"); + } + + var pathParts = firstEntry.FullName.Split('/'); + if (pathParts.Length < 4) + { + throw new Exception($"Expected directory structure like '18/158/91/tile_xxx.jpg' but got '{firstEntry.FullName}'"); + } + + Console.WriteLine($" ✓ Directory structure preserved (zoom/{pathParts[0]}/x-bucket/{pathParts[1]}/y-bucket/{pathParts[2]}/file)"); } Console.WriteLine(); diff --git a/SatelliteProvider.Services/RouteProcessingService.cs b/SatelliteProvider.Services/RouteProcessingService.cs index fe2dff9..ef53f87 100644 --- a/SatelliteProvider.Services/RouteProcessingService.cs +++ b/SatelliteProvider.Services/RouteProcessingService.cs @@ -701,6 +701,9 @@ public class RouteProcessingService : BackgroundService int addedFiles = 0; int missingFiles = 0; + var tilesBasePath = _storageConfig.TilesDirectory; + var normalizedBasePath = Path.GetFullPath(tilesBasePath).TrimEnd(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar); + foreach (var tile in tiles) { if (cancellationToken.IsCancellationRequested) @@ -710,8 +713,20 @@ public class RouteProcessingService : BackgroundService { try { - var fileName = Path.GetFileName(tile.FilePath); - zipArchive.CreateEntryFromFile(tile.FilePath, fileName, CompressionLevel.Optimal); + var fullPath = Path.GetFullPath(tile.FilePath); + string entryName; + + if (fullPath.StartsWith(normalizedBasePath, StringComparison.OrdinalIgnoreCase)) + { + entryName = fullPath.Substring(normalizedBasePath.Length + 1); + entryName = entryName.Replace(Path.DirectorySeparatorChar, '/'); + } + else + { + entryName = Path.GetFileName(tile.FilePath); + } + + zipArchive.CreateEntryFromFile(tile.FilePath, entryName, CompressionLevel.Optimal); addedFiles++; } catch (Exception ex)