feat(client): standardize connection outcomes (#13)
quality-gate / quality (push) Successful in 59s

This commit is contained in:
KyuubiYoru
2026-07-16 10:18:41 +02:00
parent b4b6072fe1
commit 94aba8a3bb
47 changed files with 2727 additions and 178 deletions
@@ -29,6 +29,7 @@ internal sealed record EphemeralStoreOptions
public int MaxListings { get; init; } = 25_000;
public int MaxPresenceBindings { get; init; } = 25_000;
public int MaxJoinAttempts { get; init; } = 10_000;
public int MaxOutcomeReports { get; init; } = 35_000;
public int MaxReplayEntries { get; init; } = 30_000;
public int MaxRevocations { get; init; } = 10_000;
public int MaxIdempotencyEntries { get; init; } = 35_000;
@@ -45,6 +46,7 @@ internal sealed record EphemeralStoreOptions
RequirePositive(MaxListings, nameof(MaxListings));
RequirePositive(MaxPresenceBindings, nameof(MaxPresenceBindings));
RequirePositive(MaxJoinAttempts, nameof(MaxJoinAttempts));
RequirePositive(MaxOutcomeReports, nameof(MaxOutcomeReports));
RequirePositive(MaxReplayEntries, nameof(MaxReplayEntries));
RequirePositive(MaxRevocations, nameof(MaxRevocations));
RequirePositive(MaxIdempotencyEntries, nameof(MaxIdempotencyEntries));
@@ -173,6 +175,7 @@ internal sealed record ListingDefinition
public required int CurrentPlayers { get; init; }
public required int MaximumPlayers { get; init; }
public required IReadOnlyDictionary<string, string> Metadata { get; init; }
public NetworkEndpoint? DedicatedFallback { get; init; }
public required SecretFingerprint LeaseFingerprint { get; init; }
public required MediationHandle HostPresenceHandle { get; init; }
public required SecretFingerprint HostPresenceFingerprint { get; init; }
@@ -189,7 +192,17 @@ internal sealed record StoredListing
public static ListingDefinition Freeze(ListingDefinition source) => source with
{
Metadata = source.Metadata.ToFrozenDictionary(StringComparer.Ordinal),
DedicatedFallback = CopyEndpoint(source.DedicatedFallback),
};
internal static NetworkEndpoint? CopyEndpoint(NetworkEndpoint? endpoint) => endpoint is null
? null
: new NetworkEndpoint
{
AddressFamily = endpoint.AddressFamily,
Address = endpoint.Address,
Port = endpoint.Port,
};
}
internal sealed record CreateListingCommand(
@@ -214,7 +227,8 @@ internal sealed record UpdateListingCommand(
string DisplayName,
int CurrentPlayers,
int MaximumPlayers,
IReadOnlyDictionary<string, string> Metadata);
IReadOnlyDictionary<string, string> Metadata,
NetworkEndpoint? DedicatedFallback);
internal sealed record DeleteListingCommand(
SessionListingId ListingId,
@@ -257,6 +271,7 @@ internal sealed record CreateJoinAttemptCommand
public required SecretFingerprint ClientCapabilityFingerprint { get; init; }
public required SecretFingerprint ConnectionTicketFingerprint { get; init; }
public required string CapabilityDerivationSalt { get; init; }
public NetworkEndpoint? DedicatedFallback { get; init; }
public int ScopeAttemptLimit { get; init; } = int.MaxValue;
public override string ToString() => "[CreateJoinAttemptCommand: credentials redacted]";
@@ -280,6 +295,7 @@ internal sealed record StoredJoinAttempt
public required SecretFingerprint HostCapabilityFingerprint { get; init; }
public required SecretFingerprint ClientCapabilityFingerprint { get; init; }
public required SecretFingerprint ConnectionTicketFingerprint { get; init; }
public NetworkEndpoint? DedicatedFallback { get; init; }
public required DateTimeOffset ExpiresAt { get; init; }
public required DateTimeOffset ConnectionTicketExpiresAt { get; init; }
public AttemptEndpointBinding? HostEndpoint { get; init; }
@@ -316,6 +332,16 @@ internal sealed record CancelJoinAttemptCommand(
JoinAttemptId AttemptId,
SecretFingerprint ClientCapabilityFingerprint);
internal sealed record ReportConnectionOutcomeCommand(
JoinAttemptId AttemptId,
SecretFingerprint ClientCapabilityFingerprint,
ConnectionOutcomeKind Outcome,
ConnectionElapsedBucket ElapsedBucket);
internal sealed record StoredConnectionOutcome(
ConnectionOutcomeKind Outcome,
ConnectionElapsedBucket ElapsedBucket);
internal sealed record ConsumeConnectionTicketCommand(
JoinAttemptId AttemptId,
SecretFingerprint ConnectionTicketFingerprint);
@@ -336,6 +362,8 @@ internal enum StoreResultCode
Draining = 6,
ReplayRejected = 7,
ServiceUnavailable = 8,
StaleHost = 9,
IncompatibleProtocol = 10,
}
internal sealed record StoreResult<T>(StoreResultCode Code, T? Value = default, bool IsIdempotentReplay = false)
@@ -359,6 +387,7 @@ internal interface IEphemeralRendezvousStore
StoreResult<StoredJoinAttempt> CreateJoinAttempt(CreateJoinAttemptCommand command, CancellationToken cancellationToken = default);
StoreResult<IReadOnlyList<StoredJoinAttempt>> BrowseHostJoinAttempts(HostJoinAttemptQuery query, CancellationToken cancellationToken = default);
StoreResult<bool> CancelJoinAttempt(CancelJoinAttemptCommand command, CancellationToken cancellationToken = default);
StoreResult<StoredConnectionOutcome> ReportConnectionOutcome(ReportConnectionOutcomeCommand command, CancellationToken cancellationToken = default);
StoreResult<StoredJoinAttempt> BindAttemptEndpoint(BindAttemptEndpointCommand command, CancellationToken cancellationToken = default);
StoreResult<IntroductionEndpoints> ConsumeIntroduction(MediationHandle handle, CancellationToken cancellationToken = default);
StoreResult<bool> ConsumeConnectionTicket(ConsumeConnectionTicketCommand command, CancellationToken cancellationToken = default);