using FinalFactory.Rendezvous.Contracts; using FinalFactory.Rendezvous.Server.Provisioning; using FinalFactory.Rendezvous.Server.Sessions; using FinalFactory.Rendezvous.Server.State; using FinalFactory.Rendezvous.Tests.Provisioning; using FinalFactory.Rendezvous.Tests.State; namespace FinalFactory.Rendezvous.Tests.Sessions; internal sealed class SessionLeaseFixture : IDisposable { private int _sequence; public SessionLeaseFixture(EphemeralStoreOptions? storeOptions = null) { StoreOptions = storeOptions ?? new EphemeralStoreOptions(); Clock = new(); Store = new(StoreOptions, Clock, Clock); Capabilities = new(); GamePolicyRegistry policies = GamePolicyRegistry.Create([ProvisioningTestData.CreatePolicy()]); Service = new( new PublisherAuthorizationService(policies), Store, Capabilities, SessionLeaseTiming.From(StoreOptions), Clock); Principal = Publisher("publisher-1"); } public EphemeralStoreOptions StoreOptions { get; } public ManualRendezvousClock Clock { get; } public InMemoryEphemeralRendezvousStore Store { get; } public EphemeralCapabilityIssuer Capabilities { get; } public SessionLeaseService Service { get; } public DedicatedPublisherPrincipal Principal { get; } public TenantScope Scope { get; } = new(new("space-game"), new("production")); public DedicatedPublisherPrincipal Publisher(string subject) => new( subject, Clock.UtcNow.AddMinutes(10), Scope.GameId, Scope.EnvironmentId, new HashSet { new("eu-central") }); public RegisterSessionRequest Request(string? idempotencyKey = null) => new() { IdempotencyKey = idempotencyKey ?? $"register-{Interlocked.Increment(ref _sequence)}", GameId = Scope.GameId, EnvironmentId = Scope.EnvironmentId, RegionId = new("eu-central"), ProtocolVersion = 7, BuildVersion = "1.4.2", DisplayName = "Europa Relay", Visibility = ListingVisibility.Public, Capacity = new() { CurrentPlayers = 2, MaximumPlayers = 8 }, Metadata = new Dictionary(StringComparer.Ordinal) { ["mode"] = "co-op", ["map"] = "europa", }, }; public RegisterSessionResponse Register( RegisterSessionRequest? request = null, DedicatedPublisherPrincipal? principal = null) { SessionServiceResult result = Service.Register( principal ?? Principal, request ?? Request()); Assert.True(result.Succeeded); Assert.NotNull(result.Value); return result.Value; } public StoreResult BindPresence(RegisterSessionResponse registration) { Assert.True(Capabilities.TryFingerprint( registration.HostPresenceCapability, out SecretFingerprint fingerprint)); return Store.BindHostPresence(new( registration.HostPresenceHandle, fingerprint, new(AddressFamilyKind.Ipv4, "203.0.113.50", 40_000), new ObservedEndpoint(AddressFamilyKind.Ipv4, "192.168.1.50", 40_000))); } public IReadOnlyList Browse() => Store.BrowseVisibleListings(new( Scope, 7, new RegionId("eu-central"))).Value!; public void Dispose() => Capabilities.Dispose(); }