Skip to content

feat(dotnet): let DucPushClient and DucStreamer tell Gateway the recording ended - #89

Merged
irvingouj@Devolutions (irvingoujAtDevolution) merged 2 commits into
masterfrom
feat/push-close-recording-ended
Oct 26, 2026
Merged

irvingouj@Devolutions (irvingoujAtDevolution) merged 2 commits into
masterfrom
feat/push-close-recording-ended

Conversation

@irvingoujAtDevolution

@irvingoujAtDevolution irvingouj@Devolutions (irvingoujAtDevolution) commented Oct 19, 2026 •

Copy link
Copy Markdown
Contributor

Lets both .NET push clients close the recording stream with close code 4011, which tells Gateway the recording is over so it ends it right away.

Why: Gateway can't tell "the recording is over" apart from "the producer is reconnecting" (after a resize, or a dropped stream), because both close with 1000. So it keeps every finished recording open until the reconnection window runs out, and live viewers only see the end after that. devolutions-gateway#2116 (DGW-477) makes Gateway end the recording when it gets 4011.

  • DucPushClient.EndRecordingAsync(CancellationToken) (net10.0, used by RDM Windows). CloseAsync and DisposeAsync still send 1000; RDM's resize reconnect depends on that. EndRecordingAsync shares CloseAsync's cancel and receive-loop handling.
  • DucStreamer.EndRecording(CancellationToken) (all TFMs, used by RDM Mac and Linux). Same shape as Disconnect: the V3 (WebSocket) backend closes with 4011; V1/V2 have no close code and just disconnect. Disconnect still sends 1000, because Linux terminal recording calls it right before reconnecting.
  • The 4011 constant lives in one internal GatewayPushCloseCodes class used by both.

Tested:

  • Devolutions.Cadeau builds for all three TFMs with no new warnings.
  • No test in the repo: the test project is a net6.0 console runner that CI doesn't run, and it can't see DucPushClient. Instead a throwaway net10.0 app against a loopback HttpListener WebSocket server checked the close code the server received:
    • DucStreamer.EndRecording after ConnectUrlAsync: 4011, after the payload; after sync ConnectUrl: 4011.
    • DucStreamer.Disconnect: 1000.
    • DucStreamer.EndRecording when never connected: returns null, no throw (same as Disconnect).
    • DucPushClient.EndRecordingAsync: 4011; CloseAsync and DisposeAsync: 1000; an already-cancelled token throws OperationCanceledException.

Follow-up after a Cadeau release (RDM):

  • Windows: StreamingExternalSessionRecorder.EndRecordingAsync calls EndRecordingAsync instead of CloseAsync; ReconnectAsync keeps DisposeAsync.
  • Mac and Linux: the video and terminal ExternalSessionRecorders call EndRecording where the recording really ends, and keep Disconnect on the reconnect path.

Adds `DucPushClient.EndRecordingAsync`, which closes the push stream with
close code 4011. Gateway then ends the recording right away instead of
waiting out the reconnection window.

`CloseAsync` and `DisposeAsync` still send 1000, since RDM drops and
reopens the stream on resize and Gateway has to keep the recording open
for that.

Gateway side: Devolutions/devolutions-gateway#2116 (DGW-477).
Mac and Linux RDM push recordings through DucStreamer, whose WebSocket
(V3) backend always closed with 1000. Gateway keeps such a recording
open for its reconnection window, so live viewers only saw the end
after that delay.

DucStreamer.EndRecording closes the WebSocket with code 4011, which
tells Gateway the recording is over. Disconnect still closes with 1000
because callers also use it before reconnecting. Older protocols have
no close code and just disconnect. The 4011 constant is now shared with
DucPushClient.

Refs: DGW-477, Devolutions/devolutions-gateway#2116
@irvingoujAtDevolution irvingouj@Devolutions (irvingoujAtDevolution) changed the title feat(dotnet): let DucPushClient tell Gateway the recording ended feat(dotnet): let DucPushClient and DucStreamer tell Gateway the recording ended Oct 19, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

2 participants