using FinalFactory.Rendezvous.Contracts; namespace FinalFactory.Rendezvous.Client; public sealed class RendezvousSessionBrowserClient : IRendezvousSessionBrowserClient { private readonly RendezvousHttpTransport _transport; public RendezvousSessionBrowserClient( HttpClient httpClient, RendezvousClientOptions? options = null, IRendezvousDelay? delay = null) { _transport = new(httpClient, options, delay); } public Task> BrowseAsync( BrowseSessionsRequest request, CancellationToken cancellationToken = default) { if (request is null) { throw new ArgumentNullException(nameof(request)); } string query = $"v1/sessions?contractVersion={request.ContractVersion}" + $"&gameId={Escape(request.GameId.Value)}" + $"&environmentId={Escape(request.EnvironmentId.Value)}" + $"&protocolVersion={request.ProtocolVersion}" + $"&pageSize={request.PageSize}" + $"&excludeFull={request.ExcludeFull.ToString().ToLowerInvariant()}" + (request.RegionId.HasValue ? $"®ionId={Escape(request.RegionId.Value.Value)}" : string.Empty) + (request.Cursor is not null ? $"&cursor={Escape(request.Cursor)}" : string.Empty); return _transport.SendSafeAsync( () => new HttpRequestMessage(HttpMethod.Get, query), cancellationToken); } public async Task>> BrowseAllAsync( BrowseSessionsRequest request, int maximumPages = 100, CancellationToken cancellationToken = default) { if (request is null) { throw new ArgumentNullException(nameof(request)); } if (maximumPages is < 1 or > 1000) { throw new ArgumentOutOfRangeException(nameof(maximumPages)); } List items = []; string? cursor = request.Cursor; for (int page = 0; page < maximumPages; page++) { BrowseSessionsRequest pageRequest = new() { ContractVersion = request.ContractVersion, GameId = request.GameId, EnvironmentId = request.EnvironmentId, ProtocolVersion = request.ProtocolVersion, RegionId = request.RegionId, PageSize = request.PageSize, ExcludeFull = request.ExcludeFull, Cursor = cursor, }; RendezvousClientResult result = await BrowseAsync( pageRequest, cancellationToken).ConfigureAwait(false); if (!result.IsSuccess || result.Value is null) { return RendezvousClientResult.Failure>( result.Error, result.Message, result.RetryAfterSeconds); } items.AddRange(result.Value.Items); cursor = result.Value.NextCursor; if (string.IsNullOrEmpty(cursor)) { return RendezvousClientResult.Success>(items.AsReadOnly()); } } return RendezvousClientResult.Failure>( RendezvousErrorCode.CapacityExceeded, $"Browsing exceeded the configured {maximumPages}-page limit."); } public Task> GetAsync( SessionListingId listingId, GameId gameId, EnvironmentId environmentId, uint protocolVersion, CancellationToken cancellationToken = default) { string query = $"v1/sessions/{listingId}?contractVersion={ContractLimits.ContractVersion}" + $"&gameId={Escape(gameId.Value)}" + $"&environmentId={Escape(environmentId.Value)}" + $"&protocolVersion={protocolVersion}"; return _transport.SendSafeAsync( () => new HttpRequestMessage(HttpMethod.Get, query), cancellationToken); } private static string Escape(string value) => Uri.EscapeDataString(value ?? string.Empty); }