using FinalFactory.Rendezvous.Contracts; namespace FinalFactory.Rendezvous.Client; public sealed class RendezvousPublisherClient : IRendezvousPublisherClient { private readonly RendezvousHttpTransport _transport; private readonly IRendezvousDelay _delay; public RendezvousPublisherClient( HttpClient httpClient, RendezvousClientOptions? options = null, IRendezvousDelay? delay = null) { _delay = delay ?? new SystemRendezvousDelay(); _transport = new(httpClient, options, _delay); } public async Task> RegisterAsync( RegisterSessionRequest request, string publisherCredential, CancellationToken cancellationToken = default) { if (request is null) { throw new ArgumentNullException(nameof(request)); } RegisterSessionRequest body = CopyRegistration(request); RendezvousClientResult result = await _transport.SendSafeAsync( () => RendezvousHttpTransport.JsonRequest(HttpMethod.Post, "v1/sessions", body, publisherCredential), cancellationToken).ConfigureAwait(false); return result.IsSuccess && result.Value is not null ? RendezvousClientResult.Success(new PublishedSession(result.Value)) : RendezvousClientResult.Failure( result.Error, result.Message, result.RetryAfterSeconds); } public async Task> RenewAsync( PublishedSession session, string publisherCredential, CancellationToken cancellationToken = default) { if (session is null) { throw new ArgumentNullException(nameof(session)); } RendezvousClientResult result = await _transport.SendSafeAsync( () => RendezvousHttpTransport.JsonRequest( HttpMethod.Post, $"v1/sessions/{session.ListingId}/renew", new RenewLeaseRequest { LeaseToken = session.LeaseToken }, publisherCredential), cancellationToken).ConfigureAwait(false); if (result.IsSuccess && result.Value is not null) { session.ExpiresAt = result.Value.ExpiresAt; session.LeaseRenewAfterSeconds = result.Value.RenewAfterSeconds; } return result; } public Task> UpdateAsync( PublishedSession session, UpdateSessionRequest request, string publisherCredential, CancellationToken cancellationToken = default) { if (session is null) { throw new ArgumentNullException(nameof(session)); } if (request is null) { throw new ArgumentNullException(nameof(request)); } UpdateSessionRequest body = new() { ContractVersion = request.ContractVersion, LeaseToken = session.LeaseToken, BuildVersion = request.BuildVersion, DisplayName = request.DisplayName, Capacity = CopyCapacity(request.Capacity), Metadata = CopyMetadata(request.Metadata), DedicatedFallback = RendezvousEndpoint.Copy(request.DedicatedFallback), }; return _transport.SendSafeAsync( () => RendezvousHttpTransport.JsonRequest( HttpMethod.Put, $"v1/sessions/{session.ListingId}", body, publisherCredential), cancellationToken); } public Task> DeregisterAsync( PublishedSession session, string publisherCredential, CancellationToken cancellationToken = default) { if (session is null) { throw new ArgumentNullException(nameof(session)); } return _transport.SendSafeAsync( () => RendezvousHttpTransport.JsonRequest( HttpMethod.Delete, $"v1/sessions/{session.ListingId}", new DeleteSessionRequest { LeaseToken = session.LeaseToken }, publisherCredential), cancellationToken); } public SessionLeaseMaintainer CreateLeaseMaintainer( PublishedSession session, string publisherCredential) => new( this, session ?? throw new ArgumentNullException(nameof(session)), RendezvousHttpTransport.RequireCredential(publisherCredential), _delay); private static RegisterSessionRequest CopyRegistration(RegisterSessionRequest request) => new() { ContractVersion = request.ContractVersion, IdempotencyKey = request.IdempotencyKey, GameId = request.GameId, EnvironmentId = request.EnvironmentId, RegionId = request.RegionId, ProtocolVersion = request.ProtocolVersion, BuildVersion = request.BuildVersion, DisplayName = request.DisplayName, Visibility = request.Visibility, Capacity = CopyCapacity(request.Capacity), Metadata = CopyMetadata(request.Metadata), DedicatedFallback = RendezvousEndpoint.Copy(request.DedicatedFallback), }; private static SessionCapacity CopyCapacity(SessionCapacity capacity) => new() { CurrentPlayers = capacity.CurrentPlayers, MaximumPlayers = capacity.MaximumPlayers, }; private static Dictionary CopyMetadata(Dictionary metadata) => new(metadata, StringComparer.Ordinal); }