feat: add publisher and browser client SDK (#9)
quality-gate / quality (push) Successful in 1m6s
quality-gate / quality (push) Successful in 1m6s
Closes #9
This commit is contained in:
@@ -0,0 +1,141 @@
|
||||
using FinalFactory.Rendezvous.Contracts;
|
||||
|
||||
namespace FinalFactory.Rendezvous.Client;
|
||||
|
||||
public sealed class RendezvousClientResult<T>
|
||||
{
|
||||
internal RendezvousClientResult(
|
||||
RendezvousErrorCode error,
|
||||
T? value,
|
||||
string message,
|
||||
int? retryAfterSeconds)
|
||||
{
|
||||
Error = error;
|
||||
Value = value;
|
||||
Message = message;
|
||||
RetryAfterSeconds = retryAfterSeconds;
|
||||
}
|
||||
|
||||
public bool IsSuccess => Error == RendezvousErrorCode.None;
|
||||
public RendezvousErrorCode Error { get; }
|
||||
public T? Value { get; }
|
||||
public string Message { get; }
|
||||
public int? RetryAfterSeconds { get; }
|
||||
|
||||
}
|
||||
|
||||
public static class RendezvousClientResult
|
||||
{
|
||||
public static RendezvousClientResult<T> Success<T>(T value) =>
|
||||
value is null
|
||||
? throw new ArgumentNullException(nameof(value))
|
||||
: new(RendezvousErrorCode.None, value, string.Empty, null);
|
||||
|
||||
public static RendezvousClientResult<T> Failure<T>(
|
||||
RendezvousErrorCode error,
|
||||
string message,
|
||||
int? retryAfterSeconds = null) =>
|
||||
error == RendezvousErrorCode.None
|
||||
? throw new ArgumentException("A failure requires a non-success error.", nameof(error))
|
||||
: new(error, default, message ?? string.Empty, retryAfterSeconds);
|
||||
}
|
||||
|
||||
public sealed class PublishedSession
|
||||
{
|
||||
internal PublishedSession(RegisterSessionResponse response)
|
||||
{
|
||||
ListingId = response.ListingId;
|
||||
LeaseId = response.LeaseId;
|
||||
LeaseToken = response.LeaseToken;
|
||||
HostPresenceHandle = response.HostPresenceHandle;
|
||||
HostPresenceCapability = response.HostPresenceCapability;
|
||||
ExpiresAt = response.ExpiresAt;
|
||||
LeaseRenewAfterSeconds = response.LeaseRenewAfterSeconds;
|
||||
HostPresenceRefreshAfterSeconds = response.HostPresenceRefreshAfterSeconds;
|
||||
}
|
||||
|
||||
public SessionListingId ListingId { get; }
|
||||
public LeaseId LeaseId { get; }
|
||||
public string LeaseToken { get; }
|
||||
public MediationHandle HostPresenceHandle { get; }
|
||||
public string HostPresenceCapability { get; }
|
||||
public DateTimeOffset ExpiresAt { get; internal set; }
|
||||
public int LeaseRenewAfterSeconds { get; internal set; }
|
||||
public int HostPresenceRefreshAfterSeconds { get; }
|
||||
|
||||
public override string ToString() => $"[PublishedSession {ListingId}; credentials redacted]";
|
||||
}
|
||||
|
||||
public interface IRendezvousPublisherClient
|
||||
{
|
||||
Task<RendezvousClientResult<PublishedSession>> RegisterAsync(
|
||||
RegisterSessionRequest request,
|
||||
string publisherCredential,
|
||||
CancellationToken cancellationToken = default);
|
||||
|
||||
Task<RendezvousClientResult<RenewLeaseResponse>> RenewAsync(
|
||||
PublishedSession session,
|
||||
string publisherCredential,
|
||||
CancellationToken cancellationToken = default);
|
||||
|
||||
Task<RendezvousClientResult<bool>> UpdateAsync(
|
||||
PublishedSession session,
|
||||
UpdateSessionRequest request,
|
||||
string publisherCredential,
|
||||
CancellationToken cancellationToken = default);
|
||||
|
||||
Task<RendezvousClientResult<bool>> DeregisterAsync(
|
||||
PublishedSession session,
|
||||
string publisherCredential,
|
||||
CancellationToken cancellationToken = default);
|
||||
}
|
||||
|
||||
public interface IRendezvousSessionBrowserClient
|
||||
{
|
||||
Task<RendezvousClientResult<BrowseSessionsResponse>> BrowseAsync(
|
||||
BrowseSessionsRequest request,
|
||||
CancellationToken cancellationToken = default);
|
||||
|
||||
Task<RendezvousClientResult<IReadOnlyList<SessionListing>>> BrowseAllAsync(
|
||||
BrowseSessionsRequest request,
|
||||
int maximumPages = 100,
|
||||
CancellationToken cancellationToken = default);
|
||||
|
||||
Task<RendezvousClientResult<GetSessionResponse>> GetAsync(
|
||||
SessionListingId listingId,
|
||||
GameId gameId,
|
||||
EnvironmentId environmentId,
|
||||
uint protocolVersion,
|
||||
CancellationToken cancellationToken = default);
|
||||
}
|
||||
|
||||
public interface IRendezvousDelay
|
||||
{
|
||||
Task DelayAsync(TimeSpan delay, CancellationToken cancellationToken);
|
||||
}
|
||||
|
||||
public sealed class RendezvousClientOptions
|
||||
{
|
||||
public int MaximumSafeRetries { get; set; } = 2;
|
||||
public TimeSpan InitialRetryDelay { get; set; } = TimeSpan.FromMilliseconds(200);
|
||||
public TimeSpan MaximumRetryDelay { get; set; } = TimeSpan.FromSeconds(2);
|
||||
public double JitterRatio { get; set; } = 0.2;
|
||||
|
||||
internal void Validate()
|
||||
{
|
||||
if (MaximumSafeRetries is < 0 or > 5
|
||||
|| InitialRetryDelay < TimeSpan.Zero
|
||||
|| MaximumRetryDelay < InitialRetryDelay
|
||||
|| MaximumRetryDelay > TimeSpan.FromSeconds(30)
|
||||
|| JitterRatio is < 0 or > 1)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(nameof(RendezvousClientOptions));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal sealed class SystemRendezvousDelay : IRendezvousDelay
|
||||
{
|
||||
public Task DelayAsync(TimeSpan delay, CancellationToken cancellationToken) =>
|
||||
Task.Delay(delay, cancellationToken);
|
||||
}
|
||||
Reference in New Issue
Block a user