Add the network analyzer page to the admin panel - #907
Open
sven-n wants to merge 4 commits into
Open
Conversation
The page shows the connections of all servers of this process and the traffic of a selected one. It's the first part which is visible to an admin - the archive of observed accounts follows later. * The connections are listed in a collapsible sidebar, grouped by their server and searchable by name or endpoint. Each entry can be selected or disconnected. * Selecting a connection starts a capture and shows its packets in a virtualized grid, with the direction, the size, the code and the extracted short information of each packet. A selected packet is shown with its raw data and all extracted fields. * The packets can be filtered by direction and by a text which is matched against the code, the raw data and the message. The view can be paused and cleared without stopping the capture. * The packet definition set and the client version come from the connection, so the traffic of the connect server is analyzed with the connect server definitions without asking the user. The page and its menu entry are only shown when an IPacketCaptureService is registered, which is the case in the all-in-one deployment. Two fixes which were found while running it: * The PacketAnalyzer loaded its definition files relative to the working directory. They are copied next to the binaries, which is not the same directory when the server isn't started from its own folder - the analyzer then failed to load them. It uses the base directory of the application now. * ICapturedConnectionInfo provides the description of its server, so the connections can be grouped by a readable caption instead of the internal server id. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Pb82LmoaUVdZtBtQs7xrtA
The traffic can be followed now: while it's active, the newest packets are shown on top, so the live traffic stays visible without scrolling. A real auto scroll would either need javascript to move the scroll position - which also fights with the scroll position of the user - or a scroll container with 'flex-direction: column-reverse', which is not compatible with the virtualization of the grid. Showing the newest packets first achieves the same without both. The components are tested with bUnit: * ConnectionList: grouping by server description, filtering by the search term, the selection and that the disconnect button doesn't select the connection. * PacketGrid: the direction, timestamp and size of the packets, the extracted message, the raw data as fallback without an analyzer, and the selection. * PacketDetail: the raw data and the extracted fields. * The page: the note when the capture service isn't registered, the listed connections, that a selection (also a preselected one from the route) starts the capture, and the order of the packets with and without following. The tests of the grid and the detail use a real PacketAnalyzer, so they also cover that its definition files are found next to the binaries. The QuickGrid virtualizes its rows, which requires javascript to measure the viewport - it's therefore a parameter of the PacketGrid now, so the tests can render the rows. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Pb82LmoaUVdZtBtQs7xrtA
sven-n
force-pushed
the
claude/network-analyzer-page
branch
from
August 27, 2026 18:19
882c56c to
e0e3360
Compare
Member
Author
The packets are in chronological order again - the newest one is the last row - and the grid scrolls to it while the traffic is followed. That's done by a small javascript module, like the log viewer does it. * The grid has a fixed height now, based on the number of rows which should be visible at once (15 by default). Its scrollbar is always shown, so the layout doesn't jump when the first packets arrive, and the rows stay virtualized. * The details of a selected packet are shown inside its row instead of below the whole table, so they belong to the packet which is looked at. The height of the raw data and of the extracted information is limited, so a big packet doesn't blow up the row. * The styles of the detail moved into its own component stylesheet. Scoped styles of the page don't apply to the elements of a child component, so they had no effect there anyway. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Pb82LmoaUVdZtBtQs7xrtA
The scrollbars appeared on the page instead of the grid, because the styles were in the stylesheet of the page while the elements are rendered by the components: a scoped stylesheet only applies to the markup of its own component, so the rules never matched. The height of the grid was applied - it's set inline - but nothing clipped its content, so the page grew instead. The styles moved to the components they belong to, and the column headers of the grid stay visible while scrolling. Because they are part of the QuickGrid, which is a child component, the scope of the stylesheet has to be lifted with ::deep for them. 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 3 of #895 — the first part which is actually visible to an admin. Builds on the capture hook (#897) and the capture service (#901), both on master now.
The page
/network-analyzershows the connections of all servers of this process on the left and the traffic of the selected one on the right.QuickGridwith timestamp, direction, size, code and the extracted short information. Selecting a packet shows its raw data and all extracted fields.PacketAnalyzerwere for.The page and its menu entry only appear when an
IPacketCaptureServiceis registered, which is the case in the all-in-one deployment. In the distributed deployment the page shows an explanatory note instead. The service is resolved throughIServiceProvider.GetServicerather than[Inject], because Blazor throws for an unregistered service even on a nullable property — the same patternServers.razoruses for the optional game server dictionary.Two fixes found by running it
I ran the server in demo mode and drove the page in a browser, which turned up two things:
PacketAnalyzerloaded its definition files relative to the working directory. They are copied next to the binaries, which is a different directory whenever the server isn't started from its own folder — the analyzer then threwFileNotFoundExceptionand took the Blazor circuit down with it. It resolves them againstAppContext.BaseDirectorynow, and a missing file leaves the definitions empty instead of throwing (the grid then still shows the raw data). This affects the deployed server generally, not just the page.ICapturedConnectionInfonow provides the description of its server, so the groups are captioned "Connect Server (Season 6 Episode 3 GMO Client)" instead of "Connect Server 65536" — the connect server ids start atSpecialServerIds.ConnectServer.Verification
Besides the build and the test suite, I ran the whole thing:
dotnet run -- -demo -resolveIP:local, opened TCP clients against a connect server and a game server, and drove the page in Chromium.Both connections were listed under their servers, and selecting the connect server client showed its traffic — including a
C2response, so the reassembly of the outgoing pipe from phase 1 is confirmed under real conditions:The detail pane showed
C2 00 13 F4 06 00 03 00 00 00 00 01 00 00 00 02 00 00 00with the extractedServerListResponse / ServerCount: 3. No Blazor errors, no console errors.dotnet build MUnique.OpenMU.sln -p:ci=true→ 0 errors; no warning originates in a file this PR adds or changes.Notes
.gitignoregaineddata-protection-keys/, which ASP.NET creates in the working directory when you run the server locally.🤖 Generated with Claude Code
https://claude.ai/code/session_01Pb82LmoaUVdZtBtQs7xrtA
Generated by Claude Code