Class BowireSseProtocol

Namespace
Kuestenlogik.Bowire.Protocol.Sse
Assembly
Kuestenlogik.Bowire.Protocol.Sse.dll

Bowire protocol plugin for Server-Sent Events (SSE). Discovers SSE endpoints via SseEndpointAttribute, Produces("text/event-stream") metadata, or manual registration. Auto-discovered by BowireProtocolRegistry. Also implements IInlineSseSubscriber so other plugins (MCP notifications, GraphQL graphql-sse subscriptions) can reuse the SSE event-stream parser via FindSseSubscriber() without taking a compile-time dependency on this assembly.

public sealed class BowireSseProtocol : IBowireProtocol, IBowireProxySupport, IInlineSseSubscriber
Inheritance
BowireSseProtocol
Implements
Inherited Members

Constructors

BowireSseProtocol()

public BowireSseProtocol()

Properties

Description

One-line description shown next to the plugin's display name in Settings → Plugins. Optional; defaults to empty so the row falls back to "DisplayName + version" without the description line. Keep it short (≤ 100 characters) — the row truncates anything wider than the manage panel.

public string Description { get; }

Property Value

string

DescriptionKey

#691 — optional catalogue key for Description. When the workbench's active locale has an entry for it, that entry is shown; otherwise Description is, exactly as before. Third-party plugins leave it empty and keep today's behaviour.

public string DescriptionKey { get; }

Property Value

string

IconSvg

SVG icon for the protocol tab.

public string IconSvg { get; }

Property Value

string

Id

Short identifier (e.g., "grpc", "signalr").

public string Id { get; }

Property Value

string

Name

Protocol name shown in UI tabs.

public string Name { get; }

Property Value

string

ProxySupport

How far this plugin's connections follow the proxy.

public BowireProxySupport ProxySupport { get; }

Property Value

BowireProxySupport

Methods

DiscoverAsync(string, bool, IReadOnlyDictionary<string, string>?, CancellationToken)

public Task<List<BowireServiceInfo>> DiscoverAsync(string serverUrl, bool showInternalServices, IReadOnlyDictionary<string, string>? metadata, CancellationToken ct = default)

Parameters

serverUrl string
showInternalServices bool
metadata IReadOnlyDictionary<string, string>
ct CancellationToken

Returns

Task<List<BowireServiceInfo>>

Remarks

Discovery was the one operation with no way to carry configuration, and it is the operation that decides whether anything else can run at all. A gRPC server with reflection switched off could be invoked once a descriptor set was supplied, but could not be enumerated — so a scan could not find the methods it was meant to test, and mTLS-protected servers could not be reflected against at all.

A default implementation that drops the metadata, so a plugin with no per-environment configuration to honour stays exactly as it is. Only a plugin that already reads a marker out of metadata elsewhere has any reason to override it.

DiscoverAsync(string, bool, CancellationToken)

Side-channel marker the discovery endpoint appends to the URL when the caller explicitly hinted sse@…. DiscoverAsync has no hint parameter, and the ad-hoc fallback below must never fire on the hint-less all-plugins fan-out (any URL that happens to answer text/event-stream — legacy MCP SSE transport, graphql-sse — would grow a phantom "SSE Endpoints" service next to the owning plugin's real one).

public Task<List<BowireServiceInfo>> DiscoverAsync(string serverUrl, bool showInternalServices, CancellationToken ct = default)

Parameters

serverUrl string
showInternalServices bool
ct CancellationToken

Returns

Task<List<BowireServiceInfo>>

Remarks

Reads the shared PluginHint marker rather than a private one. The private version needed a constant here and a matching literal in BowireDiscoveryEndpoints, kept together by a comment; SignalR had a second copy of the same arrangement, and the third plugin to want this bit got it wrong instead.

Initialize(IServiceProvider?)

Called after registration to inject the app's service provider (embedded mode).

public void Initialize(IServiceProvider? serviceProvider)

Parameters

serviceProvider IServiceProvider

InvokeAsync(string, string, string, List<string>, bool, Dictionary<string, string>?, CancellationToken)

Invoke a unary or client-streaming call.

public Task<InvokeResult> InvokeAsync(string serverUrl, string service, string method, List<string> jsonMessages, bool showInternalServices, Dictionary<string, string>? metadata = null, CancellationToken ct = default)

Parameters

serverUrl string
service string
method string
jsonMessages List<string>
showInternalServices bool
metadata Dictionary<string, string>
ct CancellationToken

Returns

Task<InvokeResult>

InvokeStreamAsync(string, string, string, List<string>, bool, Dictionary<string, string>?, CancellationToken)

Invoke a server-streaming or duplex call.

public IAsyncEnumerable<string> InvokeStreamAsync(string serverUrl, string service, string method, List<string> jsonMessages, bool showInternalServices, Dictionary<string, string>? metadata = null, CancellationToken ct = default)

Parameters

serverUrl string
service string
method string
jsonMessages List<string>
showInternalServices bool
metadata Dictionary<string, string>
ct CancellationToken

Returns

IAsyncEnumerable<string>

OpenChannelAsync(string, string, string, bool, Dictionary<string, string>?, CancellationToken)

Open an interactive channel (for duplex/client-streaming).

public Task<IBowireChannel?> OpenChannelAsync(string serverUrl, string service, string method, bool showInternalServices, Dictionary<string, string>? metadata = null, CancellationToken ct = default)

Parameters

serverUrl string
service string
method string
showInternalServices bool
metadata Dictionary<string, string>
ct CancellationToken

Returns

Task<IBowireChannel>

RegisterEndpoint(SseEndpointInfo)

Register an SSE endpoint for Bowire discovery. Call before MapBowire() or during startup.

public static void RegisterEndpoint(SseEndpointInfo endpoint)

Parameters

endpoint SseEndpointInfo

SubscribeAsync(string, Dictionary<string, string>?, CancellationToken)

Open an SSE connection to url with the given request headers and yield each parsed event as a JSON envelope of the form { id, event, data, retry }. The stream stays open until the server closes it or ct is cancelled.

public IAsyncEnumerable<string> SubscribeAsync(string url, Dictionary<string, string>? headers, CancellationToken ct = default)

Parameters

url string
headers Dictionary<string, string>
ct CancellationToken

Returns

IAsyncEnumerable<string>