diff --git a/src/ByteSync.Client/Services/Communications/Transfers/FileDownloader.cs b/src/ByteSync.Client/Services/Communications/Transfers/FileDownloader.cs index de3e5e89..9b203e60 100644 --- a/src/ByteSync.Client/Services/Communications/Transfers/FileDownloader.cs +++ b/src/ByteSync.Client/Services/Communications/Transfers/FileDownloader.cs @@ -107,26 +107,27 @@ private async Task DownloadFile() break; } - var response = await policy.ExecuteAsync(async () => + var transferParameters = new TransferParameters + { + SessionId = SharedFileDefinition.SessionId, + SharedFileDefinition = SharedFileDefinition, + PartNumber = partNumber + }; + var downloadLocation = await _fileTransferApiClient.GetDownloadFileStorageLocation(transferParameters); + var storageProvider = downloadLocation.StorageProvider; + + var downloadResponse = await policy.ExecuteAsync(async () => { - var transferParameters = new TransferParameters - { - SessionId = SharedFileDefinition.SessionId, - SharedFileDefinition = SharedFileDefinition, - PartNumber = partNumber - }; - var downloadLocation = await _fileTransferApiClient.GetDownloadFileStorageLocation(transferParameters); - var memoryStream = new MemoryStream(); - var downloadStrategy = _strategies[downloadLocation.StorageProvider]; + var downloadStrategy = _strategies[storageProvider]; var response = await downloadStrategy.DownloadAsync(memoryStream, downloadLocation, CancellationTokenSource.Token); DownloadTarget.AddOrReplaceMemoryStream(partNumber, memoryStream); return response; }); - if (response.IsSuccess) + if (downloadResponse.IsSuccess) { - await AssertFilePartIsDownloaded(partNumber); + await AssertFilePartIsDownloaded(partNumber, storageProvider); await _semaphoreSlim.WaitAsync(); try { @@ -166,14 +167,16 @@ private async Task DownloadFile() } } - private async Task AssertFilePartIsDownloaded(int partNumber) + private async Task AssertFilePartIsDownloaded(int partNumber, StorageProvider storageProvider) { var transferParameters = new TransferParameters { SessionId = SharedFileDefinition.SessionId, SharedFileDefinition = SharedFileDefinition, - PartNumber = partNumber + PartNumber = partNumber, + StorageProvider = storageProvider }; + await _filePartDownloadAsserter.AssertAsync(transferParameters); } diff --git a/src/ByteSync.Common/Business/SharedFiles/TransferParameters.cs b/src/ByteSync.Common/Business/SharedFiles/TransferParameters.cs index db995180..64675e6f 100644 --- a/src/ByteSync.Common/Business/SharedFiles/TransferParameters.cs +++ b/src/ByteSync.Common/Business/SharedFiles/TransferParameters.cs @@ -13,4 +13,6 @@ public class TransferParameters public int? TotalParts { get; set; } public List? ActionsGroupIds { get; set; } + + public StorageProvider StorageProvider { get; set; } } \ No newline at end of file diff --git a/src/ByteSync.ServerCommon/Business/Sessions/SharedFileData.cs b/src/ByteSync.ServerCommon/Business/Sessions/SharedFileData.cs index 5efc65a7..4152f4e7 100644 --- a/src/ByteSync.ServerCommon/Business/Sessions/SharedFileData.cs +++ b/src/ByteSync.ServerCommon/Business/Sessions/SharedFileData.cs @@ -9,8 +9,8 @@ public SharedFileData() { } - - public SharedFileData(SharedFileDefinition sharedFileDefinition, ICollection recipients) + + public SharedFileData(SharedFileDefinition sharedFileDefinition, ICollection recipients, StorageProvider storageProvider) { SharedFileDefinition = sharedFileDefinition; @@ -24,11 +24,13 @@ public SharedFileData(SharedFileDefinition sharedFileDefinition, ICollection>(); + + StorageProvider = storageProvider; } public SharedFileDefinition SharedFileDefinition { get; set; } = null!; @@ -78,4 +80,6 @@ public bool IsPartFullyDownloaded(int partNumber) return false; } + + public StorageProvider StorageProvider { get; set; } } \ No newline at end of file diff --git a/src/ByteSync.ServerCommon/Commands/FileTransfers/AssertFilePartIsDownloadedCommandHandler.cs b/src/ByteSync.ServerCommon/Commands/FileTransfers/AssertFilePartIsDownloadedCommandHandler.cs index 5347e5f1..a3352d97 100644 --- a/src/ByteSync.ServerCommon/Commands/FileTransfers/AssertFilePartIsDownloadedCommandHandler.cs +++ b/src/ByteSync.ServerCommon/Commands/FileTransfers/AssertFilePartIsDownloadedCommandHandler.cs @@ -31,7 +31,7 @@ public async Task Handle(AssertFilePartIsDownloadedRequest request, Cancellation if (_transferLocationService.IsSharedFileDefinitionAllowed(sessionMemberData, sharedFileDefinition)) { - await _sharedFilesService.AssertFilePartIsDownloaded(sharedFileDefinition, request.Client, partNumber); + await _sharedFilesService.AssertFilePartIsDownloaded(request.Client, request.TransferParameters); } _logger.LogDebug("File part download asserted for session {SessionId}, file {FileId}, part {PartNumber}", diff --git a/src/ByteSync.ServerCommon/Commands/FileTransfers/AssertFilePartIsUploadedCommandHandler.cs b/src/ByteSync.ServerCommon/Commands/FileTransfers/AssertFilePartIsUploadedCommandHandler.cs index a22fa5f1..5bd51a7d 100644 --- a/src/ByteSync.ServerCommon/Commands/FileTransfers/AssertFilePartIsUploadedCommandHandler.cs +++ b/src/ByteSync.ServerCommon/Commands/FileTransfers/AssertFilePartIsUploadedCommandHandler.cs @@ -51,7 +51,7 @@ public async Task Handle(AssertFilePartIsUploadedRequest request, CancellationTo { var otherSessionMembers = GetOtherSessionMembers(session!, sessionMemberData); - await _sharedFilesService.AssertFilePartIsUploaded(sharedFileDefinition, partNumber, + await _sharedFilesService.AssertFilePartIsUploaded(request.TransferParameters, otherSessionMembers.Select(sm => sm.ClientInstanceId).ToList()); var transferPush = new FileTransferPush diff --git a/src/ByteSync.ServerCommon/Commands/FileTransfers/AssertUploadIsFinishedCommandHandler.cs b/src/ByteSync.ServerCommon/Commands/FileTransfers/AssertUploadIsFinishedCommandHandler.cs index 6cce1a34..5dc51cac 100644 --- a/src/ByteSync.ServerCommon/Commands/FileTransfers/AssertUploadIsFinishedCommandHandler.cs +++ b/src/ByteSync.ServerCommon/Commands/FileTransfers/AssertUploadIsFinishedCommandHandler.cs @@ -47,7 +47,7 @@ public async Task Handle(AssertUploadIsFinishedRequest request, CancellationToke { var otherSessionMembers = GetOtherSessionMembers(session!, sessionMemberData); - await _sharedFilesService.AssertUploadIsFinished(sharedFileDefinition, totalParts, + await _sharedFilesService.AssertUploadIsFinished(request.TransferParameters, otherSessionMembers.Select(sm => sm.ClientInstanceId).ToList()); var transferPush = new FileTransferPush diff --git a/src/ByteSync.ServerCommon/Interfaces/Services/ISharedFilesService.cs b/src/ByteSync.ServerCommon/Interfaces/Services/ISharedFilesService.cs index 4e9c7dee..25b86fe8 100644 --- a/src/ByteSync.ServerCommon/Interfaces/Services/ISharedFilesService.cs +++ b/src/ByteSync.ServerCommon/Interfaces/Services/ISharedFilesService.cs @@ -5,11 +5,11 @@ namespace ByteSync.ServerCommon.Interfaces.Services; public interface ISharedFilesService { - Task AssertFilePartIsUploaded(SharedFileDefinition sharedFileDefinition, int partNumber, ICollection recipients); + Task AssertFilePartIsUploaded(TransferParameters transferParameters, ICollection recipients); - Task AssertUploadIsFinished(SharedFileDefinition sharedFileDefinition, int totalParts, ICollection recipients); + Task AssertUploadIsFinished(TransferParameters transferParameters, ICollection recipients); - Task AssertFilePartIsDownloaded(SharedFileDefinition sharedFileDefinition, Client client, int partNumber); + Task AssertFilePartIsDownloaded(Client client, TransferParameters transferParameters); // Task AssertDownloadIsFinished(SharedFileDefinition sharedFileDefinition, Client client); diff --git a/src/ByteSync.ServerCommon/Services/SharedFilesService.cs b/src/ByteSync.ServerCommon/Services/SharedFilesService.cs index c160f4af..4848c482 100644 --- a/src/ByteSync.ServerCommon/Services/SharedFilesService.cs +++ b/src/ByteSync.ServerCommon/Services/SharedFilesService.cs @@ -11,19 +11,30 @@ public class SharedFilesService : ISharedFilesService { private readonly ISharedFilesRepository _sharedFilesRepository; private readonly IBlobUrlService _blobUrlService; + private readonly ICloudflareR2UrlService _cloudflareR2UrlService; private readonly ILogger _logger; - public SharedFilesService(ISharedFilesRepository sharedFilesRepository, IBlobUrlService blobUrlService, ILogger logger) + public SharedFilesService( + ISharedFilesRepository sharedFilesRepository, + IBlobUrlService blobUrlService, + ICloudflareR2UrlService cloudflareR2UrlService, + ILogger logger) { _sharedFilesRepository = sharedFilesRepository; _blobUrlService = blobUrlService; + _cloudflareR2UrlService = cloudflareR2UrlService; _logger = logger; } - public async Task AssertFilePartIsUploaded(SharedFileDefinition sharedFileDefinition, int partNumber, ICollection recipients) + + public async Task AssertFilePartIsUploaded(TransferParameters transferParameters, ICollection recipients) { + var sharedFileDefinition = transferParameters.SharedFileDefinition; + var partNumber = transferParameters.PartNumber!.Value; + var storageProvider = transferParameters.StorageProvider; + await _sharedFilesRepository.AddOrUpdate(sharedFileDefinition, sharedFileData => { - sharedFileData ??= new SharedFileData(sharedFileDefinition, recipients); + sharedFileData ??= new SharedFileData(sharedFileDefinition, recipients, storageProvider); sharedFileData.UploadedPartsNumbers.Add(partNumber); @@ -31,11 +42,14 @@ await _sharedFilesRepository.AddOrUpdate(sharedFileDefinition, sharedFileData => }); } - public async Task AssertUploadIsFinished(SharedFileDefinition sharedFileDefinition, int totalParts, ICollection recipients) + public async Task AssertUploadIsFinished(TransferParameters transferParameters, ICollection recipients) { + var sharedFileDefinition = transferParameters.SharedFileDefinition; + var totalParts = transferParameters.TotalParts!.Value; + var storageProvider = transferParameters.StorageProvider; await _sharedFilesRepository.AddOrUpdate(sharedFileDefinition, sharedFileData => { - sharedFileData ??= new SharedFileData(sharedFileDefinition, recipients); + sharedFileData ??= new SharedFileData(sharedFileDefinition, recipients, storageProvider); sharedFileData.TotalParts = totalParts; @@ -43,8 +57,10 @@ await _sharedFilesRepository.AddOrUpdate(sharedFileDefinition, sharedFileData => }); } - public async Task AssertFilePartIsDownloaded(SharedFileDefinition sharedFileDefinition, Client downloadedBy, int partNumber) + public async Task AssertFilePartIsDownloaded(Client downloadedBy, TransferParameters transferParameters) { + var sharedFileDefinition = transferParameters.SharedFileDefinition; + var partNumber = transferParameters.PartNumber!.Value; bool deleteBlob = false; bool unregister = false; @@ -74,7 +90,12 @@ await _sharedFilesRepository.AddOrUpdate(sharedFileDefinition, sharedFileData => { try { - await _blobUrlService.DeleteBlob(sharedFileDefinition, partNumber); + await (transferParameters.StorageProvider switch + { + StorageProvider.AzureBlobStorage => _blobUrlService.DeleteBlob(sharedFileDefinition, partNumber), + StorageProvider.CloudflareR2 => _cloudflareR2UrlService.DeleteObject(sharedFileDefinition, partNumber), + _ => throw new NotSupportedException($"Storage provider {transferParameters.StorageProvider} is not supported") + }); } catch (Exception ex) { @@ -105,7 +126,12 @@ public async Task ClearSession(string sessionId) { try { - await _blobUrlService.DeleteBlob(sharedFileData.SharedFileDefinition, i); + await (sharedFileData.StorageProvider switch + { + StorageProvider.AzureBlobStorage => _blobUrlService.DeleteBlob(sharedFileData.SharedFileDefinition, i), + StorageProvider.CloudflareR2 => _cloudflareR2UrlService.DeleteObject(sharedFileData.SharedFileDefinition, i), + _ => throw new NotSupportedException($"Storage provider {sharedFileData.StorageProvider} is not supported") + }); } catch (Exception ex) { diff --git a/src/ByteSync.ServerCommon/Services/SynchronizationProgressService.cs b/src/ByteSync.ServerCommon/Services/SynchronizationProgressService.cs index 029eeb75..36df7925 100644 --- a/src/ByteSync.ServerCommon/Services/SynchronizationProgressService.cs +++ b/src/ByteSync.ServerCommon/Services/SynchronizationProgressService.cs @@ -53,7 +53,13 @@ public async Task InformSynchronizationStarted(SynchronizationEntity synchroniza public async Task UploadIsFinished(SharedFileDefinition sharedFileDefinition, int totalParts, HashSet targetInstanceIds) { - await _sharedFilesService.AssertUploadIsFinished(sharedFileDefinition, totalParts, targetInstanceIds); + var transferParameters = new TransferParameters + { + SessionId = sharedFileDefinition.SessionId, + SharedFileDefinition = sharedFileDefinition, + TotalParts = totalParts + }; + await _sharedFilesService.AssertUploadIsFinished(transferParameters, targetInstanceIds); var fileTransferPush = new FileTransferPush { @@ -68,7 +74,13 @@ public async Task UploadIsFinished(SharedFileDefinition sharedFileDefinition, in public async Task FilePartIsUploaded(SharedFileDefinition sharedFileDefinition, int partNumber, HashSet targetInstanceIds) { - await _sharedFilesService.AssertFilePartIsUploaded(sharedFileDefinition, partNumber, targetInstanceIds); + var transferParameters = new TransferParameters + { + SessionId = sharedFileDefinition.SessionId, + SharedFileDefinition = sharedFileDefinition, + PartNumber = partNumber + }; + await _sharedFilesService.AssertFilePartIsUploaded(transferParameters, targetInstanceIds); var fileTransferPush = new FileTransferPush { diff --git a/tests/ByteSync.ServerCommon.Tests/Commands/FileTransfers/AssertFilePartIsDownloadedCommandHandlerTests.cs b/tests/ByteSync.ServerCommon.Tests/Commands/FileTransfers/AssertFilePartIsDownloadedCommandHandlerTests.cs index d997847f..1b1bd641 100644 --- a/tests/ByteSync.ServerCommon.Tests/Commands/FileTransfers/AssertFilePartIsDownloadedCommandHandlerTests.cs +++ b/tests/ByteSync.ServerCommon.Tests/Commands/FileTransfers/AssertFilePartIsDownloadedCommandHandlerTests.cs @@ -34,7 +34,9 @@ public void Setup() } [Test] - public async Task Handle_ValidRequest_AssertsFilePartIsDownloaded() + [TestCase(StorageProvider.AzureBlobStorage)] + [TestCase(StorageProvider.CloudflareR2)] + public async Task Handle_ValidRequest_AssertsFilePartIsDownloaded(StorageProvider storageProvider) { // Arrange var sessionId = "session1"; @@ -46,7 +48,8 @@ public async Task Handle_ValidRequest_AssertsFilePartIsDownloaded() { SessionId = sessionId, SharedFileDefinition = sharedFileDefinition, - PartNumber = partNumber + PartNumber = partNumber, + StorageProvider = storageProvider }; var request = new AssertFilePartIsDownloadedRequest(sessionId, client, transferParameters); @@ -59,7 +62,7 @@ public async Task Handle_ValidRequest_AssertsFilePartIsDownloaded() .Returns(true); // Mock the shared files service - A.CallTo(() => _mockSharedFilesService.AssertFilePartIsDownloaded(sharedFileDefinition, client, partNumber)) + A.CallTo(() => _mockSharedFilesService.AssertFilePartIsDownloaded(client, transferParameters)) .Returns(Task.CompletedTask); // Act @@ -70,10 +73,14 @@ public async Task Handle_ValidRequest_AssertsFilePartIsDownloaded() .MustHaveHappenedOnceExactly(); A.CallTo(() => _mockTransferLocationService.IsSharedFileDefinitionAllowed(mockSessionMember, sharedFileDefinition)) .MustHaveHappenedOnceExactly(); + A.CallTo(() => _mockSharedFilesService.AssertFilePartIsDownloaded(client, transferParameters)) + .MustHaveHappenedOnceExactly(); } [Test] - public async Task Handle_WhenServiceThrowsException_PropagatesException() + [TestCase(StorageProvider.AzureBlobStorage)] + [TestCase(StorageProvider.CloudflareR2)] + public async Task Handle_WhenServiceThrowsException_PropagatesException(StorageProvider storageProvider) { // Arrange var sessionId = "session1"; @@ -86,7 +93,8 @@ public async Task Handle_WhenServiceThrowsException_PropagatesException() { SessionId = sessionId, SharedFileDefinition = sharedFileDefinition, - PartNumber = partNumber + PartNumber = partNumber, + StorageProvider = storageProvider }; var request = new AssertFilePartIsDownloadedRequest(sessionId, client, transferParameters); diff --git a/tests/ByteSync.ServerCommon.Tests/Repositories/SharedFilesRepositoryTests.cs b/tests/ByteSync.ServerCommon.Tests/Repositories/SharedFilesRepositoryTests.cs index 4d617002..845a036f 100644 --- a/tests/ByteSync.ServerCommon.Tests/Repositories/SharedFilesRepositoryTests.cs +++ b/tests/ByteSync.ServerCommon.Tests/Repositories/SharedFilesRepositoryTests.cs @@ -37,7 +37,9 @@ public void SetUp() } [Test] - public async Task AddOrUpdate_IntegrationTest() + [TestCase(StorageProvider.AzureBlobStorage)] + [TestCase(StorageProvider.CloudflareR2)] + public async Task AddOrUpdate_IntegrationTest(StorageProvider storageProvider) { // Arrange var sharedFileDefinition = new SharedFileDefinition @@ -48,7 +50,7 @@ public async Task AddOrUpdate_IntegrationTest() Func updateHandler = _ => { - var sharedFileData = new SharedFileData(sharedFileDefinition, new List()); + var sharedFileData = new SharedFileData(sharedFileDefinition, new List(), storageProvider); return sharedFileData; }; @@ -65,7 +67,9 @@ public async Task AddOrUpdate_IntegrationTest() } [Test] - public async Task Forget_IntegrationTest() + [TestCase(StorageProvider.AzureBlobStorage)] + [TestCase(StorageProvider.CloudflareR2)] + public async Task Forget_IntegrationTest(StorageProvider storageProvider) { // Arrange var sharedFileDefinition = new SharedFileDefinition @@ -76,7 +80,7 @@ public async Task Forget_IntegrationTest() Func updateHandler = _ => { - var sharedFileData = new SharedFileData(sharedFileDefinition, new List()); + var sharedFileData = new SharedFileData(sharedFileDefinition, new List(), storageProvider); return sharedFileData; }; @@ -92,7 +96,9 @@ public async Task Forget_IntegrationTest() } [Test] - public async Task Clear_IntegrationTest() + [TestCase(StorageProvider.AzureBlobStorage)] + [TestCase(StorageProvider.CloudflareR2)] + public async Task Clear_IntegrationTest(StorageProvider storageProvider) { // Arrange var sharedFileDefinition = new SharedFileDefinition @@ -103,7 +109,7 @@ public async Task Clear_IntegrationTest() Func updateHandler = _ => { - var sharedFileData = new SharedFileData(sharedFileDefinition, new List()); + var sharedFileData = new SharedFileData(sharedFileDefinition, new List(), storageProvider); return sharedFileData; };