Skip to content

feat(core): typed batch references grouped by protocol category - #15

Merged
Agash merged 12 commits into
masterfrom
feat/batch-polish
Aug 25, 2026
Merged

feat(core): typed batch references grouped by protocol category#15
Agash merged 12 commits into
masterfrom
feat/batch-polish

Conversation

@Agash

@Agash Agash commented Aug 25, 2026

Copy link
Copy Markdown
Owner

Acts on the batch DX review, plus the LOGGEN036 warnings that appeared once Microsoft.Extensions.Resilience pulled in the stricter logging generator.

Typed references

Each batch request now hands back a reference carrying its response type, and requests are reached through the protocol's own categories:

ObsBatchBuilder batch = new();
BatchRef<GetVersionResponseData> version = batch.General.GetVersion();
BatchRef<GetSceneListResponseData> scenes = batch.Scenes.GetSceneList(new());

BatchResults results = await client.CallBatchAsync(batch, cancellationToken: ct);

Console.WriteLine(results.Get(version).ObsVersion);

Neither the position nor the response type is restated at the call site, and a request type can appear many times in one batch with each reference still resolving to its own result.

The categories are OBS's own category field from protocol.json, not invented here, so they track the protocol on refresh: canvases, config, filters, general, inputs, media inputs, outputs, record, scene items, scenes, sources, stream, transitions, ui.

This replaces the chainable positional methods rather than adding to them. Capturing a reference takes a statement per request anyway, so the generated method count stays at 147 rather than doubling.

Also

  • TryGet reports a failed or missing result without throwing; reading a reference past a haltOnFailure truncation throws with a message saying why.
  • Add gains a JsonTypeInfo<T> overload so custom payloads stay AOT-safe.
  • LOGGEN036 fixed by typing all 76 generated log parameters. No suppression.

Verified

  • Solution builds with 0 errors and 0 warnings on net9.0/net10.0/net11.0.
  • 23 batch tests covering reference identity, duplicates, ordering, truncation, both transports, and the absent-payload shape.
  • run-transport-tests passes on JSON and MessagePack against OBS 32.2.2, including a batch that repeats one request type three times with two different payloads and reads each back through its own reference.

Agash added 6 commits August 25, 2026 23:21
Batch requests are reached through the protocol's own categories, so
b.Scenes.GetSceneList rather than one flat list of 147 methods, and each
returns a BatchRef carrying its response type. Results are read with
results.Get(reference), which restates neither the position nor the type
and stays correct when a request type appears several times in one batch.

Replaces the chainable positional methods; capturing a reference needs a
statement per request anyway. Count stays at one method per request.

LOGGEN036 is fixed by typing the generated log parameters rather than
suppressing the diagnostic.
Reading them from the shared reader let one result's payload slice run on
into the next. Both transports now slice each result out first.

Parallel batches still mis-pair responseData and are tracked in #16;
serial batches, single requests and both transports are verified by value.
- Add overloads return a BatchRef; the raw index accessor is internal so an
  index cannot be paired with the wrong response type
- BatchResults is an IReadOnlyList
- OverloadResolutionPriority settles Add(null) between the two overloads
- net11 uses the typed GetTypeInfo<T> overload
- The example covers stream buffering under capacity pressure
OBS collects parallel batch results in completion order but labels them
from the submission order, so responseData and requestStatus belong to a
different request than requestType and requestId say. Confirmed in
obs-websocket: RequestBatchHandler.cpp appends results as tasks finish,
and WebSocketServer_Protocol.cpp zips that vector against the original
request array by index.

Reading one by reference now refuses and explains, rather than returning
another request's data. Raw stays available. Tracked in #16.
mediaDuration, mediaCursor and transitionDuration are only null in a
particular state, which the protocol states in the field description
rather than in valueOptional, so they were generated as non-nullable and
failed to deserialize whenever OBS actually sent null. MessagePack threw
outright; JSON reported a missing payload.

The example now reads state back after a media action and cross-checks the
output helpers against the requests they wrap, which is what surfaced it.
Agash added 6 commits August 26, 2026 01:05
Requests and conveniences now sit together in the category they belong to,
so client.Scenes.GetSceneListAsync and client.Scenes.SwitchProgramSceneAsync
read the same way and IntelliSense offers 14 categories rather than 147
flat methods. The groups are partial structs, so generated and hand-written
members share one type and same-named overloads resolve naturally.

The flat extension methods are gone; the batch builder already used these
categories, so both halves of the library now address OBS identically.

SceneItemNotFoundException moves out of the static helper class it was
nested in.
AddObsWebSocketClient(name) reads the endpoint from ConnectionStrings, so
OBS is configured like any other resource an application connects to, with
the password kept off ServerUri. WithAutoConnect replaces the background
service every consumer was writing, and treats an unreachable OBS at
startup as survivable rather than fatal since it is usually started later.
AddObsWebSocket registers a health check for the connection.
Options resolve through IOptionsMonitor rather than the values captured
when the container was built, so a timeout or reconnect setting applies to
the next call that reads it. Changing the endpoint, password or transport
cycles the connection, which the auto-connect service performs.
@Agash
Agash merged commit 461a4e7 into master Aug 25, 2026
7 checks passed
@Agash
Agash deleted the feat/batch-polish branch August 25, 2026 23:29
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant