Skip to content

Commit 72e6d47

Browse files
Implement pagination for receving MCR catalog items
1 parent 87375d6 commit 72e6d47

File tree

1 file changed

+73
-14
lines changed

1 file changed

+73
-14
lines changed

src/code/ContainerRegistryServerAPICalls.cs

Lines changed: 73 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,26 @@
11
// Copyright (c) Microsoft Corporation. All rights reserved.
22
// Licensed under the MIT License.
33

4-
using Microsoft.PowerShell.PSResourceGet.UtilClasses;
54
using System;
65
using System.Collections;
76
using System.Collections.Generic;
7+
using System.Collections.ObjectModel;
88
using System.IO;
9-
using System.Net.Http;
10-
using NuGet.Versioning;
11-
using System.Threading.Tasks;
12-
using System.Net;
9+
using System.Linq;
1310
using System.Management.Automation;
14-
using Newtonsoft.Json.Linq;
15-
using Newtonsoft.Json;
16-
using System.Collections.ObjectModel;
11+
using System.Net;
12+
using System.Net.Http;
1713
using System.Net.Http.Headers;
18-
using System.Linq;
19-
using Microsoft.PowerShell.PSResourceGet.Cmdlets;
20-
using System.Text;
2114
using System.Security.Cryptography;
15+
using System.Text;
2216
using System.Text.Json;
17+
using System.Text.RegularExpressions;
18+
using System.Threading.Tasks;
19+
using Microsoft.PowerShell.PSResourceGet.Cmdlets;
20+
using Microsoft.PowerShell.PSResourceGet.UtilClasses;
21+
using Newtonsoft.Json;
22+
using Newtonsoft.Json.Linq;
23+
using NuGet.Versioning;
2324

2425
namespace Microsoft.PowerShell.PSResourceGet
2526
{
@@ -688,7 +689,7 @@ internal JObject FindAllRepositories(string containerRegistryAccessToken, out Er
688689
_cmdletPassedIn.WriteDebug("In ContainerRegistryServerAPICalls::FindAllRepositories()");
689690
string repositoryListUrl = string.Format(containerRegistryRepositoryListTemplate, Registry);
690691
var defaultHeaders = GetDefaultHeaders(containerRegistryAccessToken);
691-
return GetHttpResponseJObjectUsingDefaultHeaders(repositoryListUrl, HttpMethod.Get, defaultHeaders, out errRecord);
692+
return GetHttpResponseJObjectUsingDefaultHeaders(repositoryListUrl, HttpMethod.Get, defaultHeaders, out errRecord, usePagination: true);
692693
}
693694

694695
/// <summary>
@@ -937,7 +938,7 @@ internal async Task<HttpContent> GetHttpContentResponseJObject(string url, Colle
937938
/// <summary>
938939
/// Get response object when using default headers in the request.
939940
/// </summary>
940-
internal JObject GetHttpResponseJObjectUsingDefaultHeaders(string url, HttpMethod method, Collection<KeyValuePair<string, string>> defaultHeaders, out ErrorRecord errRecord)
941+
internal JObject GetHttpResponseJObjectUsingDefaultHeaders(string url, HttpMethod method, Collection<KeyValuePair<string, string>> defaultHeaders, out ErrorRecord errRecord, bool usePagination = false)
941942
{
942943
_cmdletPassedIn.WriteDebug("In ContainerRegistryServerAPICalls::GetHttpResponseJObjectUsingDefaultHeaders()");
943944
try
@@ -946,7 +947,8 @@ internal JObject GetHttpResponseJObjectUsingDefaultHeaders(string url, HttpMetho
946947
HttpRequestMessage request = new HttpRequestMessage(method, url);
947948
SetDefaultHeaders(defaultHeaders);
948949

949-
return SendRequestAsync(request).GetAwaiter().GetResult();
950+
var response = usePagination ? SendRequestAsyncWithPagination(request) : SendRequestAsync(request);
951+
return response.GetAwaiter().GetResult();
950952
}
951953
catch (ResourceNotFoundException e)
952954
{
@@ -1152,6 +1154,63 @@ private async Task<JObject> SendRequestAsync(HttpRequestMessage message)
11521154
return JsonConvert.DeserializeObject<JObject>(await response.Content.ReadAsStringAsync());
11531155
}
11541156

1157+
private async Task<JObject> SendRequestAsyncWithPagination(HttpRequestMessage initialMessage)
1158+
{
1159+
HttpResponseMessage response;
1160+
string nextUrl = initialMessage.RequestUri.ToString();
1161+
JObject finalResult = new JObject();
1162+
JArray allRepositories = new JArray();
1163+
1164+
do
1165+
{
1166+
var message = new HttpRequestMessage(HttpMethod.Get, nextUrl);
1167+
try
1168+
{
1169+
response = await _sessionClient.SendAsync(message);
1170+
}
1171+
catch (Exception e)
1172+
{
1173+
throw new SendRequestException($"Error occurred while sending request to Container Registry server with: {e.GetType()} '{e.Message}'", e);
1174+
}
1175+
1176+
switch (response.StatusCode)
1177+
{
1178+
case HttpStatusCode.OK:
1179+
break;
1180+
case HttpStatusCode.Unauthorized:
1181+
throw new UnauthorizedException($"Response returned status code: {response.ReasonPhrase}.");
1182+
case HttpStatusCode.NotFound:
1183+
throw new ResourceNotFoundException($"Response returned status code package: {response.ReasonPhrase}.");
1184+
default:
1185+
throw new Exception($"Response returned error with status code {response.StatusCode}: {response.ReasonPhrase}.");
1186+
}
1187+
1188+
var content = await response.Content.ReadAsStringAsync();
1189+
var json = JObject.Parse(content);
1190+
var repositories = json["repositories"] as JArray;
1191+
if (repositories != null)
1192+
{
1193+
allRepositories.Merge(repositories);
1194+
}
1195+
1196+
// Check for Link header to continue pagination
1197+
if (response.Headers.TryGetValues("Link", out var linkHeaders))
1198+
{
1199+
var linkHeader = string.Join(",", linkHeaders);
1200+
var match = Regex.Match(linkHeader, @"<([^>]+)>;\s*rel=""next""");
1201+
nextUrl = match.Success ? match.Groups[1].Value : null;
1202+
}
1203+
else
1204+
{
1205+
nextUrl = null;
1206+
}
1207+
1208+
} while (!string.IsNullOrEmpty(nextUrl));
1209+
1210+
finalResult["repositories"] = allRepositories;
1211+
return finalResult;
1212+
}
1213+
11551214
/// <summary>
11561215
/// Send request to get response headers.
11571216
/// </summary>

0 commit comments

Comments
 (0)