fix(sync): use XHTTP VLESS URIs, include all agent nodes, remove server-side rendered_json
- Sync now generates XHTTP VLESS URIs (port 443, type=xhttp) instead of TCP - Node list includes all registered agent hosts, not just publicURL - Removed rendered_json (server-side inbound config) from sync response - Client generates proper outbound config from VLESS URI - Node names use full domain (e.g. jp-xhttp.svc.plus) with country code
This commit is contained in:
parent
b93afccaef
commit
ea3d6aec06
@ -53,6 +53,7 @@ func (h *handler) respondSyncConfigSnapshot(c *gin.Context) {
|
||||
}
|
||||
|
||||
renderedJSON, digest, warnings, err := h.renderUserXrayConfig(user)
|
||||
_ = renderedJSON // server-side config, not sent to clients
|
||||
if err != nil {
|
||||
respondError(c, http.StatusInternalServerError, "config_render_failed", "failed to render xray config")
|
||||
return
|
||||
@ -66,46 +67,58 @@ func (h *handler) respondSyncConfigSnapshot(c *gin.Context) {
|
||||
if proxyUUID == "" {
|
||||
proxyUUID = strings.TrimSpace(user.ID)
|
||||
}
|
||||
host := extractHostFromPublicURL(h.publicURL)
|
||||
if host == "" {
|
||||
host = "accounts.svc.plus"
|
||||
}
|
||||
_, registeredNames := registeredNodeMetadata(h.agentStatusReader)
|
||||
nodeName := resolveNodeName(host, registeredNames)
|
||||
tcpScheme := xrayconfig.VLESSTCPScheme()
|
||||
vlessURI := renderVLESSURIScheme(tcpScheme, map[string]string{
|
||||
"UUID": proxyUUID,
|
||||
"DOMAIN": host,
|
||||
"SNI": host,
|
||||
"FP": defaultTLSFP,
|
||||
"FLOW": xrayconfig.DefaultFlow,
|
||||
"TAG": url.QueryEscape(nodeName),
|
||||
})
|
||||
|
||||
profiles = append(profiles, gin.H{
|
||||
"id": strings.TrimSpace(user.ID),
|
||||
"remark": nodeName,
|
||||
"address": host,
|
||||
"port": 1443,
|
||||
"uuid": proxyUUID,
|
||||
"flow": xrayconfig.DefaultFlow,
|
||||
"source": "server",
|
||||
"vless_uri": vlessURI,
|
||||
})
|
||||
nodes = append(nodes, gin.H{
|
||||
"id": strings.TrimSpace(user.ID),
|
||||
"name": nodeName,
|
||||
"protocol": "vless",
|
||||
"transport": "tcp",
|
||||
"security": "tls",
|
||||
"address": host,
|
||||
"port": 1443,
|
||||
"uuid": proxyUUID,
|
||||
"flow": xrayconfig.DefaultFlow,
|
||||
"source": "server",
|
||||
"updated_at": updatedAt,
|
||||
"vless_uri": vlessURI,
|
||||
})
|
||||
// Collect node hosts from registered agents + publicURL fallback.
|
||||
registeredHosts, registeredNames := registeredNodeMetadata(h.agentStatusReader)
|
||||
hosts := parseProxyNodeHosts(h.publicURL, registeredHosts)
|
||||
|
||||
xhttpPath := envOrDefault("XRAY_XHTTP_PATH", defaultXHTTPPath)
|
||||
xhttpMode := envOrDefault("XRAY_XHTTP_MODE", defaultXHTTPMode)
|
||||
xhttpScheme := xrayconfig.VLESSXHTTPScheme()
|
||||
|
||||
for _, host := range hosts {
|
||||
nodeName := resolveNodeName(host, registeredNames)
|
||||
countryCode := countryCodeForHost(host)
|
||||
vlessURI := renderVLESSURIScheme(xhttpScheme, map[string]string{
|
||||
"UUID": proxyUUID,
|
||||
"DOMAIN": host,
|
||||
"NODE": host,
|
||||
"PATH": url.QueryEscape(xhttpPath),
|
||||
"MODE": url.QueryEscape(xhttpMode),
|
||||
"SNI": host,
|
||||
"FP": defaultTLSFP,
|
||||
"TAG": url.QueryEscape(nodeName),
|
||||
})
|
||||
|
||||
profiles = append(profiles, gin.H{
|
||||
"id": strings.TrimSpace(user.ID),
|
||||
"remark": nodeName,
|
||||
"address": host,
|
||||
"port": 443,
|
||||
"uuid": proxyUUID,
|
||||
"flow": "",
|
||||
"transport": "xhttp",
|
||||
"security": "tls",
|
||||
"source": "server",
|
||||
"country_code": countryCode,
|
||||
"vless_uri": vlessURI,
|
||||
})
|
||||
nodes = append(nodes, gin.H{
|
||||
"id": strings.TrimSpace(user.ID),
|
||||
"name": nodeName,
|
||||
"protocol": "vless",
|
||||
"transport": "xhttp",
|
||||
"security": "tls",
|
||||
"address": host,
|
||||
"port": 443,
|
||||
"uuid": proxyUUID,
|
||||
"flow": "",
|
||||
"source": "server",
|
||||
"country_code": countryCode,
|
||||
"updated_at": updatedAt,
|
||||
"vless_uri": vlessURI,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, gin.H{
|
||||
@ -124,9 +137,8 @@ func (h *handler) respondSyncConfigSnapshot(c *gin.Context) {
|
||||
"digest": digest,
|
||||
"warnings": warnings,
|
||||
},
|
||||
"rendered_json": renderedJSON,
|
||||
"digest": digest,
|
||||
"warnings": warnings,
|
||||
"digest": digest,
|
||||
"warnings": warnings,
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@ -383,17 +383,30 @@ func envIntOrDefault(key string, fallback int) int {
|
||||
}
|
||||
|
||||
func nodeNameForHost(host string) string {
|
||||
h := strings.TrimSpace(host)
|
||||
if h == "" {
|
||||
return "unknown-node"
|
||||
}
|
||||
return strings.ToLower(h)
|
||||
}
|
||||
|
||||
// countryCodeForHost extracts a two-letter country code from the host's
|
||||
// subdomain prefix. For example "jp-xhttp.svc.plus" yields "JP",
|
||||
// "us-east.example.com" yields "US".
|
||||
func countryCodeForHost(host string) string {
|
||||
prefix := host
|
||||
if idx := strings.Index(prefix, "."); idx > 0 {
|
||||
prefix = prefix[:idx]
|
||||
}
|
||||
prefix = strings.TrimSpace(prefix)
|
||||
if prefix == "" {
|
||||
prefix = host
|
||||
// Take the part before the first dash: "jp-xhttp" -> "jp"
|
||||
if idx := strings.Index(prefix, "-"); idx > 0 {
|
||||
prefix = prefix[:idx]
|
||||
}
|
||||
prefix = strings.ReplaceAll(prefix, "_", "-")
|
||||
prefix = strings.ToUpper(prefix)
|
||||
return prefix + "-NODE"
|
||||
prefix = strings.TrimSpace(prefix)
|
||||
if len(prefix) == 2 {
|
||||
return strings.ToUpper(prefix)
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func renderVLESSURIScheme(tpl string, values map[string]string) string {
|
||||
|
||||
Loading…
Reference in New Issue
Block a user