Skip to content

Releases: cirreum/Cirreum.Runtime.RemoteConnections.WebSockets

Release v2.0.2

Choose a tag to compare

@hyspdrt hyspdrt released this 30 Aug 03:01

Full Changelog: v2.0.1...v2.0.2

Release v2.0.1

Choose a tag to compare

@hyspdrt hyspdrt released this 26 Aug 14:04

Full Changelog: v2.0.0...v2.0.1

Release v2.0.0

Choose a tag to compare

@hyspdrt hyspdrt released this 26 Aug 12:29

Cirreum.Runtime.RemoteConnections.WebSockets 2.0.0 — the registration names the connection

Why this release exists

The credential seam beneath this package changed. A credential source used to take no parameters, so
one registration answered identically for every connection an application opened — and where the
host could not infer an audience it supplied its own defaults. For a bridge holding several sockets
to several places, that is not a near miss; it is one answer for questions that have different
answers.

The fix is that a source is told which connection it is supplying for. This package is where that
information exists: it holds TConnection, and the transport beneath it does not.

What's new

A connection names its audience:

builder.AddRemoteConnectionFactory<RealtimeVoiceConnection>(options => {
    options.EndpointUri = new Uri("wss://provider.example.com/realtime");
    options.Scopes = ["api://contoso/access_as_user"];
});

The registration stamps the connection type, and a source registered keyed to that type is
preferred over the unkeyed one:

services.AddKeyedScoped<IRemoteConnectionCredentialSource, ProviderCredentialSource>(typeof(RealtimeVoiceConnection));

That matters more here than on the SignalR side. The founding consumer for raw WebSockets is a
telephony bridge holding one socket to a realtime provider and another to its own backend — two
mechanisms, two identity providers, in one process. Before this, both got whatever the single
ambient source returned.

Fixed

A factory-created connection carries the registered scopes. The factory copies the registered
options per instance, and that copy is the only path a per-session connection's options travel. It
omitted Scopes, which would have left every per-session connection's credential source with no
audience to mint for — silently, since a forgotten property looks exactly like one that was never
set.

The per-session verb is this package's common shape, so the omission would have reached most of its
consumers. Caught by a test written for the copy rather than for the feature.

Compatibility

  • The registration verbs are unchanged, including their overloads, the
    one-registration-per-connection-type rule, registration-time validation, and options-equality
    dedup.
  • One using changes where an application writes a connection type: the connection types moved
    to Cirreum.RemoteServices.Connections.
  • Declare Scopes on connections whose credential comes from the host's session. A connection
    carrying a provider key in AuthorizationHeader or a CredentialProvider never consults the
    ambient source and is unaffected. See MIGRATION-v2.md.

See also

  • Cirreum.RemoteConnections.WebSockets 2.0.0 — the transport that resolves the source, and where
    any authorization scheme may be resolved per attempt rather than only Bearer.
  • Cirreum.Contracts 5.0.0 — the credential contract and the reasoning behind its shape.

Release v1.0.0

Choose a tag to compare

@hyspdrt hyspdrt released this 25 Aug 15:18

Cirreum.Runtime.RemoteConnections.WebSockets 1.0.0

First release of the app-facing registration surface for Cirreum raw WebSocket remote connections.

What this is for

Cirreum.RemoteConnections.WebSockets supplies the connection; this package supplies the line that
registers it. Without it an application composes the wiring itself — build the context from the
provider, construct the connection, decide its lifetime — the same way in every application, which
makes it exactly the kind of thing that drifts.

What it provides

AddRemoteConnectionFactory<TConnection>() is the verb most raw-WebSocket consumers want. A
telephony bridge holds one outbound connection per active call: N concurrent calls, N connections,
each created when the media stream opens and disposed when the call ends.

builder.AddRemoteConnectionFactory<RealtimeVoiceConnection>(options => {
    options.EndpointUri = new Uri("wss://provider.example.com/realtime");
});

It registers IRemoteConnectionFactory<TConnection> and no connection instance, so a status surface
enumerating standing connections never sees per-session ones. Ownership inverts with the lifetime —
the caller creates, connects, and disposes what the factory returns:

await using var voice = this._voiceFactory.Create();
await voice.ConnectAsync(ct);

Create optionally adjusts the registered options for one session — a different deployment, a
per-call subprotocol — leaving the registration untouched for every later one.

AddRemoteConnection<TConnection>() serves the other lifetime: one connection for as long as
the process runs, such as a standing market-data feed. It resolves as TConnection and as
IRemoteConnection, and the container disposes it with the host. Registration does not connect.

Registration rules

One registration per connection type, in either shape. Registering the same type twice with
equal options is a no-op; with different options, or under both verbs, it throws. Subclass the
connection to reach a second endpoint.

The registry is keyed by service collection rather than held process-wide. A registry shared across
a process would make a second container — a test host, a second builder — silently skip registrations
the first container had already claimed.

Options are validated as they are registered. A missing or relative endpoint surfaces while the
application is composing, not when something first resolves the connection.

Host neutrality

Both verbs are extension members on IDomainApplicationBuilder, which a Blazor WebAssembly builder
and a server-side builder both implement. There is no per-host variant, and no .Wasm package.

Requirements

  • Cirreum.RemoteConnections.WebSockets 1.0.0 or later, which carries the transport and
    WebSocketRemoteConnection. It flows in transitively, along with Cirreum.Domain,
    Cirreum.Contracts and Cirreum.Kernel.
  • A host registering IRemoteConnectionTokenSource if connections are to present the session
    credential without configuring one — Cirreum.Runtime.Wasm 3.0.0 does.