From e1fee7b10220cdc730bde0f57fca608041698d89 Mon Sep 17 00:00:00 2001 From: juliangiebel Date: Wed, 30 Aug 2023 18:49:48 +0200 Subject: [PATCH 1/4] Work on fixing map tiling --- .../BuildRunners/LocalBuildService.cs | 52 +++++++++++++++++-- .../Configuration/BuildConfiguration.cs | 4 +- SS14.MapServer/Controllers/ImageController.cs | 2 +- SS14.MapServer/Controllers/MapController.cs | 3 ++ SS14.MapServer/Controllers/TileController.cs | 6 ++- .../Services/ImageProcessingService.cs | 2 +- .../Services/MapReaderServiceService.cs | 4 +- SS14.MapServer/Security/ApiKeyHandler.cs | 18 +++---- SS14.MapServer/Services/FileUploadService.cs | 5 +- SS14.MapServer/appsettings.yaml | 1 + 10 files changed, 74 insertions(+), 23 deletions(-) diff --git a/SS14.MapServer/BuildRunners/LocalBuildService.cs b/SS14.MapServer/BuildRunners/LocalBuildService.cs index d56e663..85c1860 100644 --- a/SS14.MapServer/BuildRunners/LocalBuildService.cs +++ b/SS14.MapServer/BuildRunners/LocalBuildService.cs @@ -1,8 +1,11 @@ using System.Diagnostics; +using System.Text; +using Sentry; using Serilog; using SS14.MapServer.Configuration; using SS14.MapServer.Exceptions; using ILogger = Serilog.ILogger; +// ReSharper disable AccessToDisposedClosure namespace SS14.MapServer.BuildRunners; @@ -42,7 +45,10 @@ public async Task Build(string directory, CancellationToken cancellationToken = var outputDir = Path.Join(directory, _configuration.RelativeOutputPath); process.StartInfo.Arguments = "build -c Release"; - process.OutputDataReceived += LogOutput; + + using var logStream = new MemoryStream(); + await using var logWriter = new StreamWriter(logStream); + process.OutputDataReceived += (_, args) => LogOutput(args, logWriter); _log.Information("Started building {ProjectName}", _configuration.MapRendererProjectName); @@ -58,8 +64,15 @@ public async Task Build(string directory, CancellationToken cancellationToken = } if (process.ExitCode != 0) - throw new BuildException($"Failed building {_configuration.MapRendererProjectName}"); + { + process.Close(); + logWriter.Close(); + var exception = new BuildException($"Failed building {_configuration.MapRendererProjectName}"); + CaptureBuildRunnerException(exception, logStream); + } + process.Close(); + logWriter.Close(); _log.Information("Build finished"); } @@ -71,8 +84,11 @@ public async Task Run(string directory, string command, List arguments, SetUpProcess(process, executablePath); process.StartInfo.WorkingDirectory = directory; process.StartInfo.Arguments = string.Join(' ', arguments); - process.OutputDataReceived += LogOutput; - process.ErrorDataReceived += LogOutput; + + using var logStream = new MemoryStream(); + await using var logWriter = new StreamWriter(logStream); + process.OutputDataReceived += (_, args) => LogOutput(args, logWriter); + process.ErrorDataReceived += (_, args) => LogOutput(args, logWriter); _log.Information("Running: {Command} {Arguments}", command, string.Join(' ', arguments)); @@ -94,7 +110,16 @@ public async Task Run(string directory, string command, List arguments, throw new BuildException($"Run timed out {_configuration.MapRendererProjectName}"); } + if (process.ExitCode == 0) + { + var exception = new BuildException($"Running {command} {string.Join(' ', arguments)} failed"); + CaptureBuildRunnerException(exception, logStream); + process.Close(); + logWriter.Close(); + } + process.Close(); + logWriter.Close(); _log.Information("Run finished"); } @@ -106,11 +131,28 @@ private void SetUpProcess(Process process, string? executable = "dotnet") process.StartInfo.FileName = executable; } - private void LogOutput(object _, DataReceivedEventArgs args) + private void LogOutput(DataReceivedEventArgs args, TextWriter logWriter) { if (args.Data == null) return; + logWriter.Write(args.Data); _log.Debug("{Output}", args.Data); } + + private void CaptureBuildRunnerException(Exception exception, Stream stream) + { + if (!SentrySdk.IsEnabled) + throw exception; + + var content = new StreamAttachmentContent(stream); + var attachment = new Attachment(AttachmentType.Default, content, "run.log", null); + var breadcrumb = new Breadcrumb("Captured run log", "log"); + + SentrySdk.CaptureException(exception, scope => + { + scope.AddBreadcrumb(breadcrumb, Hint.WithAttachments(attachment)); + }); + + } } diff --git a/SS14.MapServer/Configuration/BuildConfiguration.cs b/SS14.MapServer/Configuration/BuildConfiguration.cs index 1e880dc..575f945 100644 --- a/SS14.MapServer/Configuration/BuildConfiguration.cs +++ b/SS14.MapServer/Configuration/BuildConfiguration.cs @@ -3,7 +3,7 @@ public sealed class BuildConfiguration { public const string Name = "Build"; - + public bool Enabled { get; set; } = true; public BuildRunnerName Runner { get; set; } = BuildRunnerName.Local; public string RelativeOutputPath { get; set; } = "bin"; @@ -20,4 +20,4 @@ public enum BuildRunnerName { Local, Container -} \ No newline at end of file +} diff --git a/SS14.MapServer/Controllers/ImageController.cs b/SS14.MapServer/Controllers/ImageController.cs index 8433814..21b8211 100644 --- a/SS14.MapServer/Controllers/ImageController.cs +++ b/SS14.MapServer/Controllers/ImageController.cs @@ -133,7 +133,7 @@ private async Task InternalGetMap(Map? map, int gridId) if (map == null) return new NotFoundResult(); - var hash = $@"""{map.MapGuid:N}{map.LastUpdated.GetHashCode():X}"""; + var hash = $@"""{map.MapGuid:N}{gridId + map.LastUpdated.GetHashCode():X}"""; if (CheckETags(hash, out var result)) return result; diff --git a/SS14.MapServer/Controllers/MapController.cs b/SS14.MapServer/Controllers/MapController.cs index bf49382..5c01553 100644 --- a/SS14.MapServer/Controllers/MapController.cs +++ b/SS14.MapServer/Controllers/MapController.cs @@ -290,6 +290,9 @@ private Map SetMapGridUrls(Map map) _serverConfiguration.Host.Scheme, $"{_serverConfiguration.Host.Host}:{_serverConfiguration.Host.Port}" ); + + if (grid.Tiled) + grid.Url = grid.Url?.Replace("Image/grid", "Tile"); } map.Grids.Sort((grid, grid1) => grid1.Extent.CompareTo(grid.Extent)); return map; diff --git a/SS14.MapServer/Controllers/TileController.cs b/SS14.MapServer/Controllers/TileController.cs index 951709a..ce6035e 100644 --- a/SS14.MapServer/Controllers/TileController.cs +++ b/SS14.MapServer/Controllers/TileController.cs @@ -1,6 +1,7 @@ using System.Diagnostics.CodeAnalysis; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.RateLimiting; using Microsoft.EntityFrameworkCore; using Microsoft.Net.Http.Headers; using MimeTypes; @@ -22,6 +23,7 @@ public TileController(Context context) [AllowAnonymous] [ResponseCache(CacheProfileName = "Default")] + [DisableRateLimiting] [HttpGet("{id:guid}/{gridId:int}/{x:int}/{y:int}/{z:int}")] [ProducesResponseType(200, Type = typeof(FileStreamResult))] [Produces("image/jpg", "image/png", "image/webp", "application/json")] @@ -35,7 +37,7 @@ public async Task GetTile(Guid id, int gridId, int x, int y, int if (map == null) return new NotFoundResult(); - var hash = $@"""{map.MapGuid:N}{map.LastUpdated.GetHashCode():X}"""; + var hash = $@"""{map.MapGuid:N}{x + y + gridId + map.LastUpdated.GetHashCode():X}"""; if (CheckETags(hash, out var result)) return result; @@ -48,7 +50,7 @@ public async Task GetTile(Guid id, int gridId, int x, int y, int var tile = await _context.Tile!.FindAsync(id, gridId, x, y); - if (tile == null || !System.IO.File.Exists(grid.Path)) + if (tile == null || !System.IO.File.Exists(tile.Path)) return new NotFoundResult(); var file = new FileStream(tile.Path, FileMode.Open); diff --git a/SS14.MapServer/MapProcessing/Services/ImageProcessingService.cs b/SS14.MapServer/MapProcessing/Services/ImageProcessingService.cs index e5d67b9..6b662b8 100644 --- a/SS14.MapServer/MapProcessing/Services/ImageProcessingService.cs +++ b/SS14.MapServer/MapProcessing/Services/ImageProcessingService.cs @@ -10,7 +10,7 @@ public sealed class ImageProcessingService public async Task> TileImage(Guid mapGuid, int gridId, string sourcePath, string targetPath, int tileSize) { if (tileSize < MinTileSize) - throw new ArgumentOutOfRangeException($"Provider tile size {tileSize} is smaller than minimum tile size {MinTileSize}"); + throw new ArgumentOutOfRangeException($"Provided tile size {tileSize} is smaller than minimum tile size {MinTileSize}"); if (!Path.HasExtension(sourcePath)) throw new Exception($"Invalid image path: {sourcePath}"); diff --git a/SS14.MapServer/MapProcessing/Services/MapReaderServiceService.cs b/SS14.MapServer/MapProcessing/Services/MapReaderServiceService.cs index 8f6e24d..d3d90ea 100644 --- a/SS14.MapServer/MapProcessing/Services/MapReaderServiceService.cs +++ b/SS14.MapServer/MapProcessing/Services/MapReaderServiceService.cs @@ -93,7 +93,7 @@ public async Task> UpdateMapsFromFs(string path, string gitRef = "ma GridId = gridData.GridId, Extent = gridData.Extent, Offset = gridData.Offset, - Tiled = gridData.Tiled, + Tiled = true//gridData.Tiled, }; map.Grids.Add(grid); _context.Add(grid); @@ -108,7 +108,7 @@ public async Task> UpdateMapsFromFs(string path, string gitRef = "ma if (newMap) { - var id = (await _context.Map.AddAsync(map, cancellationToken)).Entity.MapGuid; + var id = (await _context.Map!.AddAsync(map, cancellationToken)).Entity.MapGuid; ids.Add(id); } else diff --git a/SS14.MapServer/Security/ApiKeyHandler.cs b/SS14.MapServer/Security/ApiKeyHandler.cs index d980001..c68b069 100644 --- a/SS14.MapServer/Security/ApiKeyHandler.cs +++ b/SS14.MapServer/Security/ApiKeyHandler.cs @@ -14,12 +14,12 @@ public class ApiKeyHandler : AuthenticationHandler public const string HeaderName = "X-API-Key"; public const string Name = "API_KEY"; - + public ApiKeyHandler( - IOptionsMonitor options, - ILoggerFactory logger, - UrlEncoder encoder, - ISystemClock clock) + IOptionsMonitor options, + ILoggerFactory logger, + UrlEncoder encoder, + ISystemClock clock) : base(options, logger, encoder, clock) { } @@ -27,19 +27,19 @@ public ApiKeyHandler( protected override Task HandleAuthenticateAsync() { var key = Options.ApiKey; - + if(key == null) return Task.FromResult(AuthenticateResult.Fail("No API Key configured. Management API is disabled.")); if(!Request.Headers.TryGetValue(HeaderName, out var providedKey)) return Task.FromResult(AuthenticateResult.Fail(InvalidApiKeyMessage)); - + if (!key.Equals(providedKey)) return Task.FromResult(AuthenticateResult.Fail(InvalidApiKeyMessage)); - + var claims = new[] { new Claim(ClaimTypes.Name, "API") }; var principal = new ClaimsPrincipal(new ClaimsIdentity(claims, Name)); var ticket = new AuthenticationTicket(principal, Scheme.Name); return Task.FromResult(AuthenticateResult.Success(ticket)); } -} \ No newline at end of file +} diff --git a/SS14.MapServer/Services/FileUploadService.cs b/SS14.MapServer/Services/FileUploadService.cs index c4e5a70..1c927e6 100644 --- a/SS14.MapServer/Services/FileUploadService.cs +++ b/SS14.MapServer/Services/FileUploadService.cs @@ -115,7 +115,10 @@ private async Task UploadAndProcessTiledImage(Guid mapGuid, string mapPa {ProcessTiledImage.ProcessOptionsKey, processingOptions} }; - await _schedulingService.RunJob(nameof(ProcessTiledImage), "Processing", data); + await _schedulingService.RunJob( + $"{nameof(ProcessTiledImage)}-{mapGuid}-{gridId}", + "Processing", + data); return targetPath; } diff --git a/SS14.MapServer/appsettings.yaml b/SS14.MapServer/appsettings.yaml index 1f18164..1c9f832 100644 --- a/SS14.MapServer/appsettings.yaml +++ b/SS14.MapServer/appsettings.yaml @@ -4,6 +4,7 @@ Serilog: Default: "Information" Override: SS14: "Information" + SS14.MapServer.Security.ApiKeyHandler: "Error" Microsoft: "Warning" Microsoft.Hosting.Lifetime: "Information" Microsoft.AspNetCore: "Warning" From 75c9a936a32bfaebba70b233ea90c56e84f20c8c Mon Sep 17 00:00:00 2001 From: juliangiebel Date: Fri, 1 Sep 2023 17:31:29 +0200 Subject: [PATCH 2/4] Work on tile preloading --- SS14.MapServer/Controllers/ImageController.cs | 4 +- SS14.MapServer/Controllers/TileController.cs | 40 ++- .../Services/ImageProcessingService.cs | 18 +- .../Services/MapReaderServiceService.cs | 17 +- .../20230831083404_TilePreview.Designer.cs | 267 ++++++++++++++++++ .../Migrations/20230831083404_TilePreview.cs | 29 ++ .../Migrations/ContextModelSnapshot.cs | 4 + SS14.MapServer/Models/Entities/Tile.cs | 4 +- SS14.MapServer/Models/Types/Area.cs | 11 + SS14.MapServer/Services/FileUploadService.cs | 10 +- 10 files changed, 368 insertions(+), 36 deletions(-) create mode 100644 SS14.MapServer/Migrations/20230831083404_TilePreview.Designer.cs create mode 100644 SS14.MapServer/Migrations/20230831083404_TilePreview.cs diff --git a/SS14.MapServer/Controllers/ImageController.cs b/SS14.MapServer/Controllers/ImageController.cs index 21b8211..c35785a 100644 --- a/SS14.MapServer/Controllers/ImageController.cs +++ b/SS14.MapServer/Controllers/ImageController.cs @@ -141,8 +141,8 @@ private async Task InternalGetMap(Map? map, int gridId) if (grid == null) return new NotFoundResult(); - if (grid.Tiled) - return new BadRequestObjectResult(new ApiErrorMessage($"Grid image with id {gridId} is a tiled image")); + //if (grid.Tiled) + // return new BadRequestObjectResult(new ApiErrorMessage($"Grid image with id {gridId} is a tiled image")); if (!System.IO.File.Exists(grid.Path)) return new NotFoundResult(); diff --git a/SS14.MapServer/Controllers/TileController.cs b/SS14.MapServer/Controllers/TileController.cs index ce6035e..b23a9d8 100644 --- a/SS14.MapServer/Controllers/TileController.cs +++ b/SS14.MapServer/Controllers/TileController.cs @@ -1,5 +1,6 @@ using System.Diagnostics.CodeAnalysis; using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Components; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.RateLimiting; using Microsoft.EntityFrameworkCore; @@ -7,10 +8,11 @@ using MimeTypes; using SS14.MapServer.Exceptions; using SS14.MapServer.Models; +using SS14.MapServer.Models.Entities; namespace SS14.MapServer.Controllers; -[Route("api/[controller]")] +[Microsoft.AspNetCore.Mvc.Route("api/[controller]")] [ApiController] public class TileController : ControllerBase { @@ -22,28 +24,23 @@ public TileController(Context context) } [AllowAnonymous] - [ResponseCache(CacheProfileName = "Default")] [DisableRateLimiting] + [ResponseCache(CacheProfileName = "Default", VaryByQueryKeys = new[] { "preload" })] [HttpGet("{id:guid}/{gridId:int}/{x:int}/{y:int}/{z:int}")] [ProducesResponseType(200, Type = typeof(FileStreamResult))] [Produces("image/jpg", "image/png", "image/webp", "application/json")] - public async Task GetTile(Guid id, int gridId, int x, int y, int z) + public async Task GetTile(Guid id, int gridId, int x, int y, int z, [FromQuery] bool preload) { - var map = await _context.Map! - .Include(map => map.Grids) - .Where(map => map.MapGuid.Equals(id)) - .SingleOrDefaultAsync(); + // TODO cache the result of this method + var (map, grid) = await RetrieveMapAndGrid(id, gridId); - if (map == null) + if (map == null || grid == null) return new NotFoundResult(); - var hash = $@"""{map.MapGuid:N}{x + y + gridId + map.LastUpdated.GetHashCode():X}"""; + var hash = $@"""{map.MapGuid:N}{Convert.ToInt32(preload) + x + y + gridId + map.LastUpdated.GetHashCode():X}"""; if (CheckETags(hash, out var result)) return result; - var grid = map.Grids.Find(value => value.GridId.Equals(gridId)); - if (grid == null) - return new NotFoundResult(); if (!grid.Tiled) return new BadRequestObjectResult(new ApiErrorMessage($"Grid image with id {gridId} doesn't support image tiling")); @@ -51,7 +48,10 @@ public async Task GetTile(Guid id, int gridId, int x, int y, int var tile = await _context.Tile!.FindAsync(id, gridId, x, y); if (tile == null || !System.IO.File.Exists(tile.Path)) - return new NotFoundResult(); + return new OkResult(); + + if (preload) + return File(tile.Preview, "image/webp", true); var file = new FileStream(tile.Path, FileMode.Open); var mimeType = MimeTypeMap.GetMimeType(Path.GetExtension(tile.Path)); @@ -59,6 +59,20 @@ public async Task GetTile(Guid id, int gridId, int x, int y, int return File(file, mimeType, map.LastUpdated, new EntityTagHeaderValue(hash), true); } + private async Task<(Map? map, Grid? grid)> RetrieveMapAndGrid(Guid id, int gridId) + { + var map = await _context.Map! + .Include(map => map.Grids) + .Where(map => map.MapGuid.Equals(id)) + .SingleOrDefaultAsync(); + + if (map == null) + return (null, null); + + var grid = map.Grids.Find(value => value.GridId.Equals(gridId)); + return (map, grid); + } + private bool CheckETags(string hash, [NotNullWhen(true)] out IActionResult? result) { if (Request.Headers.IfNoneMatch.Any(h => h != null && h.Equals(hash))) diff --git a/SS14.MapServer/MapProcessing/Services/ImageProcessingService.cs b/SS14.MapServer/MapProcessing/Services/ImageProcessingService.cs index 6b662b8..5b9f5bb 100644 --- a/SS14.MapServer/MapProcessing/Services/ImageProcessingService.cs +++ b/SS14.MapServer/MapProcessing/Services/ImageProcessingService.cs @@ -1,4 +1,5 @@ using SixLabors.ImageSharp.Advanced; +using SixLabors.ImageSharp.Formats.Webp; using SS14.MapServer.Models.Entities; namespace SS14.MapServer.MapProcessing.Services; @@ -28,17 +29,32 @@ public async Task> TileImage(Guid mapGuid, int gridId, string sourceP var extension = Path.GetExtension(sourcePath); var encoder = image.DetectEncoder(sourcePath); + var compressedWebpEncoder = new WebpEncoder + { + Method = WebpEncodingMethod.Level6, + FileFormat = WebpFileFormatType.Lossy, + Quality = 1, + SkipMetadata = true, + FilterStrength = 0, + TransparentColorMode = WebpTransparentColorMode.Preserve + }; + for (var y = 0; y < heightSteps; y++) { for (var x = 0; x < widthSteps; x++) { var rectangle = new Rectangle(tileSize * x, tileSize * y, tileSize, tileSize); var tile = image.Clone(img => img.Crop(rectangle)); + var preview = tile.Clone(img => img.Pixelate(8)); var path = Path.Combine(targetPath, $"tile_{Guid.NewGuid()}{extension}"); await tile.SaveAsync(path, encoder); - tiles.Add(new Tile(mapGuid, gridId, x, y, tileSize, path)); + using var stream = new MemoryStream(); + await preview.SaveAsync(stream, compressedWebpEncoder); + var previewData = stream.ToArray(); + + tiles.Add(new Tile(mapGuid, gridId, x, y, tileSize, path, previewData)); } } diff --git a/SS14.MapServer/MapProcessing/Services/MapReaderServiceService.cs b/SS14.MapServer/MapProcessing/Services/MapReaderServiceService.cs index d3d90ea..8c4261c 100644 --- a/SS14.MapServer/MapProcessing/Services/MapReaderServiceService.cs +++ b/SS14.MapServer/MapProcessing/Services/MapReaderServiceService.cs @@ -69,6 +69,9 @@ public async Task> UpdateMapsFromFs(string path, string gitRef = "ma map.Attribution = data.Attribution; map.ParallaxLayers = data.ParallaxLayers; + if (newMap) + await _context.Map!.AddAsync(map, cancellationToken); + //Remove previous grids if there are any if (map.Grids.Count > 0) _context.RemoveRange(map.Grids); @@ -93,7 +96,8 @@ public async Task> UpdateMapsFromFs(string path, string gitRef = "ma GridId = gridData.GridId, Extent = gridData.Extent, Offset = gridData.Offset, - Tiled = true//gridData.Tiled, + //Only tile maps used by the viewer and prevent small grids from being tiled + Tiled = gridData.Extent.GetArea() >= 65536 && gitRef == "master"//gridData.Tiled, }; map.Grids.Add(grid); _context.Add(grid); @@ -106,16 +110,7 @@ public async Task> UpdateMapsFromFs(string path, string gitRef = "ma await stream.DisposeAsync(); } - if (newMap) - { - var id = (await _context.Map!.AddAsync(map, cancellationToken)).Entity.MapGuid; - ids.Add(id); - } - else - { - ids.Add(map.MapGuid); - } - + ids.Add(map.MapGuid); await _context.SaveChangesAsync(cancellationToken); } diff --git a/SS14.MapServer/Migrations/20230831083404_TilePreview.Designer.cs b/SS14.MapServer/Migrations/20230831083404_TilePreview.Designer.cs new file mode 100644 index 0000000..8778ae4 --- /dev/null +++ b/SS14.MapServer/Migrations/20230831083404_TilePreview.Designer.cs @@ -0,0 +1,267 @@ +// +using System; +using System.Collections.Generic; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; +using SS14.MapServer.Models; +using SS14.MapServer.Models.Types; + +#nullable disable + +namespace SS14.MapServer.Migrations +{ + [DbContext(typeof(Context))] + [Migration("20230831083404_TilePreview")] + partial class TilePreview + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "7.0.5") + .HasAnnotation("Relational:MaxIdentifierLength", 63); + + NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); + + modelBuilder.Entity("SS14.MapServer.Models.Entities.Grid", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("GridId") + .HasColumnType("integer"); + + b.Property("MapGuid") + .HasColumnType("uuid"); + + b.Property("Path") + .IsRequired() + .HasColumnType("text"); + + b.Property("TileSize") + .HasColumnType("integer"); + + b.Property("Tiled") + .HasColumnType("boolean"); + + b.HasKey("Id"); + + b.HasIndex("GridId"); + + b.HasIndex("MapGuid"); + + b.ToTable("Grid"); + }); + + modelBuilder.Entity("SS14.MapServer.Models.Entities.ImageFile", b => + { + b.Property("Path") + .HasColumnType("text"); + + b.Property("InternalPath") + .IsRequired() + .HasColumnType("text"); + + b.Property("LastUpdated") + .ValueGeneratedOnAddOrUpdate() + .HasColumnType("timestamp with time zone") + .HasDefaultValueSql("CURRENT_TIMESTAMP"); + + b.HasKey("Path"); + + b.ToTable("Image"); + }); + + modelBuilder.Entity("SS14.MapServer.Models.Entities.Map", b => + { + b.Property("MapGuid") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("Attribution") + .HasColumnType("text"); + + b.Property("DisplayName") + .IsRequired() + .HasColumnType("text"); + + b.Property("GitRef") + .IsRequired() + .HasColumnType("text"); + + b.Property("LastUpdated") + .ValueGeneratedOnAddOrUpdate() + .HasColumnType("timestamp with time zone") + .HasDefaultValueSql("CURRENT_TIMESTAMP"); + + b.Property("MapId") + .IsRequired() + .HasColumnType("text"); + + b.Property>("ParallaxLayers") + .IsRequired() + .HasColumnType("jsonb"); + + b.HasKey("MapGuid"); + + b.HasIndex("GitRef"); + + b.HasIndex("GitRef", "MapId") + .IsUnique(); + + b.ToTable("Map"); + }); + + modelBuilder.Entity("SS14.MapServer.Models.Entities.PullRequestComment", b => + { + b.Property("Owner") + .HasColumnType("text"); + + b.Property("Repository") + .HasColumnType("text"); + + b.Property("IssueNumber") + .HasColumnType("integer"); + + b.Property("CommentId") + .HasColumnType("integer"); + + b.HasKey("Owner", "Repository", "IssueNumber"); + + b.ToTable("PullRequestComment"); + }); + + modelBuilder.Entity("SS14.MapServer.Models.Entities.Tile", b => + { + b.Property("MapGuid") + .HasColumnType("uuid"); + + b.Property("GridId") + .HasColumnType("integer"); + + b.Property("X") + .HasColumnType("integer"); + + b.Property("Y") + .HasColumnType("integer"); + + b.Property("Path") + .IsRequired() + .HasColumnType("text"); + + b.Property("Preview") + .IsRequired() + .HasColumnType("bytea"); + + b.Property("Size") + .HasColumnType("integer"); + + b.HasKey("MapGuid", "GridId", "X", "Y"); + + b.HasIndex("MapGuid", "GridId"); + + b.ToTable("Tile"); + }); + + modelBuilder.Entity("SS14.MapServer.Models.Entities.Grid", b => + { + b.HasOne("SS14.MapServer.Models.Entities.Map", null) + .WithMany("Grids") + .HasForeignKey("MapGuid"); + + b.OwnsOne("SS14.MapServer.Models.Types.Point", "Offset", b1 => + { + b1.Property("GridId") + .HasColumnType("uuid"); + + b1.Property("X") + .HasColumnType("real"); + + b1.Property("Y") + .HasColumnType("real"); + + b1.HasKey("GridId"); + + b1.ToTable("Grid"); + + b1.WithOwner() + .HasForeignKey("GridId"); + }); + + b.OwnsOne("SS14.MapServer.Models.Types.Area", "Extent", b1 => + { + b1.Property("GridId") + .HasColumnType("uuid"); + + b1.HasKey("GridId"); + + b1.ToTable("Grid"); + + b1.WithOwner() + .HasForeignKey("GridId"); + + b1.OwnsOne("SS14.MapServer.Models.Types.Point", "A", b2 => + { + b2.Property("AreaGridId") + .HasColumnType("uuid"); + + b2.Property("X") + .HasColumnType("real"); + + b2.Property("Y") + .HasColumnType("real"); + + b2.HasKey("AreaGridId"); + + b2.ToTable("Grid"); + + b2.WithOwner() + .HasForeignKey("AreaGridId"); + }); + + b1.OwnsOne("SS14.MapServer.Models.Types.Point", "B", b2 => + { + b2.Property("AreaGridId") + .HasColumnType("uuid"); + + b2.Property("X") + .HasColumnType("real"); + + b2.Property("Y") + .HasColumnType("real"); + + b2.HasKey("AreaGridId"); + + b2.ToTable("Grid"); + + b2.WithOwner() + .HasForeignKey("AreaGridId"); + }); + + b1.Navigation("A") + .IsRequired(); + + b1.Navigation("B") + .IsRequired(); + }); + + b.Navigation("Extent") + .IsRequired(); + + b.Navigation("Offset") + .IsRequired(); + }); + + modelBuilder.Entity("SS14.MapServer.Models.Entities.Map", b => + { + b.Navigation("Grids"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/SS14.MapServer/Migrations/20230831083404_TilePreview.cs b/SS14.MapServer/Migrations/20230831083404_TilePreview.cs new file mode 100644 index 0000000..017d5a0 --- /dev/null +++ b/SS14.MapServer/Migrations/20230831083404_TilePreview.cs @@ -0,0 +1,29 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace SS14.MapServer.Migrations +{ + /// + public partial class TilePreview : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.AddColumn( + name: "Preview", + table: "Tile", + type: "bytea", + nullable: false, + defaultValue: new byte[0]); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropColumn( + name: "Preview", + table: "Tile"); + } + } +} diff --git a/SS14.MapServer/Migrations/ContextModelSnapshot.cs b/SS14.MapServer/Migrations/ContextModelSnapshot.cs index 7f22b78..6149947 100644 --- a/SS14.MapServer/Migrations/ContextModelSnapshot.cs +++ b/SS14.MapServer/Migrations/ContextModelSnapshot.cs @@ -151,6 +151,10 @@ protected override void BuildModel(ModelBuilder modelBuilder) .IsRequired() .HasColumnType("text"); + b.Property("Preview") + .IsRequired() + .HasColumnType("bytea"); + b.Property("Size") .HasColumnType("integer"); diff --git a/SS14.MapServer/Models/Entities/Tile.cs b/SS14.MapServer/Models/Entities/Tile.cs index 25c6814..d41fd23 100644 --- a/SS14.MapServer/Models/Entities/Tile.cs +++ b/SS14.MapServer/Models/Entities/Tile.cs @@ -12,8 +12,9 @@ public class Tile public int Y { get; set; } public int Size { get; set; } public string Path { get; set; } + public byte[] Preview { get; set; } - public Tile(Guid mapGuid, int gridId, int x, int y, int size, string path) + public Tile(Guid mapGuid, int gridId, int x, int y, int size, string path, byte[] preview) { MapGuid = mapGuid; GridId = gridId; @@ -21,5 +22,6 @@ public Tile(Guid mapGuid, int gridId, int x, int y, int size, string path) Y = y; Size = size; Path = path; + Preview = preview; } } diff --git a/SS14.MapServer/Models/Types/Area.cs b/SS14.MapServer/Models/Types/Area.cs index 76171fd..eaa9045 100644 --- a/SS14.MapServer/Models/Types/Area.cs +++ b/SS14.MapServer/Models/Types/Area.cs @@ -23,4 +23,15 @@ public int CompareTo(Area? other) return area.CompareTo(areaB); } + + public Point GetSize() + { + return A - B; + } + + public int GetArea() + { + var size = GetSize(); + return (int)Math.Abs(size.X * size.Y); + } } diff --git a/SS14.MapServer/Services/FileUploadService.cs b/SS14.MapServer/Services/FileUploadService.cs index 1c927e6..94aa145 100644 --- a/SS14.MapServer/Services/FileUploadService.cs +++ b/SS14.MapServer/Services/FileUploadService.cs @@ -51,16 +51,10 @@ public async Task UploadGridImages(string gitRef, Map map, IEnumerable Date: Wed, 14 Feb 2024 19:37:28 +0100 Subject: [PATCH 3/4] Clean up getting the default branch in map reader --- .../MapProcessing/Services/MapReaderServiceService.cs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/SS14.MapServer/MapProcessing/Services/MapReaderServiceService.cs b/SS14.MapServer/MapProcessing/Services/MapReaderServiceService.cs index 8c4261c..86ae6ad 100644 --- a/SS14.MapServer/MapProcessing/Services/MapReaderServiceService.cs +++ b/SS14.MapServer/MapProcessing/Services/MapReaderServiceService.cs @@ -13,6 +13,7 @@ namespace SS14.MapServer.MapProcessing.Services; public sealed class MapReaderServiceService : IMapReaderService { private readonly BuildConfiguration _buildConfiguration = new(); + private readonly GitConfiguration _gitConfiguration = new(); private readonly FileUploadService _fileUploadService; private readonly Context _context; @@ -22,9 +23,10 @@ public MapReaderServiceService(IConfiguration configuration, FileUploadService f _context = context; configuration.Bind(BuildConfiguration.Name, _buildConfiguration); + configuration.Bind(GitConfiguration.Name, _gitConfiguration); } - public async Task> UpdateMapsFromFs(string path, string gitRef = "master", CancellationToken cancellationToken = default) + public async Task> UpdateMapsFromFs(string path, string gitRef, CancellationToken cancellationToken = default) { if (!Directory.Exists(path)) throw new DirectoryNotFoundException($"Map import path not found: {path}"); @@ -97,7 +99,7 @@ public async Task> UpdateMapsFromFs(string path, string gitRef = "ma Extent = gridData.Extent, Offset = gridData.Offset, //Only tile maps used by the viewer and prevent small grids from being tiled - Tiled = gridData.Extent.GetArea() >= 65536 && gitRef == "master"//gridData.Tiled, + Tiled = gridData.Extent.GetArea() >= 65536 && gitRef == _gitConfiguration.Branch }; map.Grids.Add(grid); _context.Add(grid); From 5892cb48e38f16534c169b686111dc4b1ea0b2fe Mon Sep 17 00:00:00 2001 From: juliangiebel Date: Wed, 14 Feb 2024 23:40:17 +0100 Subject: [PATCH 4/4] a --- SS14.MapServer/appsettings.yaml | 1 - 1 file changed, 1 deletion(-) diff --git a/SS14.MapServer/appsettings.yaml b/SS14.MapServer/appsettings.yaml index 65e0108..f7c33db 100644 --- a/SS14.MapServer/appsettings.yaml +++ b/SS14.MapServer/appsettings.yaml @@ -4,7 +4,6 @@ Serilog: Default: "Information" Override: SS14: "Information" - SS14.MapServer.Security.ApiKeyHandler: "Error" Microsoft: "Warning" Microsoft.Hosting.Lifetime: "Information" Microsoft.AspNetCore: "Warning"