54 lines
2.9 KiB
Markdown
54 lines
2.9 KiB
Markdown
# ADR 0007: caller-owned .NET publisher and browser SDK
|
|
|
|
- Status: Accepted
|
|
- Date: 2026-07-16
|
|
- Tracking: #9
|
|
|
|
## Decision
|
|
|
|
The .NET client package exposes separate publisher and browser interfaces plus
|
|
concrete clients over a caller-supplied `HttpClient`. The caller owns that client,
|
|
its handler, base address, connection pool, proxy, and lifetime. SDK operations
|
|
dispose every request, response, and response body they create, but never dispose
|
|
the supplied client. The package targets `netstandard2.1`, depends only on the
|
|
wire-contract package and LiteNetLib, and contains no Godot types, global client,
|
|
service URL, publisher secret, or embedded game credential.
|
|
|
|
Every operation returns `RendezvousClientResult<T>` with a stable error code,
|
|
message, and optional retry guidance. Cancellation remains exceptional through
|
|
the caller's `CancellationToken`; transport failures become `ServiceUnavailable`.
|
|
Response bodies are streamed under the contract's 256 KiB browser ceiling before
|
|
deserialization. Invalid or oversized success bodies become `InternalError` and
|
|
never escape as partially trusted contract objects.
|
|
|
|
The SDK retries only operations whose duplicate execution is safe: scoped reads,
|
|
idempotency-keyed registration, lease renewal with the same lease token, complete
|
|
resource update, and lease-token deregistration. It honors bounded server retry
|
|
guidance and otherwise uses capped exponential backoff with jitter. Each retry
|
|
creates a fresh HTTP request while preserving the caller's registration
|
|
idempotency key. Configuration is copied on construction so later option mutation
|
|
cannot change an in-flight client's behavior.
|
|
|
|
`PublishedSession` holds the server-issued lease and presence capabilities needed
|
|
by the host. Its string representation always redacts them. Update requests are
|
|
copied before the lease token is attached, so the SDK never mutates caller-owned
|
|
DTOs. The browser exposes one-page calls and bounded cursor traversal; cursor
|
|
values remain opaque and caller requests remain unchanged.
|
|
|
|
Lease maintenance is explicit. Creating a `SessionLeaseMaintainer` starts no task;
|
|
the game chooses when to call `RunAsync`, owns cancellation, and awaits
|
|
`DisposeAsync`. The loop uses the latest server-provided renewal interval and
|
|
returns a distinct cancelled, disposed, lost-lease, or failed result. Terminal
|
|
authorization, expiry, and missing-lease responses also raise `LeaseLost` so the
|
|
host can stop advertising or re-register deliberately.
|
|
|
|
## Consequences
|
|
|
|
- SpaceGame and Unscouted can inject the publisher/browser interfaces in tests
|
|
without an engine runtime or real network.
|
|
- Games must configure an absolute `HttpClient.BaseAddress` (or equivalent
|
|
handler routing), obtain publisher credentials from their deployment boundary,
|
|
and explicitly run and dispose lease maintenance.
|
|
- The versioned client public-API snapshot and live-server integration tests fail
|
|
together when SDK and HTTP contracts drift.
|