[pull] master from Ehco1996:master#312
Merged
Merged
Conversation
* xray: replace gRPC stats/handler with in-process user mgmt + conn tracker Drop the gRPC StatsService polling and HandlerService roundtrip: xray's inbound.Manager is reached directly for AddUser/RemoveUser, and a custom outbound replaces the default freedom outbound to count bytes per user and register every dialed conn in a tracker. The tracker backs a small admin API (GET/DELETE /api/v1/xray/conns) so the upstream can list and kill live conns without going through xray. Per-user upload/download counters become atomic and are snapshot-and-reset on each upstream sync. The api inbound, policy.system stats, Stats and OutboundConfigs blocks are stripped programmatically before core.New so xray's stats accumulators don't run unused. E2E tests cover trojan / vless / ss2022 over TCP, trojan / ss2022 over UDP, and vless+REALITY — each verifies echo round-trip, tracker registration, per-user counters, and KillByUser semantics. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * xray: simplify outbound + user.go + e2e harness, wire test-e2e make target - outbound.go: drop dead direction enum, fold the wrap helpers and the meteringWriter.Close indirection — counter wrap is now a single if-block in Dispatch. - user.go: replace the hand-rolled containsLower with strings.Contains + strings.ToLower. - e2e_test.go: collapse the per-protocol orchestration into a single runScenario that takes a serverCfg/clientFactory/runSession trio. TCP and UDP each have one shared session helper; the 6 tests are now ~12-line scenario constructions. - Makefile: bump make test timeout to 3m for e2e headroom; add a test-e2e shortcut for fast iteration. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * fix pricing * xray: report access IP per user, fix outbound lint - Make connEntry hold *session.Inbound/*session.Outbound directly so source IP is available without duplicating fields; expose SourceIP on the admin /xray/conns response - Per-user FIFO IP set (cap 10) recorded in metered outbound and snapshotted alongside byte counters; populates UserTraffic.IPList - Populate UserTraffic.TcpCount from connTracker.CountTCPByUser at sync time - Fix errcheck lint: discard common.Interrupt return values in outbound.go Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * fix: spurious xray reload + missing IPs for long-lived conns - config: reset XRayConfig before re-decoding so xray-conf UnmarshalJSON methods (e.g. PortList.Range) don't accumulate state across reloads. Without this, the relay reloader's LoadConfig() mutates the shared Config, xray's needReload sees a phantom listener change and triggers a reload that kills all live conns. - xray: merge live-conn source IPs from connTracker into the per-cycle IP list. RecordIP only fires once per Dispatch, so long-lived conns spanning multiple sync cycles previously only reported their IP in the first cycle. - xray: log the sync payload JSON before POST to help diagnose upstream reporting issues. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * fix: don't fail traffic sync when bandwidth fetch fails UserPool's first sync runs synchronously inside xrayS.Start, where it GETs the local /metrics/ endpoint for bandwidth. At boot the web server hadn't started yet, so the fetch errored and the entire sync (including the user traffic upload) was aborted. - Reorder boot in MustStartComponents: start the web server goroutine before xrayS.Start so /metrics/ is reachable when the first sync hits. - Demote bandwidth fetch errors to a warn and continue with bandwidth=0 for that cycle. Bandwidth is a delta tracker; missing one tick is fine, but losing the user traffic upload is not. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * docs: add CLAUDE.md with project conventions and gotchas Captures non-obvious project knowledge for future Claude sessions: boot order constraints, the shared-Config + xray-conf UnmarshalJSON append bug pattern, xray/ package design (in-process bypass of gRPC, stripUnused, user_id-as-email convention, reload semantics, per-cycle reporting), and code/commit conventions. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* web: redesign admin dashboard around DataTable + grouped nav
The previous UI rendered the full user list (498 rows in production) in
one pass with no pagination, no sort, no traffic-aware filtering, so the
signal (users actually pushing bytes) was buried under hundreds of
probe-noise rows. Overview also duplicated host metrics shown on the
Host page and left half the screen empty.
- DataTable primitive: sortable columns, 50/page pagination, density
toggle, mdOnly columns for narrow screens. Replaces the per-page
hand-rolled <table> + mobile card list duplication.
- Segmented control for filter chips and time-range pickers.
- Layout: split sidebar into Live (Overview/Users/Conns/Logs) and
Config (Rules/Host/Settings); rename Node -> Host.
- Overview: triage landing page. Top users by recent throughput +
recent connections, both click-through. Host metrics collapsed to
a 4-stat strip linking to detail. Configuration & sync endpoint
blocks moved to Settings.
- XrayUsers: default view is "Active" (users with traffic in the last
5min OR live conns OR cumulative >1KB). Active/Running/All/Disabled
segments with counts. Sortable by traffic, status, conn count.
- XrayConns: Flat / By user / By target view modes (URL-state). Group
view exposes a per-user kill action.
- Rules: ported to DataTable, sortable by xfer / conns / ping.
- Logs: error-count pill in header, level segments, logger dropdown
populated from observed frames.
- Settings: gains Runtime configuration + Sync endpoint cards (with
copy-to-clipboard).
Removes the old ui/Table.tsx (no remaining refs) and the /node alias.
* web: fold Host into Overview, expose page-size + refresh-interval controls
- Drop the standalone Host page; its CPU/Mem/Net charts now live at the
bottom of Overview with their own time-window picker. Removes /host
route and the Host nav entry.
- DataTable footer is always visible and includes a page-size selector
(25 / 50 / 100 / All), so users can pull the full list without
hunting for a hidden control. Pagination chevrons only render when
more than one page exists.
- New util/polling.ts + ui/RefreshPicker: a single hook drives the
interval, persists the choice in localStorage, and skips ticks while
the tab is hidden. Default poll interval bumped from 2-5s to 15s
(Overview/Users) and 5s (Conns), with off/5s/15s/30s/1m options
exposed in each page header.
- Replace hand-rolled setInterval/Pause-Play widgets in Overview /
Users / Conns with the shared RefreshPicker.
* web: fix sign-in/sign-out by centralizing auth state
The previous flow had two latent bugs:
1. Sign-out called `clearToken()` then `location.reload()`. If the SPA
was originally opened via a bookmarked `?token=...` URL, the reload
re-executed the URL-token bootstrap path and immediately re-saved
the token from the URL, so sign-out had no visible effect.
2. The boot probe in App.tsx treated any non-401 error (network blip,
5xx) as "ok" and let the user past LoginGate. Subsequent API calls
then failed silently and the dashboard looked broken with no way
back to the login screen.
Move all auth state into store/auth.ts:
- `authState` signal ("checking" | "needed" | "ok") drives App.tsx.
- `probeAuth()` runs once on mount; treats 401/403 as needed and
clears any stale token; treats other errors as needed too so the
user always has a path back in.
- `signIn(token)` saves, probes, and resolves to an error message or
null. LoginGate just awaits it.
- `signOut()` clears the token and flips state to "needed" without
reloading the page, sidestepping the URL-token resurrection bug.
Drop the Access token card from Settings — sign out from the sidebar
already covers token rotation, and the redundant entry point made
the sessionStorage / signal split easy to misuse.
* web: support BasicAuth in the SPA login flow
Setups using web_auth_user / web_auth_pass were stuck: the browser's
native BasicAuth dialog handled login, the SPA never saw it, and
"Sign out" was a no-op because there's no JS API to clear the
browser's cached credentials. After my previous refactor the SPA's
LoginGate would never appear for these deployments either — it only
asked for a token.
Switch to fully SPA-owned auth UX:
- Replace echo's middleware.BasicAuthWithConfig with a custom one
that returns a plain 401 (no WWW-Authenticate). The browser no
longer pops its native dialog, so the SPA can render its own form
and signOut() actually has somewhere to clear creds back to.
- New public GET /api/v1/auth/info advertises which schemes the
server enforces; LoginGate uses it to render token / user+pass /
both.
- store/auth: track {token, user, pass}; persist all three; expose
authInfo so LoginGate knows which fields to show.
- api/client: send Authorization: Basic when user/pass are set, in
addition to the existing ?token= query param. WS still uses the
token (browsers can't attach Authorization headers to WS upgrades
reliably; out-of-scope for this fix).
* web: hide sign-out and surface real auth status when no auth is set
Running ehco without web_token / web_auth_user / web_auth_pass leaves
every admin endpoint open. The dashboard still rendered a Sign out
button, which was confusing: clicking it cleared (empty) creds and
flipped to the LoginGate, but the next probe immediately succeeded
without any credentials and bounced the user straight back.
Also reword the Settings copy that hardcoded "?token= when web_token
is set" — that's only one of three possible states now.
- Layout: gate Sign out (sidebar + mobile sheet) on
authInfo.token || authInfo.basic.
- Settings runtime card: add an "auth" row showing none / token /
basic / "basic + token".
- Settings API surface footer: drive the requirement string off the
real authInfo signal; if neither scheme is enabled, say so plainly.
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 subscribe to this conversation on GitHub.
Already have an account?
Sign in.
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.
See Commits and Changes for more details.
Created by
pull[bot] (v2.0.0-alpha.4)
Can you help keep this open source service alive? 💖 Please sponsor : )