From 0483e62d14615d1282ff4338783c3f27e5517ec4 Mon Sep 17 00:00:00 2001 From: Vitalii Mikhailov Date: Fri, 23 Feb 2024 15:42:33 +0200 Subject: [PATCH] Added sitemap and it's caching --- .../Controllers/ReportController.cs | 28 +++++++++++++++++- .../Models/Sitemaps/ChangeFrequency.cs | 29 +++++++++++++++++++ .../Models/Sitemaps/Url.cs | 27 +++++++++++++++++ .../Models/Sitemaps/Urlset.cs | 11 +++++++ .../Options/CrashUploadOptions.cs | 5 ++++ .../Services/DatabaseMigrator.cs | 2 +- src/BUTR.CrashReportServer/Startup.cs | 8 ++++- src/BUTR.CrashReportServer/appsettings.json | 4 +++ 8 files changed, 111 insertions(+), 3 deletions(-) create mode 100644 src/BUTR.CrashReportServer/Models/Sitemaps/ChangeFrequency.cs create mode 100644 src/BUTR.CrashReportServer/Models/Sitemaps/Url.cs create mode 100644 src/BUTR.CrashReportServer/Models/Sitemaps/Urlset.cs diff --git a/src/BUTR.CrashReportServer/Controllers/ReportController.cs b/src/BUTR.CrashReportServer/Controllers/ReportController.cs index f053eaa..6dd46a4 100644 --- a/src/BUTR.CrashReportServer/Controllers/ReportController.cs +++ b/src/BUTR.CrashReportServer/Controllers/ReportController.cs @@ -2,6 +2,8 @@ using BUTR.CrashReportServer.Models; using BUTR.CrashReportServer.Models.API; using BUTR.CrashReportServer.Models.Database; +using BUTR.CrashReportServer.Models.Sitemaps; +using BUTR.CrashReportServer.Options; using BUTR.CrashReportServer.Services; using Microsoft.AspNetCore.Authorization; @@ -9,6 +11,7 @@ using Microsoft.AspNetCore.Mvc; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Options; using System; using System.Collections.Generic; @@ -33,12 +36,14 @@ public sealed record GetNewCrashReportsBody } private readonly ILogger _logger; + private readonly ReportOptions _options; private readonly AppDbContext _dbContext; private readonly GZipCompressor _gZipCompressor; - public ReportController(ILogger logger, AppDbContext dbContext, GZipCompressor gZipCompressor) + public ReportController(ILogger logger, IOptionsSnapshot options, AppDbContext dbContext, GZipCompressor gZipCompressor) { _logger = logger ?? throw new ArgumentNullException(nameof(logger)); + _options = options.Value ?? throw new ArgumentNullException(nameof(options)); _dbContext = dbContext ?? throw new ArgumentNullException(nameof(dbContext)); _gZipCompressor = gZipCompressor ?? throw new ArgumentNullException(nameof(gZipCompressor)); } @@ -180,4 +185,25 @@ public ActionResult> GetNewCrashReportsDates([FromBody .Where(x => x.Created.Ticks > body.DateTime.Ticks) .Select(x => new FileMetadata(x.FileId, x.CrashReportId, x.Version, x.Created.ToUniversalTime()))); } + + [AllowAnonymous] + [HttpGet("sitemap.xml")] + [Produces("application/xml")] + [ProducesResponseType(typeof(Urlset), StatusCodes.Status200OK, "application/xml")] + [ProducesResponseType(typeof(void), StatusCodes.Status500InternalServerError, "application/problem+xml")] + [ResponseCache(Duration = 60 * 60 * 4)] + public IActionResult Sitemap(CancellationToken ct) + { + var sitemap = new Urlset + { + Url = _dbContext.Set().Select(x => new { x.FileId, x.Created }).Select(x => new Url + { + Location = $"{_options.BaseUri}/{x.FileId}", + TimeStamp = x.Created, + Priority = 0.5, + ChangeFrequency = ChangeFrequency.Never, + }).ToList(), + }; + return Ok(sitemap); + } } \ No newline at end of file diff --git a/src/BUTR.CrashReportServer/Models/Sitemaps/ChangeFrequency.cs b/src/BUTR.CrashReportServer/Models/Sitemaps/ChangeFrequency.cs new file mode 100644 index 0000000..0a9fe34 --- /dev/null +++ b/src/BUTR.CrashReportServer/Models/Sitemaps/ChangeFrequency.cs @@ -0,0 +1,29 @@ +using System; +using System.Xml.Serialization; + +namespace BUTR.CrashReportServer.Models.Sitemaps; + +[Serializable] +public enum ChangeFrequency +{ + [XmlEnum(Name = "always")] + Always, + + [XmlEnum(Name = "hourly")] + Hourly, + + [XmlEnum(Name = "daily")] + Daily, + + [XmlEnum(Name = "weekly")] + Weekly, + + [XmlEnum(Name = "monthly")] + Monthly, + + [XmlEnum(Name = "yearly")] + Yearly, + + [XmlEnum(Name = "never")] + Never +} \ No newline at end of file diff --git a/src/BUTR.CrashReportServer/Models/Sitemaps/Url.cs b/src/BUTR.CrashReportServer/Models/Sitemaps/Url.cs new file mode 100644 index 0000000..82ab4e9 --- /dev/null +++ b/src/BUTR.CrashReportServer/Models/Sitemaps/Url.cs @@ -0,0 +1,27 @@ +using System; +using System.Xml.Serialization; + +namespace BUTR.CrashReportServer.Models.Sitemaps; + +[XmlRoot(ElementName="url", Namespace="http://www.sitemaps.org/schemas/sitemap/0.9")] +public class Url +{ + [XmlElement(ElementName="loc", Namespace="http://www.sitemaps.org/schemas/sitemap/0.9")] + public string Location { get; set; } + + [XmlIgnore] + public DateTime TimeStamp { get; set; } + + [XmlElement(ElementName="lastmod", Namespace="http://www.sitemaps.org/schemas/sitemap/0.9")] + public string LastMod + { + get => TimeStamp.ToString("yyyy-MM-ddTHH:mm:sszzz"); + set => TimeStamp = DateTime.Parse(value); + } + + [XmlElement(ElementName="changefreq", Namespace="http://www.sitemaps.org/schemas/sitemap/0.9")] + public ChangeFrequency ChangeFrequency { get; set; } + + [XmlElement(ElementName="priority", Namespace="http://www.sitemaps.org/schemas/sitemap/0.9")] + public double Priority { get; set; } +} \ No newline at end of file diff --git a/src/BUTR.CrashReportServer/Models/Sitemaps/Urlset.cs b/src/BUTR.CrashReportServer/Models/Sitemaps/Urlset.cs new file mode 100644 index 0000000..8bde429 --- /dev/null +++ b/src/BUTR.CrashReportServer/Models/Sitemaps/Urlset.cs @@ -0,0 +1,11 @@ +using System.Collections.Generic; +using System.Xml.Serialization; + +namespace BUTR.CrashReportServer.Models.Sitemaps; + +[XmlRoot(ElementName="urlset", Namespace="http://www.sitemaps.org/schemas/sitemap/0.9")] +public class Urlset { + + [XmlElement(ElementName="url", Namespace="http://www.sitemaps.org/schemas/sitemap/0.9")] + public List Url { get; set; } +} \ No newline at end of file diff --git a/src/BUTR.CrashReportServer/Options/CrashUploadOptions.cs b/src/BUTR.CrashReportServer/Options/CrashUploadOptions.cs index 9c50033..362a493 100644 --- a/src/BUTR.CrashReportServer/Options/CrashUploadOptions.cs +++ b/src/BUTR.CrashReportServer/Options/CrashUploadOptions.cs @@ -5,5 +5,10 @@ public record CrashUploadOptions public int MinContentLength { get; set; } public int MaxContentLength { get; set; } + public string? BaseUri { get; set; } +} + +public record ReportOptions +{ public string? BaseUri { get; set; } } \ No newline at end of file diff --git a/src/BUTR.CrashReportServer/Services/DatabaseMigrator.cs b/src/BUTR.CrashReportServer/Services/DatabaseMigrator.cs index 8dc3413..e49d91c 100644 --- a/src/BUTR.CrashReportServer/Services/DatabaseMigrator.cs +++ b/src/BUTR.CrashReportServer/Services/DatabaseMigrator.cs @@ -50,7 +50,7 @@ protected override async Task ExecuteAsync(CancellationToken ct) var dbContextFactory = scope.ServiceProvider.GetRequiredService>(); var dbContextPool = new ObjectPool(dbContextFactory.CreateDbContextAsync); - var options = new ParallelOptions { CancellationToken = ct, MaxDegreeOfParallelism = 4 }; + var options = new ParallelOptions { CancellationToken = ct }; await Parallel.ForEachAsync(Enumerable.Range(0, 4), options, async (_, ct2) => { var dbContext = await dbContextPool.GetAsync(ct2); diff --git a/src/BUTR.CrashReportServer/Startup.cs b/src/BUTR.CrashReportServer/Startup.cs index 311144e..3e641d9 100644 --- a/src/BUTR.CrashReportServer/Startup.cs +++ b/src/BUTR.CrashReportServer/Startup.cs @@ -6,6 +6,7 @@ using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.Mvc.Formatters; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; @@ -40,6 +41,7 @@ public void ConfigureServices(IServiceCollection services) services.Configure(_configuration.GetSection("Auth")); services.Configure(_configuration.GetSection("Storage")); services.Configure(_configuration.GetSection("CrashUpload")); + services.Configure(_configuration.GetSection("Report")); services.AddTransient(_ => RandomNumberGenerator.Create()); services.AddSingleton(); @@ -102,13 +104,15 @@ public void ConfigureServices(IServiceCollection services) opts.JsonSerializerOptions.PropertyNameCaseInsensitive = true; opts.JsonSerializerOptions.PropertyNamingPolicy = JsonNamingPolicy.CamelCase; opts.JsonSerializerOptions.Converters.Add(new JsonStringEnumConverter(JsonNamingPolicy.CamelCase)); - }); + }).AddXmlSerializerFormatters().AddXmlDataContractSerializerFormatters(); services.Configure(opts => { opts.PropertyNameCaseInsensitive = true; opts.PropertyNamingPolicy = JsonNamingPolicy.CamelCase; opts.Converters.Add(new JsonStringEnumConverter(JsonNamingPolicy.CamelCase)); }); + + services.AddResponseCaching(); } public void Configure(IApplicationBuilder app, IWebHostEnvironment env) @@ -122,6 +126,8 @@ public void Configure(IApplicationBuilder app, IWebHostEnvironment env) app.UseSwaggerUI(options => options.SwaggerEndpoint("/swagger/v1/swagger.json", _appName)); app.UseRouting(); + + app.UseResponseCaching(); app.UseAuthentication(); app.UseAuthorization(); diff --git a/src/BUTR.CrashReportServer/appsettings.json b/src/BUTR.CrashReportServer/appsettings.json index ed45371..d409102 100644 --- a/src/BUTR.CrashReportServer/appsettings.json +++ b/src/BUTR.CrashReportServer/appsettings.json @@ -10,6 +10,10 @@ "Main": "" }, + "Report": { + "BaseUri": "https://crash.butr.dev/report" + }, + "CrashUpload": { "MinContentLength": 512, "MaxContentLength": 8388608,