refactor(genLink): replace map with struct for link params

This commit is contained in:
Anem
2026-01-05 15:35:03 +08:00
parent 0ef5db4846
commit 9d367fb83d
+159 -111
View File
@@ -13,6 +13,11 @@ import (
var InboundTypeWithLink = []string{"socks", "http", "mixed", "shadowsocks", "naive", "hysteria", "hysteria2", "anytls", "tuic", "vless", "trojan", "vmess"} var InboundTypeWithLink = []string{"socks", "http", "mixed", "shadowsocks", "naive", "hysteria", "hysteria2", "anytls", "tuic", "vless", "trojan", "vmess"}
type LinkParam struct {
Key string
Value string
}
func LinkGenerator(clientConfig json.RawMessage, i *model.Inbound, hostname string) []string { func LinkGenerator(clientConfig json.RawMessage, i *model.Inbound, hostname string) []string {
inbound, err := i.MarshalFull() inbound, err := i.MarshalFull()
if err != nil { if err != nil {
@@ -30,7 +35,9 @@ func LinkGenerator(clientConfig json.RawMessage, i *model.Inbound, hostname stri
} }
var Addrs []map[string]interface{} var Addrs []map[string]interface{}
json.Unmarshal(i.Addrs, &Addrs) if err := json.Unmarshal(i.Addrs, &Addrs); err != nil {
return []string{}
}
if len(Addrs) == 0 { if len(Addrs) == 0 {
Addrs = append(Addrs, map[string]interface{}{ Addrs = append(Addrs, map[string]interface{}{
"server": hostname, "server": hostname,
@@ -63,13 +70,13 @@ func LinkGenerator(clientConfig json.RawMessage, i *model.Inbound, hostname stri
switch i.Type { switch i.Type {
case "socks": case "socks":
return socksLink(userConfig["socks"], *inbound, Addrs) return socksLink(userConfig["socks"], Addrs)
case "http": case "http":
return httpLink(userConfig["http"], *inbound, Addrs) return httpLink(userConfig["http"], Addrs)
case "mixed": case "mixed":
return append( return append(
socksLink(userConfig["socks"], *inbound, Addrs), socksLink(userConfig["socks"], Addrs),
httpLink(userConfig["http"], *inbound, Addrs)..., httpLink(userConfig["http"], Addrs)...,
) )
case "shadowsocks": case "shadowsocks":
return shadowsocksLink(userConfig, *inbound, Addrs) return shadowsocksLink(userConfig, *inbound, Addrs)
@@ -96,8 +103,12 @@ func LinkGenerator(clientConfig json.RawMessage, i *model.Inbound, hostname stri
func prepareTls(t *model.Tls) map[string]interface{} { func prepareTls(t *model.Tls) map[string]interface{} {
var iTls, oTls map[string]interface{} var iTls, oTls map[string]interface{}
json.Unmarshal(t.Client, &oTls) if err := json.Unmarshal(t.Client, &oTls); err != nil {
json.Unmarshal(t.Server, &iTls) return nil
}
if err := json.Unmarshal(t.Server, &iTls); err != nil {
return nil
}
for k, v := range iTls { for k, v := range iTls {
switch k { switch k {
@@ -107,8 +118,8 @@ func prepareTls(t *model.Tls) map[string]interface{} {
reality := v.(map[string]interface{}) reality := v.(map[string]interface{})
clientReality := oTls["reality"].(map[string]interface{}) clientReality := oTls["reality"].(map[string]interface{})
clientReality["enabled"] = reality["enabled"] clientReality["enabled"] = reality["enabled"]
if short_ids, hasSIds := reality["short_id"].([]interface{}); hasSIds && len(short_ids) > 0 { if shortIDs, hasSIds := reality["short_id"].([]interface{}); hasSIds && len(shortIDs) > 0 {
clientReality["short_id"] = short_ids[common.RandomInt(len(short_ids))] clientReality["short_id"] = shortIDs[common.RandomInt(len(shortIDs))]
} }
oTls["reality"] = clientReality oTls["reality"] = clientReality
} }
@@ -116,7 +127,7 @@ func prepareTls(t *model.Tls) map[string]interface{} {
return oTls return oTls
} }
func socksLink(userConfig map[string]interface{}, inbound map[string]interface{}, addrs []map[string]interface{}) []string { func socksLink(userConfig map[string]interface{}, addrs []map[string]interface{}) []string {
var links []string var links []string
for _, addr := range addrs { for _, addr := range addrs {
links = append(links, fmt.Sprintf("socks5://%s:%s@%s:%d", userConfig["username"], userConfig["password"], addr["server"].(string), uint(addr["server_port"].(float64)))) links = append(links, fmt.Sprintf("socks5://%s:%s@%s:%d", userConfig["username"], userConfig["password"], addr["server"].(string), uint(addr["server_port"].(float64))))
@@ -124,9 +135,9 @@ func socksLink(userConfig map[string]interface{}, inbound map[string]interface{}
return links return links
} }
func httpLink(userConfig map[string]interface{}, inbound map[string]interface{}, addrs []map[string]interface{}) []string { func httpLink(userConfig map[string]interface{}, addrs []map[string]interface{}) []string {
var links []string var links []string
var protocol string = "http" protocol := "http"
for _, addr := range addrs { for _, addr := range addrs {
if addr["tls"] != nil { if addr["tls"] != nil {
protocol = "https" protocol = "https"
@@ -177,27 +188,27 @@ func naiveLink(
var links []string var links []string
for _, addr := range addrs { for _, addr := range addrs {
params := map[string]string{} var params []LinkParam
params["padding"] = "1" params = append(params, LinkParam{"padding", "1"})
if tls, ok := addr["tls"].(map[string]interface{}); ok { if tls, ok := addr["tls"].(map[string]interface{}); ok {
if sni, ok := tls["server_name"].(string); ok { if sni, ok := tls["server_name"].(string); ok {
params["peer"] = sni params = append(params, LinkParam{"peer", sni})
} }
if alpn, ok := tls["alpn"].([]interface{}); ok { if alpn, ok := tls["alpn"].([]interface{}); ok {
alpnList := make([]string, len(alpn)) alpnList := make([]string, len(alpn))
for i, v := range alpn { for i, v := range alpn {
alpnList[i] = v.(string) alpnList[i] = v.(string)
} }
params["alpn"] = strings.Join(alpnList, ",") params = append(params, LinkParam{"alpn", strings.Join(alpnList, ",")})
} }
if insecure, ok := tls["insecure"].(bool); ok && insecure { if insecure, ok := tls["insecure"].(bool); ok && insecure {
params["insecure"] = "1" params = append(params, LinkParam{"insecure", "1"})
} }
} }
if tfo, ok := inbound["tcp_fast_open"].(bool); ok && tfo { if tfo, ok := inbound["tcp_fast_open"].(bool); ok && tfo {
params["tfo"] = "1" params = append(params, LinkParam{"tfo", "1"})
} else { } else {
params["tfo"] = "0" params = append(params, LinkParam{"tfo", "0"})
} }
port, _ := addr["server_port"].(float64) port, _ := addr["server_port"].(float64)
@@ -216,35 +227,37 @@ func hysteriaLink(
var links []string var links []string
for _, addr := range addrs { for _, addr := range addrs {
params := map[string]string{} var params []LinkParam
if upmbps, ok := inbound["up_mbps"].(float64); ok { if upmbps, ok := inbound["up_mbps"].(float64); ok {
params["downmbps"] = fmt.Sprintf("%.0f", upmbps) params = append(params, LinkParam{"downmbps", fmt.Sprintf("%.0f", upmbps)})
} }
if downmbps, ok := inbound["down_mbps"].(float64); ok { if downmbps, ok := inbound["down_mbps"].(float64); ok {
params["upmbps"] = fmt.Sprintf("%.0f", downmbps) params = append(params, LinkParam{"upmbps", fmt.Sprintf("%.0f", downmbps)})
} }
if auth, ok := userConfig["auth_str"].(string); ok { if auth, ok := userConfig["auth_str"].(string); ok {
params["auth"] = auth params = append(params, LinkParam{"auth", auth})
} }
if tls, ok := addr["tls"].(map[string]interface{}); ok { if tls, ok := addr["tls"].(map[string]interface{}); ok {
getTlsParams(&params, tls, "insecure") getTlsParams(&params, tls, "insecure")
} }
if obfs, ok := inbound["obfs"].(string); ok { if obfs, ok := inbound["obfs"].(string); ok {
params["obfs"] = obfs params = append(params, LinkParam{"obfs", obfs})
} }
if tfo, ok := inbound["tcp_fast_open"].(bool); ok && tfo { if tfo, ok := inbound["tcp_fast_open"].(bool); ok && tfo {
params["fastopen"] = "1" params = append(params, LinkParam{"fastopen", "1"})
} else { } else {
params["fastopen"] = "0" params = append(params, LinkParam{"fastopen", "0"})
} }
var outJson map[string]interface{} var outJson map[string]interface{}
json.Unmarshal(inbound["out_json"].(json.RawMessage), &outJson) if err := json.Unmarshal(inbound["out_json"].(json.RawMessage), &outJson); err != nil {
return []string{} // Handle error
}
if mport, ok := outJson["server_ports"].([]interface{}); ok { if mport, ok := outJson["server_ports"].([]interface{}); ok {
mportList := make([]string, len(mport)) mportList := make([]string, len(mport))
for i, v := range mport { for i, v := range mport {
mportList[i] = v.(string) mportList[i] = v.(string)
} }
params["mport"] = strings.Join(mportList, ",") params = append(params, LinkParam{"mport", strings.Join(mportList, ",")})
} }
port, _ := addr["server_port"].(float64) port, _ := addr["server_port"].(float64)
@@ -265,37 +278,39 @@ func hysteria2Link(
var links []string var links []string
for _, addr := range addrs { for _, addr := range addrs {
params := map[string]string{} var params []LinkParam
if upmbps, ok := inbound["up_mbps"].(float64); ok { if upmbps, ok := inbound["up_mbps"].(float64); ok {
params["downmbps"] = fmt.Sprintf("%.0f", upmbps) params = append(params, LinkParam{"downmbps", fmt.Sprintf("%.0f", upmbps)})
} }
if downmbps, ok := inbound["down_mbps"].(float64); ok { if downmbps, ok := inbound["down_mbps"].(float64); ok {
params["upmbps"] = fmt.Sprintf("%.0f", downmbps) params = append(params, LinkParam{"upmbps", fmt.Sprintf("%.0f", downmbps)})
} }
if tls, ok := addr["tls"].(map[string]interface{}); ok { if tls, ok := addr["tls"].(map[string]interface{}); ok {
getTlsParams(&params, tls, "insecure") getTlsParams(&params, tls, "insecure")
} }
if obfs, ok := inbound["obfs"].(map[string]interface{}); ok { if obfs, ok := inbound["obfs"].(map[string]interface{}); ok {
if obfsType, ok := obfs["type"].(string); ok { if obfsType, ok := obfs["type"].(string); ok {
params["obfs"] = obfsType params = append(params, LinkParam{"obfs", obfsType})
} }
if obfsPassword, ok := obfs["password"].(string); ok { if obfsPassword, ok := obfs["password"].(string); ok {
params["obfs-password"] = obfsPassword params = append(params, LinkParam{"obfs-password", obfsPassword})
} }
} }
if tfo, ok := inbound["tcp_fast_open"].(bool); ok && tfo { if tfo, ok := inbound["tcp_fast_open"].(bool); ok && tfo {
params["fastopen"] = "1" params = append(params, LinkParam{"fastopen", "1"})
} else { } else {
params["fastopen"] = "0" params = append(params, LinkParam{"fastopen", "0"})
} }
var outJson map[string]interface{} var outJson map[string]interface{}
json.Unmarshal(inbound["out_json"].(json.RawMessage), &outJson) if err := json.Unmarshal(inbound["out_json"].(json.RawMessage), &outJson); err != nil {
return []string{} // Handle error
}
if mport, ok := outJson["server_ports"].([]interface{}); ok { if mport, ok := outJson["server_ports"].([]interface{}); ok {
mportList := make([]string, len(mport)) mportList := make([]string, len(mport))
for i, v := range mport { for i, v := range mport {
mportList[i] = v.(string) mportList[i] = v.(string)
} }
params["mport"] = strings.Join(mportList, ",") params = append(params, LinkParam{"mport", strings.Join(mportList, ",")})
} }
port, _ := addr["server_port"].(float64) port, _ := addr["server_port"].(float64)
@@ -315,7 +330,7 @@ func anytlsLink(
var links []string var links []string
for _, addr := range addrs { for _, addr := range addrs {
params := map[string]string{} var params []LinkParam
if tls, ok := addr["tls"].(map[string]interface{}); ok { if tls, ok := addr["tls"].(map[string]interface{}); ok {
getTlsParams(&params, tls, "insecure") getTlsParams(&params, tls, "insecure")
} }
@@ -339,12 +354,12 @@ func tuicLink(
var links []string var links []string
for _, addr := range addrs { for _, addr := range addrs {
params := map[string]string{} var params []LinkParam
if tls, ok := addr["tls"].(map[string]interface{}); ok { if tls, ok := addr["tls"].(map[string]interface{}); ok {
getTlsParams(&params, tls, "insecure") getTlsParams(&params, tls, "insecure")
} }
if congestionControl, ok := inbound["congestion_control"].(string); ok { if congestionControl, ok := inbound["congestion_control"].(string); ok {
params["congestion_control"] = congestionControl params = append(params, LinkParam{"congestion_control", congestionControl})
} }
port, _ := addr["server_port"].(float64) port, _ := addr["server_port"].(float64)
@@ -365,11 +380,12 @@ func vlessLink(
var links []string var links []string
for _, addr := range addrs { for _, addr := range addrs {
params := baseParams params := make([]LinkParam, len(baseParams))
copy(params, baseParams)
if tls, ok := addr["tls"].(map[string]interface{}); ok && tls["enabled"].(bool) { if tls, ok := addr["tls"].(map[string]interface{}); ok && tls["enabled"].(bool) {
getTlsParams(&params, tls, "allowInsecure") getTlsParams(&params, tls, "allowInsecure")
if flow, ok := userConfig["flow"].(string); ok { if flow, ok := userConfig["flow"].(string); ok {
params["flow"] = flow params = append(params, LinkParam{"flow", flow})
} }
} }
port, _ := addr["server_port"].(float64) port, _ := addr["server_port"].(float64)
@@ -390,7 +406,8 @@ func trojanLink(
var links []string var links []string
for _, addr := range addrs { for _, addr := range addrs {
params := baseParams params := make([]LinkParam, len(baseParams))
copy(params, baseParams)
if tls, ok := addr["tls"].(map[string]interface{}); ok && tls["enabled"].(bool) { if tls, ok := addr["tls"].(map[string]interface{}); ok && tls["enabled"].(bool) {
getTlsParams(&params, tls, "allowInsecure") getTlsParams(&params, tls, "allowInsecure")
} }
@@ -409,58 +426,58 @@ func vmessLink(
addrs []map[string]interface{}) []string { addrs []map[string]interface{}) []string {
uuid, _ := userConfig["uuid"].(string) uuid, _ := userConfig["uuid"].(string)
trasportParams := getTransportParams(inbound["transport"]) transportParams := getTransportParams(inbound["transport"])
var links []string var links []string
baseParams := map[string]interface{}{ baseParams := map[string]interface{}{
"v": 2, "v": "2",
"id": uuid, "id": uuid,
"aid": 0, "aid": 0,
} }
if trasportParams["type"] == "http" || trasportParams["type"] == "tcp" {
var net, typ, host, path string
for _, p := range transportParams {
switch p.Key {
case "type":
net = p.Value
case "host":
host = p.Value
case "path":
path = p.Value
}
}
if net == "http" || net == "tcp" {
baseParams["net"] = "tcp" baseParams["net"] = "tcp"
if trasportParams["type"] == "http" { if net == "http" {
baseParams["type"] = "http" typ = "http"
} }
} else { } else {
baseParams["net"] = trasportParams["type"] baseParams["net"] = net
} }
for _, addr := range addrs { for _, addr := range addrs {
obj := baseParams obj := make(map[string]interface{})
obj["add"], _ = addr["server"].(string) for k, v := range baseParams {
port, _ := addr["server_port"].(float64) obj[k] = v
obj["port"] = uint(port)
obj["ps"], _ = addr["remark"].(string)
if trasportParams["host"] != "" {
obj["host"] = trasportParams["host"]
}
if trasportParams["path"] != "" {
obj["path"] = trasportParams["path"]
}
if tls, ok := addr["tls"].(map[string]interface{}); ok && tls["enabled"].(bool) {
obj["tls"] = "tls"
if insecure, ok := tls["insecure"].(bool); ok && insecure {
obj["allowInsecure"] = 1
}
if sni, ok := tls["server_name"].(string); ok {
obj["sni"] = sni
}
if alpn, ok := tls["alpn"].([]interface{}); ok {
alpnList := make([]string, len(alpn))
for i, v := range alpn {
alpnList[i] = v.(string)
}
obj["alpn"] = strings.Join(alpnList, ",")
}
if utls, ok := tls["utls"].(map[string]interface{}); ok {
obj["fp"], _ = utls["fingerprint"].(string)
}
} else {
obj["tls"] = "none"
} }
jsonStr, _ := json.MarshalIndent(obj, "", " ") obj["add"], _ = addr["server"].(string)
port, _ := addr["server_port"].(float64)
obj["port"] = fmt.Sprintf("%.0f", port)
obj["ps"], _ = addr["remark"].(string)
if typ != "" {
obj["type"] = typ
}
if host != "" {
obj["host"] = host
}
if path != "" {
obj["path"] = path
}
populateVmessTlsParams(obj, addr["tls"])
jsonStr, _ := json.Marshal(obj)
uri := fmt.Sprintf("vmess://%s", toBase64(jsonStr)) uri := fmt.Sprintf("vmess://%s", toBase64(jsonStr))
links = append(links, uri) links = append(links, uri)
@@ -468,19 +485,43 @@ func vmessLink(
return links return links
} }
func toBase64(d []byte) string { func populateVmessTlsParams(obj map[string]interface{}, tlsConfig interface{}) {
return base64.StdEncoding.EncodeToString([]byte(d)) if tlsMap, ok := tlsConfig.(map[string]interface{}); ok && tlsMap["enabled"].(bool) {
obj["tls"] = "tls"
var tlsParams []LinkParam
getTlsParams(&tlsParams, tlsMap, "allowInsecure")
for _, p := range tlsParams {
switch p.Key {
case "security":
// ignore, as "tls" is already set
case "allowInsecure":
obj["allowInsecure"] = 1
case "sni":
obj["sni"] = p.Value
case "fp":
obj["fp"] = p.Value
case "alpn":
obj["alpn"] = p.Value
}
}
} else {
obj["tls"] = "none"
}
} }
func addParams(uri string, params map[string]string, remark string) string { func toBase64(d []byte) string {
return base64.StdEncoding.EncodeToString(d)
}
func addParams(uri string, params []LinkParam, remark string) string {
URL, _ := url.Parse(uri) URL, _ := url.Parse(uri)
var q []string var q []string
for k, v := range params { for _, p := range params {
switch k { switch p.Key {
case "mport", "alpn": case "mport", "alpn":
q = append(q, fmt.Sprintf("%s=%s", k, v)) q = append(q, fmt.Sprintf("%s=%s", p.Key, p.Value))
default: default:
q = append(q, fmt.Sprintf("%s=%s", k, url.QueryEscape(v))) q = append(q, fmt.Sprintf("%s=%s", p.Key, url.QueryEscape(p.Value)))
} }
} }
URL.RawQuery = strings.Join(q, "&") URL.RawQuery = strings.Join(q, "&")
@@ -488,80 +529,87 @@ func addParams(uri string, params map[string]string, remark string) string {
return URL.String() return URL.String()
} }
func getTransportParams(t interface{}) map[string]string { func getTransportParams(t interface{}) []LinkParam {
params := map[string]string{} var params []LinkParam
trasport, _ := t.(map[string]interface{}) trasport, _ := t.(map[string]interface{})
if transportType, ok := trasport["type"].(string); ok { var transportType string
params["type"] = transportType if tt, ok := trasport["type"].(string); ok {
transportType = tt
} else { } else {
params["type"] = "tcp" transportType = "tcp"
}
params = append(params, LinkParam{"type", transportType})
if transportType == "tcp" {
return params return params
} }
switch params["type"] {
switch transportType {
case "http": case "http":
if host, ok := trasport["host"].([]interface{}); ok { if host, ok := trasport["host"].([]interface{}); ok {
var hosts []string var hosts []string
for _, v := range host { for _, v := range host {
hosts = append(hosts, v.(string)) hosts = append(hosts, v.(string))
} }
params["host"] = strings.Join(hosts, ",") params = append(params, LinkParam{"host", strings.Join(hosts, ",")})
} }
if path, ok := trasport["path"].(string); ok { if path, ok := trasport["path"].(string); ok {
params["path"] = path params = append(params, LinkParam{"path", path})
} }
case "ws": case "ws":
if path, ok := trasport["path"].(string); ok { if path, ok := trasport["path"].(string); ok {
params["path"] = path params = append(params, LinkParam{"path", path})
} }
if headers, ok := trasport["headers"].(map[string]interface{}); ok { if headers, ok := trasport["headers"].(map[string]interface{}); ok {
if host, ok := headers["Host"].(string); ok { if host, ok := headers["Host"].(string); ok {
params["host"] = host params = append(params, LinkParam{"host", host})
} }
} }
case "grpc": case "grpc":
if serviceName, ok := trasport["service_name"].(string); ok { if serviceName, ok := trasport["service_name"].(string); ok {
params["serviceName"] = serviceName params = append(params, LinkParam{"serviceName", serviceName})
} }
case "httpupgrade": case "httpupgrade":
if host, ok := trasport["host"].(string); ok { if host, ok := trasport["host"].(string); ok {
params["host"] = host params = append(params, LinkParam{"host", host})
} }
if path, ok := trasport["path"].(string); ok { if path, ok := trasport["path"].(string); ok {
params["path"] = path params = append(params, LinkParam{"path", path})
} }
} }
return params return params
} }
func getTlsParams(params *map[string]string, tls map[string]interface{}, insecureKey string) { func getTlsParams(params *[]LinkParam, tls map[string]interface{}, insecureKey string) {
if reality, ok := tls["reality"].(map[string]interface{}); ok && reality["enabled"].(bool) { if reality, ok := tls["reality"].(map[string]interface{}); ok && reality["enabled"].(bool) {
(*params)["security"] = "reality" *params = append(*params, LinkParam{"security", "reality"})
if pbk, ok := reality["public_key"].(string); ok { if pbk, ok := reality["public_key"].(string); ok {
(*params)["pbk"] = pbk *params = append(*params, LinkParam{"pbk", pbk})
} }
if sid, ok := reality["short_id"].(string); ok { if sid, ok := reality["short_id"].(string); ok {
(*params)["sid"] = sid *params = append(*params, LinkParam{"sid", sid})
} }
} else { } else {
(*params)["security"] = "tls" *params = append(*params, LinkParam{"security", "tls"})
if insecure, ok := tls["insecure"].(bool); ok && insecure { if insecure, ok := tls["insecure"].(bool); ok && insecure {
(*params)[insecureKey] = "1" *params = append(*params, LinkParam{insecureKey, "1"})
} }
if disableSni, ok := tls["disable_sni"].(bool); ok && disableSni { if disableSni, ok := tls["disable_sni"].(bool); ok && disableSni {
(*params)["disable_sni"] = "1" *params = append(*params, LinkParam{"disable_sni", "1"})
} }
} }
if utls, ok := tls["utls"].(map[string]interface{}); ok { if utls, ok := tls["utls"].(map[string]interface{}); ok {
(*params)["fp"], _ = utls["fingerprint"].(string) if fingerprint, ok := utls["fingerprint"].(string); ok {
*params = append(*params, LinkParam{"fp", fingerprint})
}
} }
if sni, ok := tls["server_name"].(string); ok { if sni, ok := tls["server_name"].(string); ok {
(*params)["sni"] = sni *params = append(*params, LinkParam{"sni", sni})
} }
if alpn, ok := tls["alpn"].([]interface{}); ok { if alpn, ok := tls["alpn"].([]interface{}); ok {
alpnList := make([]string, len(alpn)) alpnList := make([]string, len(alpn))
for i, v := range alpn { for i, v := range alpn {
alpnList[i] = v.(string) alpnList[i] = v.(string)
} }
(*params)["alpn"] = strings.Join(alpnList, ",") *params = append(*params, LinkParam{"alpn", strings.Join(alpnList, ",")})
} }
} }