Skip to content

feat(dgw): let a recorder push its session events log - #2117

Open
irvingouj@Devolutions (irvingoujAtDevolution) wants to merge 6 commits into
feat/provisioning-task-secretsfrom
feat/recording-events-push
Open

irvingouj@Devolutions (irvingoujAtDevolution) wants to merge 6 commits into
feat/provisioning-task-secretsfrom
feat/recording-events-push

Conversation

@irvingoujAtDevolution

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

Copy link
Copy Markdown
Contributor

A recorder can now push a session events log (.slog) next to its recording, on the existing push route, with a push token of its own (same jet_aid, its own jti):

/jet/jrec/push/{id}?fileType=slog&artifact=events

The log goes under artifacts.events in recording.json, not in files. So clips, the shadow stream, the recording policy and remux don't change. Without artifact, a push works like today.

  • A reconnecting recorder appends to the same events-0.slog, while its token can still be reused: same source IP, and the recording push still active or in its reconnect window.
  • A second events push at the same time is refused, like a second clip push.
  • The events push never touches the recording: it doesn't keep the session active, so token reuse, the reconnect window, the delete conflict and the ?active=true listing work exactly like today.
  • The events push has its own token, so it never touches the recording token's replay check. The issuer (DVLS) mints both.
  • An events push before the recording is refused, and creates no session folder or manifest: those belong to the recording.

The AI analysis (#2044) only reads the locale of this log; it writes its own ai-analysis-0.slog.

Where to look hardest: handle_connect_events / handle_disconnect_events in recording.rs, and that nothing else of the recording reads events_pushes.

Tests: unit tests in recording.rs for each case above.

🤖 Generated with Claude Code

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

Token-reuse handling can reject events reconnections and concurrent clip/events startup.

2 open issues
What changed in this PR

Adds recorder-uploaded session events logs alongside recording clips, preparing for later AI enrichment.

Changes:

  • Routes artifact=events pushes to an append-only .slog artifact.
  • Tracks events connections separately from clips.
  • Adds lifecycle and manifest tests.
File Description
devolutions-gateway/​src/​recording.rs Adds events-push lifecycle, append behavior, and tests.
devolutions-gateway/​src/​artifacts.rs Adds events artifact storage and enumeration.
devolutions-gateway/​src/​api/​jrec.rs Validates and routes events push requests.

Review effort: Balanced

Comment thread devolutions-gateway/src/recording.rs Outdated
Comment on lines +935 to +936
self.events_pushes.insert(id);
self.rx.active_recordings.insert(id);
Comment thread devolutions-gateway/src/recording.rs Outdated
Comment on lines +944 to +945
if !self.ongoing_recordings.contains_key(&id) {
self.rx.active_recordings.remove(id);
A recorder can now push a session events log (`.slog`) next to its
recording stream, over the same push WebSocket:

    /jet/jrec/push/{id}?fileType=slog&artifact=events

The log is listed under `artifacts.events` in the manifest, not in
`files`, so it stays out of the clip list, the shadow stream and the
recording policy. A reconnecting recorder appends to the same log. The
session stays active (token reuse, delete conflict) while either push
is connected.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…ame first

An events push that connects before any clip creates the manifest, with
its own connect time as the session start. The first clip now resets
that start, so `startTime` and `duration` describe the recording, not
the wait for it.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
An open events push kept the session in the active recordings, so the push
token stayed reusable for new clips past its reconnect window, until it
expired. The events push now leaves the recording state alone.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
The events push created the session folder and manifest when it came
before the recording, and the first clip then had to reset the session
start for it. The folder and manifest belong to the recording: an events
push now needs the recording of the session to have started, and is
refused before.

The events push has its own push token, separate from the recording's,
so an events push refused this way never touches the recording's token.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
… untested

- The push logs say whether a clip or the events log started or ended.
- The append of a reconnecting events push has no test; an `UNTESTED:`
  comment keeps it from turning into a truncate.
- `handle_connect_events` no longer awaits anything, so it is not async.
- The test waiting for a recording to end gives up after 5 s instead of
  hanging.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

This branch has not been deployed

No deployments
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