From f2b5c12049b8dac0f648cd5ebe6f39b4f3df9441 Mon Sep 17 00:00:00 2001 From: Mauro van der Gun Date: Fri, 11 Aug 2023 09:52:27 -0400 Subject: [PATCH] add support for pagination in list objects calls --- .../src/AmazonS3Adapter.cs | 95 ++++++++++++++----- 1 file changed, 70 insertions(+), 25 deletions(-) diff --git a/FileSystem.Adapters.AmazonS3/src/AmazonS3Adapter.cs b/FileSystem.Adapters.AmazonS3/src/AmazonS3Adapter.cs index ef1441e..04f8bb3 100644 --- a/FileSystem.Adapters.AmazonS3/src/AmazonS3Adapter.cs +++ b/FileSystem.Adapters.AmazonS3/src/AmazonS3Adapter.cs @@ -76,20 +76,27 @@ public override async Task GetDirectoryAsync(string virtualPath, Can } var request = new ListObjectsV2Request {BucketName = bucketName, Prefix = path}; - var response = await client.ListObjectsV2Async(request, cancellationToken); + ListObjectsV2Response response; - if (response.KeyCount == 0) + do { - throw new DirectoryNotFoundException(path, Prefix); - } + response = await client.ListObjectsV2Async(request, cancellationToken); - foreach (var item in response.S3Objects) - { - if (item.Key == path) + if (response.KeyCount == 0) { - return ModelFactory.CreateDirectory(item, virtualPath); + throw new DirectoryNotFoundException(path, Prefix); + } + + foreach (var item in response.S3Objects) + { + if (item.Key == path) + { + return ModelFactory.CreateDirectory(item, virtualPath); + } } - } + + request.ContinuationToken = response.NextContinuationToken; + } while (response.IsTruncated); throw new DirectoryNotFoundException(path, Prefix); } @@ -109,22 +116,35 @@ public override async Task> GetFilesAsync(string virtualPath path += "/"; } + if (path == "/") + { + path = ""; + } + try { var request = new ListObjectsV2Request {BucketName = bucketName, Prefix = path}; - var response = await client.ListObjectsV2Async(request, cancellationToken); + ListObjectsV2Response response; var files = new List(); - foreach (var item in response.S3Objects) + do { - var itemName = item.Key.Substring(0, item.Key.Length - path.Length); + response = await client.ListObjectsV2Async(request, cancellationToken); - if (!item.Key.EndsWith("/") && !itemName.Contains('/')) + foreach (var item in response.S3Objects) { - files.Add(ModelFactory.CreateFile(item, GetVirtualPath(item.Key))); + // var itemName = item.Key.Substring(0, item.Key.Length - path.Length); + var itemName = item.Key.Substring(path.Length).RemoveLeadingForwardSlash(); + + if (!item.Key.EndsWith("/") && !itemName.Contains('/')) + { + files.Add(ModelFactory.CreateFile(item, GetVirtualPath(item.Key))); + } } - } + + request.ContinuationToken = response.NextContinuationToken; + } while (response.IsTruncated); return files; } @@ -139,22 +159,39 @@ public override async Task> GetDirectoriesAsync(string v await GetDirectoryAsync(virtualPath, cancellationToken); var path = GetPath(virtualPath); + if (!path.EndsWith("/")) + { + path += "/"; + } + + if (path == "/") + { + path = ""; + } + try { var request = new ListObjectsV2Request {BucketName = bucketName, Prefix = path}; - var response = await client.ListObjectsV2Async(request, cancellationToken); + ListObjectsV2Response response; var directories = new List(); - foreach (var item in response.S3Objects) + do { - var itemName = item.Key.Substring(path.Length).RemoveLeadingForwardSlash(); + response = await client.ListObjectsV2Async(request, cancellationToken); - if (item.Key.EndsWith("/") && itemName.Count(c => c.Equals('/')) == 1) + foreach (var item in response.S3Objects) { - directories.Add(ModelFactory.CreateDirectory(item, GetVirtualPath(item.Key))); + var itemName = item.Key.Substring(path.Length).RemoveLeadingForwardSlash(); + + if (item.Key.EndsWith("/") && itemName.Count(c => c.Equals('/')) == 1) + { + directories.Add(ModelFactory.CreateDirectory(item, GetVirtualPath(item.Key))); + } } - } + + request.ContinuationToken = response.NextContinuationToken; + } while (response.IsTruncated); return directories; } @@ -197,12 +234,20 @@ public override async Task DeleteDirectoryAsync(string virtualPath, Cancellation var deleteObjectsRequest = new DeleteObjectsRequest {BucketName = bucketName}; var listObjectsRequest = new ListObjectsV2Request {BucketName = bucketName, Prefix = path}; - var response = await client.ListObjectsV2Async(listObjectsRequest, cancellationToken); + ListObjectsV2Response response; - foreach (S3Object entry in response.S3Objects) + do { - deleteObjectsRequest.AddKey(entry.Key); - } + response = await client.ListObjectsV2Async(listObjectsRequest, cancellationToken); + + foreach (S3Object entry in response.S3Objects) + { + deleteObjectsRequest.AddKey(entry.Key); + } + + listObjectsRequest.ContinuationToken = response.NextContinuationToken; + } while (response.IsTruncated); + await client.DeleteObjectsAsync(deleteObjectsRequest, cancellationToken); }