Skip to content

Browse the archived sessions in the network analyzer page - #922

Open
sven-n wants to merge 1 commit into
claude/network-observation-archivefrom
claude/network-analyzer-archive-browser
Open

Browse the archived sessions in the network analyzer page#922
sven-n wants to merge 1 commit into
claude/network-observation-archivefrom
claude/network-analyzer-archive-browser

Conversation

@sven-n

@sven-n sven-n commented Aug 30, 2026

Copy link
Copy Markdown
Member

Phase 6 of #895 — the last one. Targets the phase 5 branch of #917, so please review/merge that one first; this PR then rebases onto master automatically. The diff shown here is only the phase 6 part.

The sidebar

Below the live connections, the archive of the observed accounts is listed, grouped by account: date, packet count, duration and size per session. A session which is still being written carries a record dot, because its player is still online.

  • Opening a session shows its packets in the same grid, analyzed with the client version which was recorded in its metadata (so a 0.75 session is read as 0.75, not as whatever the page happens to have).
  • A running session is re-read while it's open, so the traffic of an observed player can be followed live. The plan wanted the archive and the live tail merged by sequence number — that turned out to be unnecessary: the archived file is the live tail, since the writer flushes as soon as its queue drains. One source, nothing to merge, no gap and no duplicate by construction.
  • Deleting asks for a confirmation first (the same modal the config grid uses) and then removes the session directory.
  • Downloading hands out the session as one capture file: the parts are concatenated behind a single header line, so it opens in the WinForms tool as one session even when it was rotated.

The list only appears when an IPacketArchive is registered, so the page degrades the same way it already does without a capture service.

The download is not a static file

NetworkArchiveController (api/network-archive/{**sessionId}) streams the session instead of serving the directory statically — an archived session contains the login packet of the player in plain text. It sits behind the same RequireAuthorization() as every other controller of the panel, resolves the session through IPacketArchive (which refuses an id pointing outside the archive), takes the file names from the metadata rather than from the url, and logs the download like the other accesses to the archive.

The observation toggle

The header of a game server connection gets an Observe button. It goes through the new IPacketCaptureService.SetObservationAsync(connectionId, isActive) down to ICapturedConnectionInfo.SetObservationAsync, which the game server implements: it sets Account.IsNetworkObservationActive, persists it through the player (whose context owns that account object — saving it anywhere else would race with the player's own save), and starts or ends the archived session right away, so it needs no reconnect.

IsObserved and SetObservationAsync are default interface members on ICapturedConnectionInfo returning false: the observation is an account setting, and only a game server connection knows an account. The connect and chat server infos stay untouched.

For an offline account the flag is edited in the account editor, where AutoForm already renders it since #917.

Tests

11 new tests in MUnique.OpenMU.Web.Tests:

  • page: the archived sessions are listed; opening one shows its packets with the version from its metadata; deleting one asks the user and removes it; the observation toggle reaches the service and flips the flag; nothing archive-related is shown when no archive is registered;
  • ArchiveList: the empty hint, grouping by account, the download link (including the escaping of an account name with a space), select and delete callbacks (deleting must not open the session), and the marker of a running session.

The archive tests run against a real PacketArchive in a temp directory, so they exercise the file format end to end rather than a mock. That also made two async races in the tests visible, which is why they wait for the state instead of asserting right after the click.

Verification

  • dotnet build src/MUnique.OpenMU.sln -p:ci=true → 0 errors. The page had three StyleCop warnings (member ordering) before this PR; the members were reordered on the way, so it has none now.
  • Complete test suite green: MUnique.OpenMU.Tests 807, Web.Tests 74, Network.Tests 73 (4 skipped), Network.Packets.Tests 588, ChatServer.Tests 26, PlugIns.Tests 41, Persistence.Initialization.Tests 12 (2 skipped), AttributeSystem.Tests 44, Pathfinding.Tests 9. Web.Tests was run three times in a row for the new async tests.
  • No manual run against a live server — that's yours, as agreed.

With this, #895 is complete: capture hook, capture service, the page, the deep links (#916), the observation archive (#917) and the browser here.

🤖 Generated with Claude Code

https://claude.ai/code/session_01Pb82LmoaUVdZtBtQs7xrtA


Generated by Claude Code

The last part of the analyzer page: the archive of the observed accounts is
browsable next to the live connections, and the observation of an account
can be switched on and off while its player is online.

* The sidebar lists the archived sessions below the connections, grouped by
  account, with their date, packet count, duration and size. A session which
  is still being written is marked with a record dot.
* Opening a session shows its packets in the same grid, analyzed with the
  client version which was recorded in its metadata. A running session is
  re-read while it's open, so the traffic of an observed player can be
  followed live - the file is the single source, so there is nothing to
  merge.
* A session can be deleted after a confirmation, and downloaded as one
  capture file: the parts are concatenated behind a single header line, so
  the download opens in the analyzer tool as one session.
* The download goes through a controller of the admin panel instead of a
  static file: an archived session contains the login packet of the player
  in plain text, so it must not be reachable without an authenticated user.
  It's logged like the other accesses to the archive.
* The observation toggle in the header of a game server connection persists
  the account flag through the player and starts or ends the archived
  session right away, without a reconnect.

The member order of the page was fixed on the way, which removes three
StyleCop warnings it had before.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Pb82LmoaUVdZtBtQs7xrtA
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants