diff --git a/uplink.NET/uplink.NET.Sample/uplink.NET.Sample.Shared/ViewModels/BucketContentViewModel.cs b/uplink.NET/uplink.NET.Sample/uplink.NET.Sample.Shared/ViewModels/BucketContentViewModel.cs index 7d082f12..748d6674 100644 --- a/uplink.NET/uplink.NET.Sample/uplink.NET.Sample.Shared/ViewModels/BucketContentViewModel.cs +++ b/uplink.NET/uplink.NET.Sample/uplink.NET.Sample.Shared/ViewModels/BucketContentViewModel.cs @@ -115,7 +115,7 @@ public async Task InitAsync() { var bucket = await _bucketService.GetBucketAsync(BucketName); var listOptions = new ListObjectsOptions(); - var objects = await _objectService.ListObjectsAsync(bucket, listOptions); + var objects = await _objectService.ListObjectsAsync(bucket, listOptions, null, 1000); foreach (var obj in objects.Items) { var entry = new BucketEntryViewModel(this, _bucketService, _objectService); diff --git a/uplink.NET/uplink.NET.Test/ObjectServiceTest.cs b/uplink.NET/uplink.NET.Test/ObjectServiceTest.cs index 492e27fb..561f3827 100644 --- a/uplink.NET/uplink.NET.Test/ObjectServiceTest.cs +++ b/uplink.NET/uplink.NET.Test/ObjectServiceTest.cs @@ -606,6 +606,36 @@ public async Task CopyObject_CopiesObject_InDifferentBucket() } } + [TestMethod] + public async Task ListObjects_WithCursorAndMaxEntries() + { + string bucketname = "listobject-with-cursor-maxentries"; + + await _bucketService.CreateBucketAsync(bucketname); + var bucket = await _bucketService.GetBucketAsync(bucketname); + byte[] bytesToUpload = GetRandomBytes(2048); + + var uploadOperation1 = await _objectService.UploadObjectAsync(bucket, "myfile1.txt", new UploadOptions(), bytesToUpload, false); + await uploadOperation1.StartUploadAsync(); + var uploadOperation2 = await _objectService.UploadObjectAsync(bucket, "myfile2.txt", new UploadOptions(), bytesToUpload, false); + await uploadOperation2.StartUploadAsync(); + var uploadOperation3 = await _objectService.UploadObjectAsync(bucket, "myfile3.txt", new UploadOptions(), bytesToUpload, false); + await uploadOperation3.StartUploadAsync(); + + var listOptions = new ListObjectsOptions { MaxEntries = 2 }; + var objectList = await _objectService.ListObjectsAsync(bucket, listOptions); + + Assert.AreEqual(2, objectList.Items.Count); + Assert.AreEqual("myfile1.txt", objectList.Items[0].Key); + Assert.AreEqual("myfile2.txt", objectList.Items[1].Key); + + listOptions.Cursor = objectList.Items[1].Key; + var objectList2 = await _objectService.ListObjectsAsync(bucket, listOptions); + + Assert.AreEqual(1, objectList2.Items.Count); + Assert.AreEqual("myfile3.txt", objectList2.Items[0].Key); + } + public static byte[] GetRandomBytes(long length) { byte[] bytes = new byte[length]; @@ -640,6 +670,7 @@ public async Task CleanupAsync() await DeleteBucketAsync("copyobject-copies-object-samebucket"); await DeleteBucketAsync("copyobject-copies-object-diffbucket1"); await DeleteBucketAsync("copyobject-copies-object-diffbucket2"); + await DeleteBucketAsync("listobject-with-cursor-maxentries"); } private async Task DeleteBucketAsync(string bucketName) diff --git a/uplink.NET/uplink.NET/Interfaces/IObjectService.cs b/uplink.NET/uplink.NET/Interfaces/IObjectService.cs index 483124f1..40127750 100644 --- a/uplink.NET/uplink.NET/Interfaces/IObjectService.cs +++ b/uplink.NET/uplink.NET/Interfaces/IObjectService.cs @@ -106,6 +106,15 @@ public interface IObjectService /// The list of found objects within the bucket and with the given ListOptions or throws an ObjectListException Task ListObjectsAsync(Bucket bucket, ListObjectsOptions listObjectsOptions); /// + /// Lists objects within a bucket with pagination support + /// + /// The Bucket to list entries from + /// Options for the listing + /// The cursor value to start listing from + /// The maximum number of entries to return + /// The list of found objects within the bucket and with the given ListOptions or throws an ObjectListException + Task ListObjectsAsync(Bucket bucket, ListObjectsOptions listObjectsOptions, string cursor, int maxEntries); + /// /// Gets the specific object /// /// The Bucket where the object resides in diff --git a/uplink.NET/uplink.NET/Models/ListObjectsOptions.cs b/uplink.NET/uplink.NET/Models/ListObjectsOptions.cs index 4062f1da..c3745889 100644 --- a/uplink.NET/uplink.NET/Models/ListObjectsOptions.cs +++ b/uplink.NET/uplink.NET/Models/ListObjectsOptions.cs @@ -29,6 +29,10 @@ public class ListObjectsOptions /// Custom includes CustomMetadata in the results. /// public bool Custom { get; set; } + /// + /// MaxEntries sets the maximum number of entries to return. + /// + public int MaxEntries { get; set; } internal SWIG.UplinkListObjectsOptions ToSWIG() { @@ -38,6 +42,7 @@ internal SWIG.UplinkListObjectsOptions ToSWIG() ret.recursive = Recursive; ret.system = System; ret.custom = Custom; + ret.max_entries = MaxEntries; return ret; } diff --git a/uplink.NET/uplink.NET/Services/ObjectService.cs b/uplink.NET/uplink.NET/Services/ObjectService.cs index 11c13a12..6829ad42 100644 --- a/uplink.NET/uplink.NET/Services/ObjectService.cs +++ b/uplink.NET/uplink.NET/Services/ObjectService.cs @@ -158,6 +158,13 @@ public async Task ListObjectsAsync(Bucket bucket, ListObjectsOptions } } + public async Task ListObjectsAsync(Bucket bucket, ListObjectsOptions listObjectsOptions, string cursor, int maxEntries) + { + listObjectsOptions.Cursor = cursor; + listObjectsOptions.MaxEntries = maxEntries; + return await ListObjectsAsync(bucket, listObjectsOptions).ConfigureAwait(false); + } + public async Task GetObjectAsync(Bucket bucket, string targetPath) { using (var objectResult = await Task.Run(() => SWIG.storj_uplink.uplink_stat_object(_access._project, bucket.Name, targetPath)).ConfigureAwait(false))