Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/MHSanaei/3x-ui.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorsurbiks <43953720+surbiks@users.noreply.github.com>2026-02-09 23:43:17 +0300
committerGitHub <noreply@github.com>2026-02-09 23:43:17 +0300
commit4779939424eb047d30161631fd89a9876104084c (patch)
tree89e2682aa528281879b3afb535f2b34124a17335 /web/controller/xray_setting.go
parent4a455aa5322e0803005da2d5d65b85a19dfc42e5 (diff)
Add url speed test for outbound (#3767)
* add outbound testing functionality with configurable test URL * use no kernel tun for conflict errors
Diffstat (limited to 'web/controller/xray_setting.go')
-rw-r--r--web/controller/xray_setting.go46
1 files changed, 42 insertions, 4 deletions
diff --git a/web/controller/xray_setting.go b/web/controller/xray_setting.go
index b78925f0..a48726de 100644
--- a/web/controller/xray_setting.go
+++ b/web/controller/xray_setting.go
@@ -1,6 +1,9 @@
package controller
import (
+ "encoding/json"
+
+ "github.com/mhsanaei/3x-ui/v2/util/common"
"github.com/mhsanaei/3x-ui/v2/web/service"
"github.com/gin-gonic/gin"
@@ -34,9 +37,10 @@ func (a *XraySettingController) initRouter(g *gin.RouterGroup) {
g.POST("/warp/:action", a.warp)
g.POST("/update", a.updateSetting)
g.POST("/resetOutboundsTraffic", a.resetOutboundsTraffic)
+ g.POST("/testOutbound", a.testOutbound)
}
-// getXraySetting retrieves the Xray configuration template and inbound tags.
+// getXraySetting retrieves the Xray configuration template, inbound tags, and outbound test URL.
func (a *XraySettingController) getXraySetting(c *gin.Context) {
xraySetting, err := a.SettingService.GetXrayConfigTemplate()
if err != nil {
@@ -48,15 +52,28 @@ func (a *XraySettingController) getXraySetting(c *gin.Context) {
jsonMsg(c, I18nWeb(c, "pages.settings.toasts.getSettings"), err)
return
}
- xrayResponse := "{ \"xraySetting\": " + xraySetting + ", \"inboundTags\": " + inboundTags + " }"
+ outboundTestUrl, _ := a.SettingService.GetXrayOutboundTestUrl()
+ if outboundTestUrl == "" {
+ outboundTestUrl = "https://www.google.com/generate_204"
+ }
+ urlJSON, _ := json.Marshal(outboundTestUrl)
+ xrayResponse := "{ \"xraySetting\": " + xraySetting + ", \"inboundTags\": " + inboundTags + ", \"outboundTestUrl\": " + string(urlJSON) + " }"
jsonObj(c, xrayResponse, nil)
}
// updateSetting updates the Xray configuration settings.
func (a *XraySettingController) updateSetting(c *gin.Context) {
xraySetting := c.PostForm("xraySetting")
- err := a.XraySettingService.SaveXraySetting(xraySetting)
- jsonMsg(c, I18nWeb(c, "pages.settings.toasts.modifySettings"), err)
+ if err := a.XraySettingService.SaveXraySetting(xraySetting); err != nil {
+ jsonMsg(c, I18nWeb(c, "pages.settings.toasts.modifySettings"), err)
+ return
+ }
+ outboundTestUrl := c.PostForm("outboundTestUrl")
+ if outboundTestUrl == "" {
+ outboundTestUrl = "https://www.google.com/generate_204"
+ }
+ _ = a.SettingService.SetXrayOutboundTestUrl(outboundTestUrl)
+ jsonMsg(c, I18nWeb(c, "pages.settings.toasts.modifySettings"), nil)
}
// getDefaultXrayConfig retrieves the default Xray configuration.
@@ -118,3 +135,24 @@ func (a *XraySettingController) resetOutboundsTraffic(c *gin.Context) {
}
jsonObj(c, "", nil)
}
+
+// testOutbound tests an outbound configuration and returns the delay/response time.
+// Optional form "allOutbounds": JSON array of all outbounds; used to resolve sockopt.dialerProxy dependencies.
+func (a *XraySettingController) testOutbound(c *gin.Context) {
+ outboundJSON := c.PostForm("outbound")
+ testURL := c.PostForm("testURL")
+ allOutboundsJSON := c.PostForm("allOutbounds")
+
+ if outboundJSON == "" {
+ jsonMsg(c, I18nWeb(c, "somethingWentWrong"), common.NewError("outbound parameter is required"))
+ return
+ }
+
+ result, err := a.OutboundService.TestOutbound(outboundJSON, testURL, allOutboundsJSON)
+ if err != nil {
+ jsonMsg(c, I18nWeb(c, "somethingWentWrong"), err)
+ return
+ }
+
+ jsonObj(c, result, nil)
+}