Skip to content

0.4: modernize the API surface for current .NET conventions #14

Description

@Agash

Tracking the 0.4 work. Breaking changes are acceptable as long as callers update lines, not rewrite.

Landed

API shape

  • The whole surface is grouped by protocol category: client.Scenes.GetSceneListAsync(...), with conveniences sitting in the same group as the requests they wrap. The flat extension methods are gone.
  • Typed batch builder over the same categories, returning BatchRef<T>; results read with results.Get(reference)
  • Per-event IAsyncEnumerable streams alongside the classic events
  • Real C# enums for string-valued protocol enums; constants to const
  • Non-nullable response types (CallRequiredAsync)
  • Typed exceptions carrying the OBS status
  • WaitForEventAsync throws TimeoutException; overloads for waiting without a predicate
  • SwitchProgramSceneAsync / SwitchPreviewSceneAsync replace a bool parameter
  • TryGetSceneItemIdAsync to FindSceneItemIdAsync; int overloads for scene item ids
  • C# 14 extension members

Host and diagnostics

  • AddObsWebSocketClient(name) reading ConnectionStrings
  • WithAutoConnect() hosted service; an unreachable OBS at startup is survivable
  • AddHealthChecks().AddObsWebSocket()
  • Configuration changes apply without a restart, via IOptionsMonitor
  • Keyed DI for multiple OBS instances
  • Options validated on resolve, AOT-safe
  • ActivitySource, and metric instruments built from IMeterFactory
  • [LoggerMessage] throughout with typed parameters, no suppression
  • TimeProvider for every timeout and reconnect delay
  • Reconnect backoff via Microsoft.Extensions.Resilience, with jitter

Fixes found along the way

  • SetSceneItemEnabled never sent sceneName (positional binding after the 5.7 refresh)
  • CustomEvent payload never deserialized
  • Batch results mis-paired on MessagePack; each result is now parsed in isolation
  • Process crash from a timeout timer firing after its source was disposed
  • Fields the protocol documents as nullable in prose were generated non-nullable, so GetMediaInputStatus failed to deserialize whenever media was not playing
  • EventStream deferred argument validation

Decided against

  • Live state projection. OBS is not reliable enough as a source of truth to cache; read at the point of use.
  • IObsWebSocketClient. A source-generated sealed client does not need one, and a narrow interface would mock the low-level calls while leaving the helpers unmockable. Test at the transport instead (Testing package with an in-memory OBS server #18).
  • Shape-matching to recover parallel batch results. 75 of 147 requests return no payload, five groups share identical response shapes, and requestStatus is displaced too. See OBS mis-pairs batch results under Parallel execution (upstream bug) #16.
  • params ReadOnlySpan on the raw batch overload. params must be last, so it cannot coexist with executionType and cancellationToken.

Deferred

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

No labels
No labels

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions