From 6f08b341eb4b14b68f573dfd374dae46aa80b4b4 Mon Sep 17 00:00:00 2001 From: Vitalii Mikhailov Date: Thu, 10 Oct 2024 23:21:41 +0300 Subject: [PATCH] Crah Report Multitenant support --- .../Shared/Footer.razor | 2 +- .../RecreateStacktraceController.cs | 9 +++++---- .../Controllers/ReportsController.cs | 6 +++++- .../Jobs/CrashReportProcessorJob.cs | 2 +- .../General/ICrashReportBatchedHandler.cs | 6 ++++-- .../HttpClients/ICrashReporterClient.cs | 20 +++++++++---------- 6 files changed, 26 insertions(+), 19 deletions(-) diff --git a/src/BUTR.Site.NexusMods.Client/Shared/Footer.razor b/src/BUTR.Site.NexusMods.Client/Shared/Footer.razor index b565e40b..06a029f6 100644 --- a/src/BUTR.Site.NexusMods.Client/Shared/Footer.razor +++ b/src/BUTR.Site.NexusMods.Client/Shared/Footer.razor @@ -13,5 +13,5 @@
- © 2022-2023 BUTR + © 2022-2024 BUTR
diff --git a/src/BUTR.Site.NexusMods.Server/Controllers/RecreateStacktraceController.cs b/src/BUTR.Site.NexusMods.Server/Controllers/RecreateStacktraceController.cs index 90be7e8d..bf74ba9b 100644 --- a/src/BUTR.Site.NexusMods.Server/Controllers/RecreateStacktraceController.cs +++ b/src/BUTR.Site.NexusMods.Server/Controllers/RecreateStacktraceController.cs @@ -20,6 +20,7 @@ using System.Text; using System.Threading; using System.Threading.Tasks; +using BUTR.Site.NexusMods.Server.Utils.BindingSources; namespace BUTR.Site.NexusMods.Server.Controllers; @@ -39,7 +40,7 @@ public RecreateStacktraceController(ILogger logger [HttpGet("Json")] [Produces("application/json")] - public async Task?>> GetJsonAsync([FromQuery] CrashReportFileId id, CancellationToken ct) + public async Task?>> GetJsonAsync([BindTenant] TenantId tenant, [FromQuery] CrashReportFileId id, CancellationToken ct) { if (!HttpContext.OwnsTenantGame()) return ApiResultError("Game is not owned!", StatusCodes.Status401Unauthorized); @@ -47,7 +48,7 @@ public RecreateStacktraceController(ILogger logger string crashReportContent; try { - crashReportContent = await _crashReporterClient.GetCrashReportAsync(id, ct); + crashReportContent = await _crashReporterClient.GetCrashReportAsync(tenant, id, ct); } catch (HttpRequestException e) when (e.StatusCode == HttpStatusCode.NotFound) { @@ -76,7 +77,7 @@ public RecreateStacktraceController(ILogger logger [HttpGet("Html")] [Produces("text/plain")] - public async Task> GetHtmlAsync([FromQuery] CrashReportFileId id, CancellationToken ct) + public async Task> GetHtmlAsync([BindTenant] TenantId tenant, [FromQuery] CrashReportFileId id, CancellationToken ct) { if (!HttpContext.OwnsTenantGame()) return Unauthorized(); @@ -84,7 +85,7 @@ public async Task> GetHtmlAsync([FromQuery] CrashReportFile string crashReportContent; try { - crashReportContent = await _crashReporterClient.GetCrashReportAsync(id, ct); + crashReportContent = await _crashReporterClient.GetCrashReportAsync(tenant, id, ct); } catch (HttpRequestException e) when (e.StatusCode == HttpStatusCode.NotFound) { diff --git a/src/BUTR.Site.NexusMods.Server/Controllers/ReportsController.cs b/src/BUTR.Site.NexusMods.Server/Controllers/ReportsController.cs index a9a4e880..20764c1e 100644 --- a/src/BUTR.Site.NexusMods.Server/Controllers/ReportsController.cs +++ b/src/BUTR.Site.NexusMods.Server/Controllers/ReportsController.cs @@ -10,6 +10,7 @@ using System.Threading; using System.Threading.Tasks; +using BUTR.Site.NexusMods.Server.Utils.BindingSources; namespace BUTR.Site.NexusMods.Server.Controllers; @@ -27,7 +28,10 @@ public ReportsController(ILogger logger, ICrashReporterClient [HttpGet("{id}.html")] [Produces("text/html")] - public async Task> GetAllAsync(CrashReportFileId id, CancellationToken ct) => Ok(await _crashReporterClient.GetCrashReportAsync(id, ct)); + public async Task> GetAllAsync([BindTenant] TenantId tenant, CrashReportFileId id, CancellationToken ct) + { + return Ok(await _crashReporterClient.GetCrashReportAsync(tenant, id, ct)); + } // Just so we have ApiResult type in swagger.json [HttpGet("BlankRequest")] diff --git a/src/BUTR.Site.NexusMods.Server/Jobs/CrashReportProcessorJob.cs b/src/BUTR.Site.NexusMods.Server/Jobs/CrashReportProcessorJob.cs index 4f7e41c7..ad573947 100644 --- a/src/BUTR.Site.NexusMods.Server/Jobs/CrashReportProcessorJob.cs +++ b/src/BUTR.Site.NexusMods.Server/Jobs/CrashReportProcessorJob.cs @@ -39,7 +39,7 @@ public async Task Execute(IJobExecutionContext context) { await using var scope = _serviceScopeFactory.CreateAsyncScope().WithTenant(tenant); var crashReportBatchedHandler = scope.ServiceProvider.GetRequiredService(); - await foreach (var batch in _crashReporterClient.GetNewCrashReportMetadatasAsync(DateTime.UtcNow.AddDays(-2), ct).OfType().ChunkAsync(100).WithCancellation(ct)) + await foreach (var batch in _crashReporterClient.GetNewCrashReportMetadatasAsync(tenant, DateTime.UtcNow.AddDays(-2), ct).OfType().ChunkAsync(100).WithCancellation(ct)) processed += await crashReportBatchedHandler.HandleBatchAsync(batch, ct); } diff --git a/src/BUTR.Site.NexusMods.Server/Services/General/ICrashReportBatchedHandler.cs b/src/BUTR.Site.NexusMods.Server/Services/General/ICrashReportBatchedHandler.cs index c4169c78..bef63fbc 100644 --- a/src/BUTR.Site.NexusMods.Server/Services/General/ICrashReportBatchedHandler.cs +++ b/src/BUTR.Site.NexusMods.Server/Services/General/ICrashReportBatchedHandler.cs @@ -148,6 +148,8 @@ await _ignoredCrashReportsChannel.Writer.WriteAsync(new CrashReportIgnoredFileEn private async Task DownloadCrashReportsAsync(CancellationToken ct) { + var tenant = _tenantContextAccessor.Current; + try { var exceptions = new ConcurrentQueue(); @@ -163,11 +165,11 @@ await Parallel.ForEachAsync(_toDownloadChannel.Reader.ReadAllAsync(ct), options, { if (version <= 12) { - content = await _client.GetCrashReportAsync(fileId, ct2); + content = await _client.GetCrashReportAsync(tenant, fileId, ct2); } else { - content = await _client.GetCrashReportJsonAsync(fileId, ct2); + content = await _client.GetCrashReportJsonAsync(tenant, fileId, ct2); } } catch (Exception e) diff --git a/src/BUTR.Site.NexusMods.Server/Services/HttpClients/ICrashReporterClient.cs b/src/BUTR.Site.NexusMods.Server/Services/HttpClients/ICrashReporterClient.cs index 4790fda7..a72dfa15 100644 --- a/src/BUTR.Site.NexusMods.Server/Services/HttpClients/ICrashReporterClient.cs +++ b/src/BUTR.Site.NexusMods.Server/Services/HttpClients/ICrashReporterClient.cs @@ -15,10 +15,10 @@ namespace BUTR.Site.NexusMods.Server.Services; public interface ICrashReporterClient { - Task GetCrashReportAsync(CrashReportFileId id, CancellationToken ct); - Task GetCrashReportJsonAsync(CrashReportFileId id, CancellationToken ct); - IAsyncEnumerable GetNewCrashReportMetadatasAsync(DateTime dateTime, CancellationToken ct); - IAsyncEnumerable GetCrashReportMetadatasAsync(IEnumerable filenames, CancellationToken ct); + Task GetCrashReportAsync(TenantId tenant, CrashReportFileId id, CancellationToken ct); + Task GetCrashReportJsonAsync(TenantId tenant, CrashReportFileId id, CancellationToken ct); + IAsyncEnumerable GetNewCrashReportMetadatasAsync(TenantId tenant, DateTime dateTime, CancellationToken ct); + IAsyncEnumerable GetCrashReportMetadatasAsync(TenantId tenant, IEnumerable filenames, CancellationToken ct); } public sealed class CrashReporterClient : ICrashReporterClient @@ -32,20 +32,20 @@ public CrashReporterClient(HttpClient httpClient, IOptions GetCrashReportAsync(CrashReportFileId id, CancellationToken ct) => await _httpClient.GetStringAsync($"{id}.html", ct); - public async Task GetCrashReportJsonAsync(CrashReportFileId id, CancellationToken ct) => await _httpClient.GetStringAsync($"{id}.json", ct); + public async Task GetCrashReportAsync(TenantId tenant, CrashReportFileId id, CancellationToken ct) => await _httpClient.GetStringAsync($"{tenant}/{id}.html", ct); + public async Task GetCrashReportJsonAsync(TenantId tenant, CrashReportFileId id, CancellationToken ct) => await _httpClient.GetStringAsync($"{tenant}/{id}.json", ct); - public async IAsyncEnumerable GetNewCrashReportMetadatasAsync(DateTime dateTime, [EnumeratorCancellation] CancellationToken ct) + public async IAsyncEnumerable GetNewCrashReportMetadatasAsync(TenantId tenant, DateTime dateTime, [EnumeratorCancellation] CancellationToken ct) { - using var request = new HttpRequestMessage(HttpMethod.Post, "getnewcrashreports"); + using var request = new HttpRequestMessage(HttpMethod.Post, $"{tenant}/getnewcrashreports"); request.Content = JsonContent.Create(new { DateTime = dateTime.ToString("o") }, options: _jsonSerializerOptions); using var response = await _httpClient.SendAsync(request, HttpCompletionOption.ResponseHeadersRead, ct); await foreach (var entry in JsonSerializer.DeserializeAsyncEnumerable(await response.Content.ReadAsStreamAsync(ct), _jsonSerializerOptions, ct)) yield return entry; } - public async IAsyncEnumerable GetCrashReportMetadatasAsync(IEnumerable filenames, [EnumeratorCancellation] CancellationToken ct) + public async IAsyncEnumerable GetCrashReportMetadatasAsync(TenantId tenant, IEnumerable filenames, [EnumeratorCancellation] CancellationToken ct) { - using var request = new HttpRequestMessage(HttpMethod.Post, "getmetadata"); + using var request = new HttpRequestMessage(HttpMethod.Post, $"{tenant}/getmetadata"); request.Content = JsonContent.Create(filenames, options: _jsonSerializerOptions); using var response = await _httpClient.SendAsync(request, HttpCompletionOption.ResponseHeadersRead, ct); await foreach (var entry in JsonSerializer.DeserializeAsyncEnumerable(await response.Content.ReadAsStreamAsync(ct), _jsonSerializerOptions, ct))