精简版P9(4b): 删除本地核心整条路径(进程管理/buildXrayConfig本地分支/local-only注入/本地核心接口与任务)

- service/xray.go 1741->573行: 只剩 agent 配置构建(GetXrayConfigForAgent/buildAgentXrayConfig=模板+节点入站+egress+转发编译); 删进程生命周期/状态机/RestartXray/StopXray/SetToNeedRestart/GetXrayTraffic/GetOnlineUsers/balancer/TestRoute 与 injectPanelEgress/injectNodeEgresses/injectMtproto/injectAmneziawg/mergeSubscriptionOutbounds
- controller: 43处 SetToNeedRestart 与各 RestartXray 调用清除; 删 balancerStatus/balancerOverride/routeTest/getXrayResult 路由与handler(纯本地核心操作); 前端删 RouteTester 页签与组件
- server service: GetConfigJson 改模板直读; 状态Xray块恒 stopped/空版本; Stop/RestartXrayService 改 no-op(DB导入/恢复流程保留形状)
- setting service: PanelEgressProxyURL/NodeEgressProxyURL 恒直连(桥在本地核心内,已不存在); NodeService.withOutboundBridge 恒直连回退
- runtime: Local 改为全 no-op 桩(DB即真源); NewManager() 去 LocalDeps(APIPort/SetNeedRestart)
- job: 删 XrayTrafficJob/CheckXrayRunningJob/CheckClientIpJob 三文件(共享声明 EventBus/IPWithTimestamp/clientStatsSnapshotMaxClients 迁 shared.go); web.go 不再调度 MtprotoJob/AmneziaWGJob, 删 OnCrash 接线与 stop() 的 sidecar StopAll
- MTProto/AmneziaWG 下线: AddInbound/UpdateInbound 对两协议直接拒绝(存量行保留可删); TG bot 的 restart 命令与在线查询按无本地核心收口
- 测试: GetXrayConfig 系列移植到 agent 构建(finalmask/clients/wireguard/scale); 删退役行为测试(lifecycle/restart/mtproto本地应用/client-ip job/inject系列); 共享测试helper迁 mtproto_test_helpers_test.go 与 job/integration_helpers_test.go
- 既有红(非本轮引入,已在 f6d6520 复现): TestGetXrayConfig_EnabledClientsStillEmitted、TestRouteRegistryContract(P6删 endpoints.ts 遗留)
This commit is contained in:
Muse
2026-10-21 18:43:55 +00:00
parent f6d652019d
commit 1035d00fe4
54 changed files with 310 additions and 5963 deletions
+3 -91
View File
@@ -13,7 +13,6 @@ import (
"github.com/mhsanaei/3x-ui/v3/internal/web/service"
"github.com/mhsanaei/3x-ui/v3/internal/web/service/integration"
"github.com/mhsanaei/3x-ui/v3/internal/web/service/outbound"
"github.com/mhsanaei/3x-ui/v3/internal/xray"
"github.com/gin-gonic/gin"
)
@@ -44,7 +43,6 @@ func (a *XraySettingController) initRouter(g *gin.RouterGroup) {
g = g.Group("/xray")
g.GET("/getDefaultJsonConfig", a.getDefaultXrayConfig)
g.GET("/getOutboundsTraffic", a.getOutboundsTraffic)
g.GET("/getXrayResult", a.getXrayResult)
g.POST("/", a.getXraySetting)
g.POST("/warp/:action", a.warp)
@@ -52,9 +50,6 @@ func (a *XraySettingController) initRouter(g *gin.RouterGroup) {
g.POST("/pia/:action", a.pia)
g.POST("/update", a.updateSetting)
g.POST("/resetOutboundsTraffic", a.resetOutboundsTraffic)
g.POST("/balancerStatus", a.balancerStatus)
g.POST("/balancerOverride", a.balancerOverride)
g.POST("/routeTest", a.routeTest)
g.GET("/geodata/files", a.geodataFiles)
g.GET("/geodata/categories", a.geodataCategories)
@@ -129,22 +124,15 @@ func (a *XraySettingController) getXraySetting(c *gin.Context) {
jsonObj(c, string(result), nil)
}
// updateSetting updates the Xray configuration settings and applies them to
// the running core right away — through the gRPC API when only inbounds,
// outbounds or routing rules changed, with a process restart otherwise.
// updateSetting updates the Xray configuration settings. Agent nodes pick
// the new template up on their next config pull; there is no local core to
// apply it to.
func (a *XraySettingController) updateSetting(c *gin.Context) {
xraySetting := c.PostForm("xraySetting")
if err := a.XraySettingService.SaveXraySetting(xraySetting); err != nil {
jsonMsg(c, I18nWeb(c, "pages.settings.toasts.modifySettings"), err)
return
}
// Only reconcile a running core; a manually stopped xray stays stopped.
if a.XrayService.IsXrayRunning() {
if err := a.XrayService.RestartXray(false); err != nil {
jsonMsg(c, I18nWeb(c, "pages.settings.toasts.modifySettings"), err)
return
}
}
jsonMsg(c, I18nWeb(c, "pages.settings.toasts.modifySettings"), nil)
}
@@ -158,10 +146,6 @@ func (a *XraySettingController) getDefaultXrayConfig(c *gin.Context) {
jsonObj(c, defaultJsonConfig, nil)
}
// getXrayResult retrieves the current Xray service result.
func (a *XraySettingController) getXrayResult(c *gin.Context) {
jsonObj(c, a.XrayService.GetXrayResult(), nil)
}
// warp handles Warp-related operations based on the action parameter.
func (a *XraySettingController) warp(c *gin.Context) {
@@ -182,7 +166,6 @@ func (a *XraySettingController) warp(c *gin.Context) {
case "changeIp":
resp, err = a.WarpService.ChangeWarpIP()
if err == nil {
a.XrayService.SetToNeedRestart()
// Restart the auto-update clock so a scheduled rotation
// doesn't fire right after this manual one.
err = a.SettingService.SetWarpLastUpdate(time.Now().Unix())
@@ -284,76 +267,8 @@ func (a *XraySettingController) resetOutboundsTraffic(c *gin.Context) {
jsonObj(c, "", nil)
}
// balancerStatus reports the live state (override + strategy picks) of the
// balancer tags given as a comma-separated "tags" form field.
func (a *XraySettingController) balancerStatus(c *gin.Context) {
raw := c.PostForm("tags")
var tags []string
for tag := range strings.SplitSeq(raw, ",") {
if tag = strings.TrimSpace(tag); tag != "" {
tags = append(tags, tag)
}
}
statuses, err := a.XrayService.GetBalancersStatus(tags)
if err != nil {
jsonMsg(c, I18nWeb(c, "somethingWentWrong"), err)
return
}
byTag := make(map[string]service.BalancerStatus, len(statuses))
for _, status := range statuses {
byTag[status.Tag] = status
}
jsonObj(c, byTag, nil)
}
// balancerOverride forces a balancer to a specific outbound tag; an empty
// "target" clears the override.
func (a *XraySettingController) balancerOverride(c *gin.Context) {
tag := c.PostForm("tag")
if tag == "" {
jsonMsg(c, I18nWeb(c, "somethingWentWrong"), common.NewError("tag is required"))
return
}
target := c.PostForm("target")
if err := a.XrayService.OverrideBalancer(tag, target); err != nil {
jsonMsg(c, I18nWeb(c, "somethingWentWrong"), err)
return
}
jsonObj(c, "", nil)
}
// routeTest asks the running core which outbound it would route a synthetic
// connection to.
func (a *XraySettingController) routeTest(c *gin.Context) {
port := 0
if portStr := c.PostForm("port"); portStr != "" {
parsed, err := strconv.Atoi(portStr)
if err != nil || parsed < 0 || parsed > 65535 {
jsonMsg(c, I18nWeb(c, "somethingWentWrong"), common.NewError("invalid port"))
return
}
port = parsed
}
req := xray.RouteTestRequest{
InboundTag: c.PostForm("inboundTag"),
Domain: c.PostForm("domain"),
IP: c.PostForm("ip"),
Port: port,
Network: c.PostForm("network"),
Protocol: c.PostForm("protocol"),
Email: c.PostForm("email"),
}
if req.Domain == "" && req.IP == "" {
jsonMsg(c, I18nWeb(c, "somethingWentWrong"), common.NewError("domain or ip is required"))
return
}
result, err := a.XrayService.TestRoute(req)
if err != nil {
jsonMsg(c, I18nWeb(c, "somethingWentWrong"), err)
return
}
jsonObj(c, result, nil)
}
// maxGeodataTokens bounds one validation request; a routing rule listing more
// categories than this is not something the panel needs to answer for.
@@ -496,7 +411,6 @@ func (a *XraySettingController) deleteOutboundSub(c *gin.Context) {
return
}
// Signal that xray should drop this subscription's outbounds on next reload.
a.XrayService.SetToNeedRestart()
jsonObj(c, "", nil)
}
@@ -513,7 +427,6 @@ func (a *XraySettingController) refreshOutboundSub(c *gin.Context) {
return
}
// Signal that xray should pick up the new outbounds on next restart/reload
a.XrayService.SetToNeedRestart()
jsonObj(c, obs, nil)
}
@@ -530,7 +443,6 @@ func (a *XraySettingController) moveOutboundSub(c *gin.Context) {
return
}
// Order affects the merged outbounds, so xray needs a reload.
a.XrayService.SetToNeedRestart()
jsonObj(c, "", nil)
}