feat(online): use xray online-stats API for onlines and access-log-free IP limit

Adopt xray-core's statsUserOnline policy and GetUsersStats RPC so online
detection is connection-based and IP limiting no longer requires an access
log. Falls back to the legacy traffic-delta onlines and access-log parsing
when the running core lacks the RPCs (Unimplemented), probed lazily per
process so a panel-driven version switch re-evaluates automatically.

Backend:
- xray/api.go: GetOnlineUsers (one GetUsersStats call returns all online
  users and their source IPs) and IsUnimplementedErr.
- xray/process.go: per-process OnlineAPISupport tri-state capability cache.
- service/xray.go: ensureStatsPolicy injects statsUserOnline into every
  policy level of the generated config; XrayService.GetOnlineUsers probes
  and falls back.
- job/xray_traffic_job.go: union API onlines into the delta-derived active
  set; bump last_online for idle-but-connected clients.
- job/check_client_ip_job.go: API-first IP source with shared enforcement;
  live observations bypass the 30-min stale cutoff; access-log path
  unchanged for older cores.
- service/setting.go: GetIpLimitEnable always true; new accessLogEnable
  default for features that genuinely read the access log.

Frontend:
- Client form split into Basic and Config tabs; IP Limit and IP Log no
  longer gated on access log; compact Auto Renew next to Start After First
  Use; tabBasic/tabConfig added to all 13 locales.
- Xray logs button on the dashboard now gated on accessLogEnable.
This commit is contained in:
MHSanaei
2026-06-11 19:42:03 +02:00
parent 58905d81a4
commit 7bcc5830c6
33 changed files with 790 additions and 285 deletions
+29
View File
@@ -172,6 +172,12 @@ type process struct {
nodeOnlineTrees map[int]map[string][]string
onlineMu sync.RWMutex
// onlineAPISupport caches whether the running core implements the
// online-stats RPCs (GetUsersStats). A new process is created on every
// restart/version switch, so the flag resets to Unknown and is re-probed
// lazily by the first caller.
onlineAPISupport atomic.Int32
config *Config
configPath string // if set, use this path instead of GetConfigPath() and remove on Stop
logWriter *LogWriter
@@ -181,6 +187,29 @@ type process struct {
intentionalStop atomic.Bool
}
// OnlineAPISupport describes whether the running Xray core implements the
// online-stats API (statsUserOnline + GetUsersStats).
type OnlineAPISupport int32
const (
// OnlineAPIUnknown means support has not been probed yet for this process.
OnlineAPIUnknown OnlineAPISupport = iota
// OnlineAPISupported means the core answered the online-stats RPC.
OnlineAPISupported
// OnlineAPIUnsupported means the core returned Unimplemented (older binary).
OnlineAPIUnsupported
)
// OnlineAPISupport returns the cached online-stats capability of this process.
func (p *process) OnlineAPISupport() OnlineAPISupport {
return OnlineAPISupport(p.onlineAPISupport.Load())
}
// SetOnlineAPISupport records the probed online-stats capability of this process.
func (p *process) SetOnlineAPISupport(v OnlineAPISupport) {
p.onlineAPISupport.Store(int32(v))
}
var (
xrayGracefulStopTimeout = 5 * time.Second
xrayForceStopTimeout = 2 * time.Second