Repository navigation
feat(dotnet): let DucPushClient and DucStreamer tell Gateway the recording ended - #89
Merged
irvingouj@Devolutions (irvingoujAtDevolution) merged 2 commits intoOct 26, 2026
Conversation
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
Marc-André Moreau (mamoreau-devolutions)
approved these changes
Oct 26, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
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).CloseAsyncandDisposeAsyncstill send 1000; RDM's resize reconnect depends on that.EndRecordingAsyncsharesCloseAsync's cancel and receive-loop handling.DucStreamer.EndRecording(CancellationToken)(all TFMs, used by RDM Mac and Linux). Same shape asDisconnect: the V3 (WebSocket) backend closes with 4011; V1/V2 have no close code and just disconnect.Disconnectstill sends 1000, because Linux terminal recording calls it right before reconnecting.GatewayPushCloseCodesclass used by both.Tested:
Devolutions.Cadeaubuilds for all three TFMs with no new warnings.DucPushClient. Instead a throwaway net10.0 app against a loopbackHttpListenerWebSocket server checked the close code the server received:DucStreamer.EndRecordingafterConnectUrlAsync: 4011, after the payload; after syncConnectUrl: 4011.DucStreamer.Disconnect: 1000.DucStreamer.EndRecordingwhen never connected: returns null, no throw (same asDisconnect).DucPushClient.EndRecordingAsync: 4011;CloseAsyncandDisposeAsync: 1000; an already-cancelled token throwsOperationCanceledException.Follow-up after a Cadeau release (RDM):
StreamingExternalSessionRecorder.EndRecordingAsynccallsEndRecordingAsyncinstead ofCloseAsync;ReconnectAsynckeepsDisposeAsync.ExternalSessionRecorders callEndRecordingwhere the recording really ends, and keepDisconnecton the reconnect path.