Browse the archived sessions in the network analyzer page - #922
Merged
Conversation
An account can be marked with the new flag IsNetworkObservationActive. While it's set, the game server archives the traffic of each session of that account on the file system, so that it can be analyzed later - for example when a player is suspected of cheating. The archive is a feature of the game server, not of the admin panel: it's registered in the all-in-one host and in the Dapr game server host, so an observed account is archived even when no admin panel is running. * A session is a directory below the one of its account, which holds the packets in one or more files of the analyzer tool format plus the metadata as json. That way a session can be opened, copied or deleted as a whole - and each of its files can be loaded by the WinForms tool. * The packets are written by an own task and flushed as soon as its queue ran empty, so that the network thread never waits for the file system, a running session can be read, and a crash doesn't lose everything. * Each line carries a sequence number as a fifth field, which the loader of the analyzer tool ignores. It makes a gap visible - the writer drops packets rather than slowing the connection of the player down when the file system can't keep up. * Rotation, quota and retention keep the archive bounded. The housekeeping runs when a session starts and when one ends; a running session is never removed. * The archive starts when the player is logged in, so the version check and the login request are not part of it. Capturing them would mean to capture every connection unconditionally, which is exactly what this feature avoids. The archive path, the rotation size, the quota, the retention and the live buffer size of the analyzer page are new properties of the system configuration, so they can be edited in the admin panel. Player got a PlayerLoggedIn event, raised by the new SetAccountAsync: at the moment the state machine reaches "Authenticated", the account of the player isn't assigned yet, so the state change is not the right moment to decide whether a session has to be archived. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Pb82LmoaUVdZtBtQs7xrtA
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Pb82LmoaUVdZtBtQs7xrtA
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
Deploying openmudocs with
|
| Latest commit: |
c0d8d7d
|
| Status: | ✅ Deploy successful! |
| Preview URL: | https://47c23423.openmudocs.pages.dev |
| Branch Preview URL: | https://claude-network-analyzer-arch.openmudocs.pages.dev |
Base automatically changed from
claude/network-observation-archive
to
master
September 4, 2026 19:29
The only conflict was in NetworkObservationHandler, which arrived on master with the merge of #917: the observation toggle of this branch added ApplyObservationAsync and split StopSessionAsync out of the disconnect handler, so both additions are kept on top of the version of master. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Pb82LmoaUVdZtBtQs7xrtA
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.
Phase 6 of #895 — the last one. It targets
masternow that #916 and #917 are merged, and the diff 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.
The list only appears when an
IPacketArchiveis 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 sameRequireAuthorization()as every other controller of the panel, resolves the session throughIPacketArchive(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 toICapturedConnectionInfo.SetObservationAsync, which the game server implements: it setsAccount.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.IsObservedandSetObservationAsyncare default interface members onICapturedConnectionInforeturningfalse: 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
AutoFormalready renders it since #917.Tests
11 new tests in
MUnique.OpenMU.Web.Tests: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
PacketArchivein 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, and no warning from a file this PR touches. The page had three StyleCop warnings (member ordering) before; the members were reordered on the way, so it has none now.MUnique.OpenMU.Tests824,Web.Tests88,Network.Tests73 (4 skipped),Network.Packets.Tests588,ChatServer.Tests26,PlugIns.Tests41,Persistence.Initialization.Tests21 (6 skipped),AttributeSystem.Tests44,Pathfinding.Tests9.The last merge of
masterhad one conflict, inNetworkObservationHandler: it came to master with #917, while this branch had addedApplyObservationAsyncto it and splitStopSessionAsyncout of the disconnect handler for the observation toggle. Both additions are kept on top of the version of master; the rest of the file is master's.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