feat(sub): refine Happ routing presets, serverDescription escaping, and auto-detect placement (#6488)

* feat(sub): refine Happ routing presets, serverDescription escaping, and auto-detect placement

* fix(sub): address PR review findings on routing parity, agent regex, and i18n
This commit is contained in:
Pejman Yousefi
2026-09-13 14:23:57 +03:30
committed by GitHub
parent c7518c4038
commit cba8f0672f
10 changed files with 306 additions and 166 deletions
+23 -5
View File
@@ -1,6 +1,7 @@
package sub
import (
"encoding/base64"
"strings"
"github.com/mhsanaei/3x-ui/v3/internal/database/model"
@@ -20,10 +21,11 @@ import (
// because three behaviors branch on the raw string (keep-base, obj["tls"]
// rewrite, none-strip).
type ShareEndpoint struct {
Address string
Port int
Remark string // extra remark slot fed to genRemark, not a rendered remark
ForceTls string
Address string
Port int
Remark string // extra remark slot fed to genRemark, not a rendered remark
ServerDescription string // subtitle caption displayed in Happ client
ForceTls string
// ep is the source externalProxy entry. nil for host/default endpoints.
ep map[string]any
@@ -38,6 +40,7 @@ func externalProxyToEndpoint(ep map[string]any) ShareEndpoint {
e.Port = int(p)
}
e.Remark, _ = ep["remark"].(string)
e.ServerDescription, _ = ep["serverDescription"].(string)
e.ForceTls, _ = ep["forceTls"].(string)
return e
}
@@ -106,10 +109,14 @@ func (s *SubService) buildEndpointLinks(
applyEndpointHostPath(e, nextParams)
applyEndpointFinalMask(e, nextParams)
applyEndpointAllowInsecure(e, nextParams, securityToApply)
remark := makeRemark(e)
if e.ServerDescription != "" {
remark = appendHappServerDescription(remark, e.ServerDescription)
}
links = append(links, buildLinkWithParamsAndSecurity(
makeLink(e),
nextParams,
makeRemark(e),
remark,
securityToApply,
e.ForceTls == "none",
))
@@ -117,6 +124,14 @@ func (s *SubService) buildEndpointLinks(
return strings.Join(links, "\n")
}
func appendHappServerDescription(remark, desc string) string {
if desc == "" {
return remark
}
encoded := base64.StdEncoding.EncodeToString([]byte(desc))
return remark + "?serverDescription=" + encoded
}
// buildEndpointVmessLinks renders one VMess base64-JSON link per endpoint.
func (s *SubService) buildEndpointVmessLinks(eps []ShareEndpoint, baseObj map[string]any, inbound *model.Inbound, email string, transport string) string {
var links strings.Builder
@@ -132,6 +147,9 @@ func (s *SubService) buildEndpointVmessLinks(eps []ShareEndpoint, baseObj map[st
if e.ForceTls != "same" {
newObj["tls"] = e.ForceTls
}
if e.ServerDescription != "" {
newObj["serverDescription"] = e.ServerDescription
}
applyEndpointTLSObj(e, newObj, securityToApply)
applyEndpointHostPathObj(e, newObj)
applyEndpointFinalMaskObj(e, newObj)