Skip to content

Commit

Permalink
Re-introduce Mediator with GetDiskMetricsQuery
Browse files Browse the repository at this point in the history
  • Loading branch information
Jack-Edwards committed Dec 2, 2023
1 parent ef95503 commit 04b2f92
Show file tree
Hide file tree
Showing 7 changed files with 137 additions and 151 deletions.
16 changes: 9 additions & 7 deletions Crypter.API/Controllers/MetricsController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand All @@ -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<IActionResult> 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);
}
}
Original file line number Diff line number Diff line change
@@ -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 <http://www.gnu.org/licenses/>.
*
* 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<PublicStorageMetricsResponse> GetAggregateDiskMetricsAsync(CancellationToken cancellationToken = default);
}

public class ServerMetricsService : IServerMetricsService
{
private readonly DataContext _context;
private readonly TransferStorageSettings _transferStorageSettings;

public ServerMetricsService(DataContext context, IOptions<TransferStorageSettings> transferStorageSettings)
{
_context = context;
_transferStorageSettings = transferStorageSettings.Value;
}

public Task<PublicStorageMetricsResponse> 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 <http://www.gnu.org/licenses/>.
*
* 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
{ }
1 change: 1 addition & 0 deletions Crypter.Core/Crypter.Core.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
<PackageReference Include="Hangfire.PostgreSql" Version="1.20.3" />
<PackageReference Include="Hashids.net" Version="1.7.0" />
<PackageReference Include="MailKit" Version="4.2.0" />
<PackageReference Include="MediatR" Version="12.2.0" />
<PackageReference Include="Microsoft.AspNetCore.Cryptography.KeyDerivation" Version="7.0.11" />
<PackageReference Include="MimeKit" Version="4.2.0" />
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="7.0.11" />
Expand Down
2 changes: 1 addition & 1 deletion Crypter.Core/DependencyInjection.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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<IPasswordHashService, PasswordHashService>();
services.TryAddSingleton<ICryptoProvider, DefaultCryptoProvider>();

services.TryAddScoped<IHangfireBackgroundService, HangfireBackgroundService>();
services.TryAddScoped<IServerMetricsService, ServerMetricsService>();
services.TryAddScoped<ITransferDownloadService, TransferDownloadService>();
services.TryAddScoped<ITransferUploadService, TransferUploadService>();
services.TryAddScoped<IUserAuthenticationService, UserAuthenticationService>();
Expand Down
Original file line number Diff line number Diff line change
@@ -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 <http://www.gnu.org/licenses/>.
*
* 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<PublicStorageMetricsResponse> GetAggregateDiskMetricsAsync(DataContext dataContext,
TransferStorageSettings transferStorageSettings, CancellationToken cancellationToken = default)
{
IQueryable<long> anonymousMessageSizes = dataContext.AnonymousMessageTransfers
.Select(x => x.Size);

IQueryable<long> userMessageSizes = dataContext.UserMessageTransfers
.Select(x => x.Size);

IQueryable<long> anonymousFileSizes = dataContext.AnonymousFileTransfers
.Select(x => x.Size);

IQueryable<long> 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 <http://www.gnu.org/licenses/>.
*
* 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<GetDiskMetricsResult>;

public record GetDiskMetricsResult(long AllocatedBytes, long FreeBytes);

// ReSharper disable once ClassNeverInstantiated.Global
internal sealed class GetDiskMetricsQueryHandler : IRequestHandler<GetDiskMetricsQuery, GetDiskMetricsResult>
{
private readonly DataContext _dataContext;
private readonly TransferStorageSettings _transferStorageSettings;

public GetDiskMetricsQueryHandler(DataContext dataContext, IOptions<TransferStorageSettings> transferStorageSettings)
{
_dataContext = dataContext;
_transferStorageSettings = transferStorageSettings.Value;
}

public async Task<GetDiskMetricsResult> Handle(GetDiskMetricsQuery request, CancellationToken cancellationToken)
{
return await RunQueryAsync(_dataContext, _transferStorageSettings, cancellationToken);
}

public static async Task<GetDiskMetricsResult> RunQueryAsync(DataContext dataContext,
TransferStorageSettings transferStorageSettings, CancellationToken cancellationToken = default)
{
IQueryable<long> anonymousMessageSizes = dataContext.AnonymousMessageTransfers
.Select(x => x.Size);

IQueryable<long> userMessageSizes = dataContext.UserMessageTransfers
.Select(x => x.Size);

IQueryable<long> anonymousFileSizes = dataContext.AnonymousFileTransfers
.Select(x => x.Size);

IQueryable<long> 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);
}
}
17 changes: 10 additions & 7 deletions Crypter.Core/Services/TransferUploadService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -53,24 +55,24 @@ Task<Either<UploadTransferError, UploadTransferResponse>> 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<Either<UploadTransferError, UploadTransferResponse>> UploadFileTransferAsync(Maybe<Guid> senderId,
Expand Down Expand Up @@ -300,8 +302,9 @@ private async Task<Maybe<UploadTransferError>> SaveFileToDiskAsync(TransferUserT
private async Task<bool> 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<Unit> QueueTransferNotificationAsync(Guid itemId, TransferItemType itemType,
Expand Down
12 changes: 0 additions & 12 deletions Crypter.Core/Settings/TransferStorageSettings.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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<TransferStorageSettings> options = null)
{
services.Configure(options);
}
}

public class TransferStorageSettings
{
public int AllocatedGB { get; set; }
Expand Down

0 comments on commit 04b2f92

Please sign in to comment.