精简版第四轮补裁(P4): 页面层摘除 + Xray更新端点下线 + 本机核心监管下线
CI / go-test (push) Canceled after 0s
CI / postgres-durable-first (push) Canceled after 0s
CI / codegen (push) Canceled after 0s
CI / govulncheck (push) Canceled after 0s
CI / race (push) Canceled after 0s
CI / fuzz-smoke (push) Canceled after 0s
CI / golangci (push) Canceled after 0s
CI / frontend (push) Canceled after 0s
CodeQL Advanced / Analyze (go) (push) Canceled after 0s
CodeQL Advanced / Analyze (actions) (push) Canceled after 0s
CodeQL Advanced / Analyze (javascript-typescript) (push) Canceled after 0s
Release 3X-UI / build (386) (push) Canceled after 0s
Release 3X-UI / build (amd64) (push) Canceled after 0s
Release 3X-UI / build (arm64) (push) Canceled after 0s
Release 3X-UI / build (armv5) (push) Canceled after 0s
Release 3X-UI / build (armv6) (push) Canceled after 0s
Release 3X-UI / build (armv7) (push) Canceled after 0s
Release 3X-UI / build (s390x) (push) Canceled after 0s
Release 3X-UI / Build for Windows (amd64) (push) Canceled after 0s
Release 3X-UI / Publish rolling dev release (push) Canceled after 0s

页面层(用户真机截图发现前两轮漏裁):
- 设置: 摘除 Telegram机器人/邮件菜单与页面, 及页内残留入口(通知页/外部流量/LDAP/2FA设置页)
- Xray配置: 摘除负载均衡/DNS/高级配置菜单与页面; 基础配置(出站+路由)完好
- 总览: 摘除 Xray更新弹窗(VersionModal+GeodataSection)全部入口, 版本号改为静态展示
- 13个locale同步摘除461个已删功能专属翻译键(逐键核查前后端引用为零; i18n-dead-keys测试全绿)

Xray更新后端(经调查确认仅服务本机bin/xray, 与agent下发/订阅无关):
- 删除 getXrayVersion/installXray/updateGeofile 路由与handler(访问返回404)
- 删除 ServerService 对应实现与校验和函数; 同步api-docs/monitor白名单/openapi

本机核心监管下线(设计: 主控永不运行本机xray, 入站全在agent):
- XrayService.RestartXray 降级为no-op(一次性Warning说明日志); StopXray无进程时幂等返回
- web.go 摘除启动拉起本机核心/CheckXrayRunning看门狗(1s)/ApplyPendingRestart cron(30s)/XrayTrafficJob/CheckClientIpJob 注册
- ApplyPendingRestart 降级为消费即清, 其测试更新为新语义
- XrayMetricsService.Sample 短路: 不再每2s探本机/debug/vars, 状态优雅置为不可用
- 配置生成(纯JSON)/agent链路/订阅/入站CRUD未动; 状态读数优雅归零(stop/Unknown)

注: TestGetXrayConfig_EnabledClientsStillEmitted 在基线945b3a5同样失败(既有问题, 非本轮引入)
This commit is contained in:
Muse
2026-10-20 23:39:38 +08:00
parent 945b3a56a2
commit a654a96c38
56 changed files with 149 additions and 11458 deletions
+42 -11
View File
@@ -26,8 +26,27 @@ var (
isNeedXrayRestart atomic.Bool // Indicates that restart was requested for Xray
isManuallyStopped atomic.Bool // Indicates that Xray was stopped manually from the panel
xrayState xrayLifecycle
// localCoreDisabledOnce ensures the "local core disabled" notice is
// logged exactly once per panel run, no matter how many legacy callers
// still ask for a local restart.
localCoreDisabledOnce sync.Once
)
// logLocalCoreDisabled records, once, that local-xray lifecycle requests are
// being ignored. The lite master is a pure control plane: it never runs a
// local xray process (all inbounds live on agent nodes), so restarts are
// no-ops instead of spawn attempts that would fail every few seconds on
// hosts where bin/xray is absent or deliberately disabled.
func logLocalCoreDisabled() {
localCoreDisabledOnce.Do(func() {
// Warning level on purpose: the panel's default log level hides
// Info, and this one-time notice is the only sign that legacy
// restart requests are being absorbed.
logger.Warning("local xray core is disabled in this build (control-plane only); local restart requests are ignored")
})
}
type xrayLifecycle struct {
mu sync.RWMutex
process *xray.Process
@@ -1421,6 +1440,18 @@ func (s *XrayService) TestRoute(req xray.RouteTestRequest) (*xray.RouteTestResul
// routing rules/balancers are hot-reloadable); only changes the core cannot
// take at runtime — or a force request — stop and restart the process.
func (s *XrayService) RestartXray(isForce bool) error {
// Lite control-plane build: the local xray process is never started.
// Every historical caller (startup, crash watchdog, pending-restart
// ticker, settings-save hooks, server endpoints) funnels through here,
// so degrading this single point retires the whole local lifecycle
// without touching agent-node flows (the agent runs its own core via
// internal/agent, not via this service).
_ = isForce
logLocalCoreDisabled()
return nil
}
func (s *XrayService) restartXrayLegacy(isForce bool) error {
lock.Lock()
defer lock.Unlock()
logger.Debug("restart Xray, force:", isForce)
@@ -1600,7 +1631,10 @@ func (s *XrayService) StopXray() error {
if process != nil && process.IsRunning() {
return process.Stop()
}
return errors.New("xray is not running")
// Lite control-plane build: no local process ever runs, so stopping is
// an idempotent no-op rather than an error.
logLocalCoreDisabled()
return nil
}
// SetToNeedRestart marks that Xray needs to be restarted.
@@ -1625,17 +1659,14 @@ func (s *XrayService) IsNeedRestartAndSetFalse() bool {
return isNeedXrayRestart.CompareAndSwap(true, false)
}
// ApplyPendingRestart consumes the need-restart flag and restarts Xray. If the
// restart fails (for example GetXrayConfig hits a transient DB error and leaves
// the old process running), it re-arms the flag so the next tick retries instead
// of silently dropping the pending config change.
// ApplyPendingRestart used to consume the need-restart flag and restart
// the local core, re-arming the flag on failure so the next tick retried.
// The local core never runs in this build, so a pending restart is simply
// dropped: clear the flag and do nothing. (Its only caller, the 30s cron
// tick in web.go, has been removed as well.)
func (s *XrayService) ApplyPendingRestart() {
if !s.IsNeedRestartAndSetFalse() {
return
}
if err := s.RestartXray(false); err != nil {
logger.Error("restart xray failed:", err)
s.SetToNeedRestart()
if s.IsNeedRestartAndSetFalse() {
logLocalCoreDisabled()
}
}