diff --git a/Crypter.API/Controllers/MetricsController.cs b/Crypter.API/Controllers/MetricsController.cs index 86b719828..700ba7970 100644 --- a/Crypter.API/Controllers/MetricsController.cs +++ b/Crypter.API/Controllers/MetricsController.cs @@ -27,7 +27,8 @@ using System.Threading; using System.Threading.Tasks; using Crypter.Common.Contracts.Features.Metrics; -using Crypter.Core.Services; +using Crypter.Core.Features.Metrics.Queries; +using MediatR; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; @@ -36,19 +37,20 @@ namespace Crypter.API.Controllers; [Route("api/metrics")] public class MetricsController : CrypterControllerBase { - private readonly IServerMetricsService _serverMetricsService; + private readonly IMediator _mediator; - public MetricsController(IServerMetricsService serverMetricsService) + public MetricsController(IMediator mediator) { - _serverMetricsService = serverMetricsService; + _mediator = mediator; } [HttpGet("storage/public")] [ProducesResponseType(StatusCodes.Status200OK, Type = typeof(PublicStorageMetricsResponse))] public async Task GetPublicStorageMetricsAsync(CancellationToken cancellationToken) { - PublicStorageMetricsResponse result = - await _serverMetricsService.GetAggregateDiskMetricsAsync(cancellationToken); - return Ok(result); + GetDiskMetricsQuery request = new GetDiskMetricsQuery(); + GetDiskMetricsResult result = await _mediator.Send(request, cancellationToken); + PublicStorageMetricsResponse response = new PublicStorageMetricsResponse(result.AllocatedBytes, result.FreeBytes); + return Ok(response); } } diff --git a/Crypter.Core/Services/ServerMetricsService.cs b/Crypter.Core/AssemblyInfo.cs similarity index 50% rename from Crypter.Core/Services/ServerMetricsService.cs rename to Crypter.Core/AssemblyInfo.cs index 589162913..aaf13f726 100644 --- a/Crypter.Core/Services/ServerMetricsService.cs +++ b/Crypter.Core/AssemblyInfo.cs @@ -1,58 +1,30 @@ -/* - * Copyright (C) 2023 Crypter File Transfer - * - * This file is part of the Crypter file transfer project. - * - * Crypter is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * The Crypter source code is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - * - * You can be released from the requirements of the aforementioned license - * by purchasing a commercial license. Buying such a license is mandatory - * as soon as you develop commercial activities involving the Crypter source - * code without disclosing the source code of your own applications. - * - * Contact the current copyright holder to discuss commercial license options. - */ - -using System.Threading; -using System.Threading.Tasks; -using Crypter.Common.Contracts.Features.Metrics; -using Crypter.Core.Features.Metrics; -using Crypter.Core.Settings; -using Crypter.DataAccess; -using Microsoft.Extensions.Options; - -namespace Crypter.Core.Services; - -public interface IServerMetricsService -{ - Task GetAggregateDiskMetricsAsync(CancellationToken cancellationToken = default); -} - -public class ServerMetricsService : IServerMetricsService -{ - private readonly DataContext _context; - private readonly TransferStorageSettings _transferStorageSettings; - - public ServerMetricsService(DataContext context, IOptions transferStorageSettings) - { - _context = context; - _transferStorageSettings = transferStorageSettings.Value; - } - - public Task GetAggregateDiskMetricsAsync( - CancellationToken cancellationToken = default) - { - return MetricsQueries.GetAggregateDiskMetricsAsync(_context, _transferStorageSettings, cancellationToken); - } -} +/* + * Copyright (C) 2023 Crypter File Transfer + * + * This file is part of the Crypter file transfer project. + * + * Crypter is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The Crypter source code is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + * You can be released from the requirements of the aforementioned license + * by purchasing a commercial license. Buying such a license is mandatory + * as soon as you develop commercial activities involving the Crypter source + * code without disclosing the source code of your own applications. + * + * Contact the current copyright holder to discuss commercial license options. + */ + +namespace Crypter.Core; + +public class AssemblyInfo +{ } diff --git a/Crypter.Core/Crypter.Core.csproj b/Crypter.Core/Crypter.Core.csproj index de2975acb..f4d736fae 100644 --- a/Crypter.Core/Crypter.Core.csproj +++ b/Crypter.Core/Crypter.Core.csproj @@ -13,6 +13,7 @@ + diff --git a/Crypter.Core/DependencyInjection.cs b/Crypter.Core/DependencyInjection.cs index 42eec5d8b..8fcee8af0 100644 --- a/Crypter.Core/DependencyInjection.cs +++ b/Crypter.Core/DependencyInjection.cs @@ -55,12 +55,12 @@ public static IServiceCollection AddCrypterCore(this IServiceCollection services string hangfireConnectionString) { services.AddDataAccess(defaultConnectionString); + services.AddMediatR(cfg => cfg.RegisterServicesFromAssemblyContaining(typeof(AssemblyInfo))); services.TryAddSingleton(); services.TryAddSingleton(); services.TryAddScoped(); - services.TryAddScoped(); services.TryAddScoped(); services.TryAddScoped(); services.TryAddScoped(); diff --git a/Crypter.Core/Features/Metrics/MetricsQueries.cs b/Crypter.Core/Features/Metrics/Queries/GetDiskMetricsQuery.cs similarity index 66% rename from Crypter.Core/Features/Metrics/MetricsQueries.cs rename to Crypter.Core/Features/Metrics/Queries/GetDiskMetricsQuery.cs index 818dc8605..ef0289028 100644 --- a/Crypter.Core/Features/Metrics/MetricsQueries.cs +++ b/Crypter.Core/Features/Metrics/Queries/GetDiskMetricsQuery.cs @@ -1,66 +1,86 @@ -/* - * Copyright (C) 2023 Crypter File Transfer - * - * This file is part of the Crypter file transfer project. - * - * Crypter is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * The Crypter source code is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - * - * You can be released from the requirements of the aforementioned license - * by purchasing a commercial license. Buying such a license is mandatory - * as soon as you develop commercial activities involving the Crypter source - * code without disclosing the source code of your own applications. - * - * Contact the current copyright holder to discuss commercial license options. - */ - -using System; -using System.Linq; -using System.Threading; -using System.Threading.Tasks; -using Crypter.Common.Contracts.Features.Metrics; -using Crypter.Core.Settings; -using Crypter.DataAccess; -using Microsoft.EntityFrameworkCore; - -namespace Crypter.Core.Features.Metrics; - -internal static class MetricsQueries -{ - internal static async Task GetAggregateDiskMetricsAsync(DataContext dataContext, - TransferStorageSettings transferStorageSettings, CancellationToken cancellationToken = default) - { - IQueryable anonymousMessageSizes = dataContext.AnonymousMessageTransfers - .Select(x => x.Size); - - IQueryable userMessageSizes = dataContext.UserMessageTransfers - .Select(x => x.Size); - - IQueryable anonymousFileSizes = dataContext.AnonymousFileTransfers - .Select(x => x.Size); - - IQueryable userFileSizes = dataContext.UserFileTransfers - .Select(x => x.Size); - - long usedBytes = await anonymousMessageSizes - .Concat(userMessageSizes) - .Concat(anonymousFileSizes) - .Concat(userFileSizes) - .SumAsync(cancellationToken); - - long allocatedBytes = transferStorageSettings.AllocatedGB * Convert.ToInt64(Math.Pow(2, 30)); - long freeBytes = allocatedBytes - usedBytes; - - return new PublicStorageMetricsResponse(allocatedBytes, freeBytes); - } -} +/* + * Copyright (C) 2023 Crypter File Transfer + * + * This file is part of the Crypter file transfer project. + * + * Crypter is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The Crypter source code is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + * You can be released from the requirements of the aforementioned license + * by purchasing a commercial license. Buying such a license is mandatory + * as soon as you develop commercial activities involving the Crypter source + * code without disclosing the source code of your own applications. + * + * Contact the current copyright holder to discuss commercial license options. + */ + +using System; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using Crypter.Core.Settings; +using Crypter.DataAccess; +using MediatR; +using Microsoft.EntityFrameworkCore; +using Microsoft.Extensions.Options; + +namespace Crypter.Core.Features.Metrics.Queries; + +public record GetDiskMetricsQuery : IRequest; + +public record GetDiskMetricsResult(long AllocatedBytes, long FreeBytes); + +// ReSharper disable once ClassNeverInstantiated.Global +internal sealed class GetDiskMetricsQueryHandler : IRequestHandler +{ + private readonly DataContext _dataContext; + private readonly TransferStorageSettings _transferStorageSettings; + + public GetDiskMetricsQueryHandler(DataContext dataContext, IOptions transferStorageSettings) + { + _dataContext = dataContext; + _transferStorageSettings = transferStorageSettings.Value; + } + + public async Task Handle(GetDiskMetricsQuery request, CancellationToken cancellationToken) + { + return await RunQueryAsync(_dataContext, _transferStorageSettings, cancellationToken); + } + + public static async Task RunQueryAsync(DataContext dataContext, + TransferStorageSettings transferStorageSettings, CancellationToken cancellationToken = default) + { + IQueryable anonymousMessageSizes = dataContext.AnonymousMessageTransfers + .Select(x => x.Size); + + IQueryable userMessageSizes = dataContext.UserMessageTransfers + .Select(x => x.Size); + + IQueryable anonymousFileSizes = dataContext.AnonymousFileTransfers + .Select(x => x.Size); + + IQueryable userFileSizes = dataContext.UserFileTransfers + .Select(x => x.Size); + + long usedBytes = await anonymousMessageSizes + .Concat(userMessageSizes) + .Concat(anonymousFileSizes) + .Concat(userFileSizes) + .SumAsync(cancellationToken); + + long allocatedBytes = transferStorageSettings.AllocatedGB * Convert.ToInt64(Math.Pow(2, 30)); + long freeBytes = allocatedBytes - usedBytes; + + return new GetDiskMetricsResult(allocatedBytes, freeBytes); + } +} diff --git a/Crypter.Core/Services/TransferUploadService.cs b/Crypter.Core/Services/TransferUploadService.cs index 28a2c5060..11882f09f 100644 --- a/Crypter.Core/Services/TransferUploadService.cs +++ b/Crypter.Core/Services/TransferUploadService.cs @@ -32,7 +32,9 @@ using Crypter.Common.Contracts.Features.Transfer; using Crypter.Common.Enums; using Crypter.Core.Extensions; +using Crypter.Core.Features.Metrics.Queries; using Crypter.Core.Repositories; +using Crypter.Core.Settings; using Crypter.DataAccess; using Crypter.DataAccess.Entities; using EasyMonads; @@ -53,24 +55,24 @@ Task> UploadMessageTransferA public class TransferUploadService : ITransferUploadService { private readonly DataContext _context; - private readonly IServerMetricsService _serverMetricsService; private readonly ITransferRepository _transferStorageService; private readonly IHangfireBackgroundService _hangfireBackgroundService; private readonly IBackgroundJobClient _backgroundJobClient; private readonly IHashIdService _hashIdService; + private readonly TransferStorageSettings _transferStorageSettings; private const int _maxLifetimeHours = 24; private const int _minLifetimeHours = 1; - public TransferUploadService(DataContext context, IServerMetricsService serverMetricsService, - ITransferRepository transferStorageService, IHangfireBackgroundService hangfireBackgroundService, - IBackgroundJobClient backgroundJobClient, IHashIdService hashIdService) + public TransferUploadService(DataContext context, ITransferRepository transferStorageService, + IHangfireBackgroundService hangfireBackgroundService, IBackgroundJobClient backgroundJobClient, + IHashIdService hashIdService, TransferStorageSettings transferStorageSettings) { _context = context; - _serverMetricsService = serverMetricsService; _transferStorageService = transferStorageService; _hangfireBackgroundService = hangfireBackgroundService; _backgroundJobClient = backgroundJobClient; _hashIdService = hashIdService; + _transferStorageSettings = transferStorageSettings; } public async Task> UploadFileTransferAsync(Maybe senderId, @@ -300,8 +302,9 @@ private async Task> SaveFileToDiskAsync(TransferUserT private async Task IsDiskSpaceForTransferAsync(long transferSize, CancellationToken cancellationToken = default) { - var diskMetrics = await _serverMetricsService.GetAggregateDiskMetricsAsync(cancellationToken); - return transferSize <= diskMetrics.Available; + GetDiskMetricsResult diskMetrics = await GetDiskMetricsQueryHandler.RunQueryAsync(_context, _transferStorageSettings, + cancellationToken); + return transferSize <= diskMetrics.FreeBytes; } private async Task QueueTransferNotificationAsync(Guid itemId, TransferItemType itemType, diff --git a/Crypter.Core/Settings/TransferStorageSettings.cs b/Crypter.Core/Settings/TransferStorageSettings.cs index a06caaeb4..838f93471 100644 --- a/Crypter.Core/Settings/TransferStorageSettings.cs +++ b/Crypter.Core/Settings/TransferStorageSettings.cs @@ -24,20 +24,8 @@ * Contact the current copyright holder to discuss commercial license options. */ -using System; -using Microsoft.Extensions.DependencyInjection; - namespace Crypter.Core.Settings; -public static class TransferStorageExtensions -{ - public static void AddTransferStorage(this IServiceCollection services, - Action options = null) - { - services.Configure(options); - } -} - public class TransferStorageSettings { public int AllocatedGB { get; set; }