进一步查看前半部分对不对
This commit is contained in:
@@ -29,7 +29,7 @@ func GenerateClashWithTemplate(templateName string, servers []model.Server, user
|
|||||||
for _, s := range servers {
|
for _, s := range servers {
|
||||||
conf := service.BuildNodeConfig(&s)
|
conf := service.BuildNodeConfig(&s)
|
||||||
password := service.GenerateServerPassword(&s, &user)
|
password := service.GenerateServerPassword(&s, &user)
|
||||||
proxy := buildClashProxy(conf, password)
|
proxy := buildClashProxy(templateName, conf, password)
|
||||||
if proxy == nil {
|
if proxy == nil {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
@@ -53,35 +53,88 @@ func GenerateClashWithTemplate(templateName string, servers []model.Server, user
|
|||||||
return output, nil
|
return output, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func buildClashProxy(conf service.NodeServerConfig, password string) map[string]any {
|
func buildClashProxy(templateName string, conf service.NodeServerConfig, password string) map[string]any {
|
||||||
switch conf.Protocol {
|
switch conf.Protocol {
|
||||||
case "shadowsocks":
|
case "shadowsocks":
|
||||||
cipher, _ := conf.Cipher.(string)
|
cipher, _ := conf.Cipher.(string)
|
||||||
|
if templateName == "clash" {
|
||||||
|
switch cipher {
|
||||||
|
case "aes-128-gcm", "aes-192-gcm", "aes-256-gcm", "chacha20-ietf-poly1305":
|
||||||
|
default:
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
return map[string]any{
|
return map[string]any{
|
||||||
"name": conf.Name,
|
"name": conf.Name,
|
||||||
"type": "ss",
|
"type": "ss",
|
||||||
"server": conf.RawHost,
|
"server": conf.RawHost,
|
||||||
"port": conf.ServerPort,
|
"port": conf.Port,
|
||||||
"cipher": cipher,
|
"cipher": cipher,
|
||||||
"password": password,
|
"password": password,
|
||||||
|
"udp": true,
|
||||||
}
|
}
|
||||||
case "vmess":
|
case "vmess":
|
||||||
return map[string]any{
|
return map[string]any{
|
||||||
"name": conf.Name,
|
"name": conf.Name,
|
||||||
"type": "vmess",
|
"type": "vmess",
|
||||||
"server": conf.RawHost,
|
"server": conf.RawHost,
|
||||||
"port": conf.ServerPort,
|
"port": conf.Port,
|
||||||
"uuid": password,
|
"uuid": password,
|
||||||
"alterId": 0,
|
"alterId": 0,
|
||||||
"cipher": "auto",
|
"cipher": "auto",
|
||||||
"udp": true,
|
"udp": true,
|
||||||
}
|
}
|
||||||
|
case "vless":
|
||||||
|
if templateName != "clashmeta" {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
proxy := map[string]any{
|
||||||
|
"name": conf.Name,
|
||||||
|
"type": "vless",
|
||||||
|
"server": conf.RawHost,
|
||||||
|
"port": conf.Port,
|
||||||
|
"uuid": password,
|
||||||
|
"alterId": 0,
|
||||||
|
"cipher": "auto",
|
||||||
|
"udp": true,
|
||||||
|
"flow": toClashString(conf.Flow),
|
||||||
|
"encryption": "none",
|
||||||
|
"tls": false,
|
||||||
|
}
|
||||||
|
switch toClashInt(conf.Tls) {
|
||||||
|
case 1:
|
||||||
|
proxy["tls"] = true
|
||||||
|
if tlsSettings, ok := conf.TlsSettings.(map[string]any); ok {
|
||||||
|
proxy["skip-cert-verify"] = toClashBool(tlsSettings["allow_insecure"])
|
||||||
|
if serverName := toClashString(tlsSettings["server_name"]); serverName != "" {
|
||||||
|
proxy["servername"] = serverName
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case 2:
|
||||||
|
proxy["tls"] = true
|
||||||
|
if tlsSettings, ok := conf.TlsSettings.(map[string]any); ok {
|
||||||
|
proxy["skip-cert-verify"] = toClashBool(tlsSettings["allow_insecure"])
|
||||||
|
if serverName := toClashString(tlsSettings["server_name"]); serverName != "" {
|
||||||
|
proxy["servername"] = serverName
|
||||||
|
}
|
||||||
|
proxy["reality-opts"] = map[string]any{
|
||||||
|
"public-key": toClashString(tlsSettings["public_key"]),
|
||||||
|
"short-id": toClashString(tlsSettings["short_id"]),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
network := toClashString(conf.Network)
|
||||||
|
if network == "" {
|
||||||
|
network = "tcp"
|
||||||
|
}
|
||||||
|
proxy["network"] = network
|
||||||
|
return proxy
|
||||||
case "trojan":
|
case "trojan":
|
||||||
return map[string]any{
|
return map[string]any{
|
||||||
"name": conf.Name,
|
"name": conf.Name,
|
||||||
"type": "trojan",
|
"type": "trojan",
|
||||||
"server": conf.RawHost,
|
"server": conf.RawHost,
|
||||||
"port": conf.ServerPort,
|
"port": conf.Port,
|
||||||
"password": password,
|
"password": password,
|
||||||
"udp": true,
|
"udp": true,
|
||||||
}
|
}
|
||||||
@@ -155,6 +208,54 @@ func appendUniqueAny(base []any, values ...any) []any {
|
|||||||
return base
|
return base
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func toClashString(value any) string {
|
||||||
|
switch typed := value.(type) {
|
||||||
|
case string:
|
||||||
|
return typed
|
||||||
|
case nil:
|
||||||
|
return ""
|
||||||
|
default:
|
||||||
|
return fmt.Sprint(typed)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func toClashInt(value any) int {
|
||||||
|
switch typed := value.(type) {
|
||||||
|
case int:
|
||||||
|
return typed
|
||||||
|
case int64:
|
||||||
|
return int(typed)
|
||||||
|
case float64:
|
||||||
|
return int(typed)
|
||||||
|
case string:
|
||||||
|
if typed == "" {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
var result int
|
||||||
|
fmt.Sscanf(typed, "%d", &result)
|
||||||
|
return result
|
||||||
|
default:
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func toClashBool(value any) bool {
|
||||||
|
switch typed := value.(type) {
|
||||||
|
case bool:
|
||||||
|
return typed
|
||||||
|
case int:
|
||||||
|
return typed != 0
|
||||||
|
case int64:
|
||||||
|
return typed != 0
|
||||||
|
case float64:
|
||||||
|
return typed != 0
|
||||||
|
case string:
|
||||||
|
return typed == "1" || strings.EqualFold(typed, "true")
|
||||||
|
default:
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func generateClashFallback(servers []model.Server, user model.User) string {
|
func generateClashFallback(servers []model.Server, user model.User) string {
|
||||||
var builder strings.Builder
|
var builder strings.Builder
|
||||||
|
|
||||||
@@ -163,7 +264,7 @@ func generateClashFallback(servers []model.Server, user model.User) string {
|
|||||||
for _, s := range servers {
|
for _, s := range servers {
|
||||||
conf := service.BuildNodeConfig(&s)
|
conf := service.BuildNodeConfig(&s)
|
||||||
password := service.GenerateServerPassword(&s, &user)
|
password := service.GenerateServerPassword(&s, &user)
|
||||||
proxy := buildClashProxy(conf, password)
|
proxy := buildClashProxy("clash", conf, password)
|
||||||
if proxy == nil {
|
if proxy == nil {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -52,7 +52,7 @@ func buildShadowsocks(c service.NodeServerConfig, password string) string {
|
|||||||
userInfo := base64.StdEncoding.EncodeToString([]byte(fmt.Sprintf("%s:%s", cipher, password)))
|
userInfo := base64.StdEncoding.EncodeToString([]byte(fmt.Sprintf("%s:%s", cipher, password)))
|
||||||
userInfo = strings.TrimRight(strings.ReplaceAll(strings.ReplaceAll(userInfo, "+", "-"), "/", "_"), "=")
|
userInfo = strings.TrimRight(strings.ReplaceAll(strings.ReplaceAll(userInfo, "+", "-"), "/", "_"), "=")
|
||||||
|
|
||||||
link := fmt.Sprintf("ss://%s@%s:%d", userInfo, wrapIPv6(c.RawHost), c.ServerPort)
|
link := fmt.Sprintf("ss://%s@%s:%d", userInfo, wrapIPv6(c.RawHost), c.Port)
|
||||||
params := url.Values{}
|
params := url.Values{}
|
||||||
if plugin := toString(c.Plugin); plugin != "" {
|
if plugin := toString(c.Plugin); plugin != "" {
|
||||||
opts := toString(c.PluginOpts)
|
opts := toString(c.PluginOpts)
|
||||||
@@ -69,7 +69,7 @@ func buildVmess(c service.NodeServerConfig, password string) string {
|
|||||||
"v": "2",
|
"v": "2",
|
||||||
"ps": c.Name,
|
"ps": c.Name,
|
||||||
"add": c.RawHost,
|
"add": c.RawHost,
|
||||||
"port": fmt.Sprintf("%d", c.ServerPort),
|
"port": fmt.Sprintf("%d", c.Port),
|
||||||
"id": password,
|
"id": password,
|
||||||
"aid": "0",
|
"aid": "0",
|
||||||
"net": toString(c.Network),
|
"net": toString(c.Network),
|
||||||
@@ -145,7 +145,7 @@ func buildVless(c service.NodeServerConfig, password string) string {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return fmt.Sprintf("vless://%s@%s:%d?%s#%s", password, wrapIPv6(c.RawHost), c.ServerPort, params.Encode(), url.PathEscape(c.Name))
|
return fmt.Sprintf("vless://%s@%s:%d?%s#%s", password, wrapIPv6(c.RawHost), c.Port, params.Encode(), url.PathEscape(c.Name))
|
||||||
}
|
}
|
||||||
|
|
||||||
func buildTrojan(c service.NodeServerConfig, password string) string {
|
func buildTrojan(c service.NodeServerConfig, password string) string {
|
||||||
@@ -176,7 +176,7 @@ func buildTrojan(c service.NodeServerConfig, password string) string {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return fmt.Sprintf("trojan://%s@%s:%d?%s#%s", password, wrapIPv6(c.RawHost), c.ServerPort, params.Encode(), url.PathEscape(c.Name))
|
return fmt.Sprintf("trojan://%s@%s:%d?%s#%s", password, wrapIPv6(c.RawHost), c.Port, params.Encode(), url.PathEscape(c.Name))
|
||||||
}
|
}
|
||||||
|
|
||||||
func buildHysteria(c service.NodeServerConfig, password string) string {
|
func buildHysteria(c service.NodeServerConfig, password string) string {
|
||||||
@@ -188,7 +188,10 @@ func buildHysteria(c service.NodeServerConfig, password string) string {
|
|||||||
params.Set("obfs", "salamander")
|
params.Set("obfs", "salamander")
|
||||||
params.Set("obfs-password", toString(c.ObfsPassword))
|
params.Set("obfs-password", toString(c.ObfsPassword))
|
||||||
}
|
}
|
||||||
return fmt.Sprintf("hysteria2://%s@%s:%d?%s#%s", password, wrapIPv6(c.RawHost), c.ServerPort, params.Encode(), url.PathEscape(c.Name))
|
if c.Ports != "" {
|
||||||
|
params.Set("mport", c.Ports)
|
||||||
|
}
|
||||||
|
return fmt.Sprintf("hysteria2://%s@%s:%d?%s#%s", password, wrapIPv6(c.RawHost), c.Port, params.Encode(), url.PathEscape(c.Name))
|
||||||
}
|
}
|
||||||
|
|
||||||
params.Set("protocol", "udp")
|
params.Set("protocol", "udp")
|
||||||
@@ -200,7 +203,7 @@ func buildHysteria(c service.NodeServerConfig, password string) string {
|
|||||||
params.Set("downmbps", fmt.Sprintf("%v", c.DownMbps))
|
params.Set("downmbps", fmt.Sprintf("%v", c.DownMbps))
|
||||||
}
|
}
|
||||||
|
|
||||||
return fmt.Sprintf("hysteria://%s:%d?%s#%s", wrapIPv6(c.RawHost), c.ServerPort, params.Encode(), url.PathEscape(c.Name))
|
return fmt.Sprintf("hysteria://%s:%d?%s#%s", wrapIPv6(c.RawHost), c.Port, params.Encode(), url.PathEscape(c.Name))
|
||||||
}
|
}
|
||||||
|
|
||||||
func buildTuic(c service.NodeServerConfig, password string) string {
|
func buildTuic(c service.NodeServerConfig, password string) string {
|
||||||
@@ -209,23 +212,23 @@ func buildTuic(c service.NodeServerConfig, password string) string {
|
|||||||
params.Set("congestion_control", toString(c.CongestionControl))
|
params.Set("congestion_control", toString(c.CongestionControl))
|
||||||
params.Set("udp-relay-mode", "native")
|
params.Set("udp-relay-mode", "native")
|
||||||
|
|
||||||
return fmt.Sprintf("tuic://%s:%s@%s:%d?%s#%s", password, password, wrapIPv6(c.RawHost), c.ServerPort, params.Encode(), url.PathEscape(c.Name))
|
return fmt.Sprintf("tuic://%s:%s@%s:%d?%s#%s", password, password, wrapIPv6(c.RawHost), c.Port, params.Encode(), url.PathEscape(c.Name))
|
||||||
}
|
}
|
||||||
|
|
||||||
func buildAnyTLS(c service.NodeServerConfig, password string) string {
|
func buildAnyTLS(c service.NodeServerConfig, password string) string {
|
||||||
params := url.Values{}
|
params := url.Values{}
|
||||||
params.Set("sni", toString(c.ServerName))
|
params.Set("sni", toString(c.ServerName))
|
||||||
return fmt.Sprintf("anytls://%s@%s:%d?%s#%s", password, wrapIPv6(c.RawHost), c.ServerPort, params.Encode(), url.PathEscape(c.Name))
|
return fmt.Sprintf("anytls://%s@%s:%d?%s#%s", password, wrapIPv6(c.RawHost), c.Port, params.Encode(), url.PathEscape(c.Name))
|
||||||
}
|
}
|
||||||
|
|
||||||
func buildSocks(c service.NodeServerConfig, password string) string {
|
func buildSocks(c service.NodeServerConfig, password string) string {
|
||||||
auth := base64.StdEncoding.EncodeToString([]byte(password + ":" + password))
|
auth := base64.StdEncoding.EncodeToString([]byte(password + ":" + password))
|
||||||
return fmt.Sprintf("socks://%s@%s:%d#%s", auth, wrapIPv6(c.RawHost), c.ServerPort, url.PathEscape(c.Name))
|
return fmt.Sprintf("socks://%s@%s:%d#%s", auth, wrapIPv6(c.RawHost), c.Port, url.PathEscape(c.Name))
|
||||||
}
|
}
|
||||||
|
|
||||||
func buildHttp(c service.NodeServerConfig, password string) string {
|
func buildHttp(c service.NodeServerConfig, password string) string {
|
||||||
auth := base64.StdEncoding.EncodeToString([]byte(password + ":" + password))
|
auth := base64.StdEncoding.EncodeToString([]byte(password + ":" + password))
|
||||||
link := fmt.Sprintf("http://%s@%s:%d", auth, wrapIPv6(c.RawHost), c.ServerPort)
|
link := fmt.Sprintf("http://%s@%s:%d", auth, wrapIPv6(c.RawHost), c.Port)
|
||||||
if toInt(c.Tls) > 0 {
|
if toInt(c.Tls) > 0 {
|
||||||
params := url.Values{}
|
params := url.Values{}
|
||||||
params.Set("security", "tls")
|
params.Set("security", "tls")
|
||||||
|
|||||||
@@ -64,7 +64,7 @@ func buildSingBoxOutbound(conf service.NodeServerConfig, password string) map[st
|
|||||||
outbound := map[string]any{
|
outbound := map[string]any{
|
||||||
"tag": conf.Name,
|
"tag": conf.Name,
|
||||||
"server": conf.RawHost,
|
"server": conf.RawHost,
|
||||||
"server_port": conf.ServerPort,
|
"server_port": conf.Port,
|
||||||
}
|
}
|
||||||
|
|
||||||
switch conf.Protocol {
|
switch conf.Protocol {
|
||||||
@@ -76,6 +76,19 @@ func buildSingBoxOutbound(conf service.NodeServerConfig, password string) map[st
|
|||||||
outbound["type"] = "vmess"
|
outbound["type"] = "vmess"
|
||||||
outbound["uuid"] = password
|
outbound["uuid"] = password
|
||||||
outbound["security"] = "auto"
|
outbound["security"] = "auto"
|
||||||
|
case "vless":
|
||||||
|
outbound["type"] = "vless"
|
||||||
|
outbound["uuid"] = password
|
||||||
|
outbound["packet_encoding"] = "xudp"
|
||||||
|
if flow := singBoxString(conf.Flow); flow != "" {
|
||||||
|
outbound["flow"] = flow
|
||||||
|
}
|
||||||
|
if tls := buildSingBoxTLS(conf); tls != nil {
|
||||||
|
outbound["tls"] = tls
|
||||||
|
}
|
||||||
|
if transport := buildSingBoxTransport(conf); transport != nil {
|
||||||
|
outbound["transport"] = transport
|
||||||
|
}
|
||||||
case "trojan":
|
case "trojan":
|
||||||
outbound["type"] = "trojan"
|
outbound["type"] = "trojan"
|
||||||
outbound["password"] = password
|
outbound["password"] = password
|
||||||
@@ -96,7 +109,7 @@ func generateSingBoxFallback(servers []model.Server, user model.User) (string, e
|
|||||||
outbound := map[string]interface{}{
|
outbound := map[string]interface{}{
|
||||||
"tag": conf.Name,
|
"tag": conf.Name,
|
||||||
"server": conf.RawHost,
|
"server": conf.RawHost,
|
||||||
"server_port": conf.ServerPort,
|
"server_port": conf.Port,
|
||||||
}
|
}
|
||||||
|
|
||||||
switch conf.Protocol {
|
switch conf.Protocol {
|
||||||
@@ -108,6 +121,19 @@ func generateSingBoxFallback(servers []model.Server, user model.User) (string, e
|
|||||||
outbound["type"] = "vmess"
|
outbound["type"] = "vmess"
|
||||||
outbound["uuid"] = password
|
outbound["uuid"] = password
|
||||||
outbound["security"] = "auto"
|
outbound["security"] = "auto"
|
||||||
|
case "vless":
|
||||||
|
outbound["type"] = "vless"
|
||||||
|
outbound["uuid"] = password
|
||||||
|
outbound["packet_encoding"] = "xudp"
|
||||||
|
if flow := singBoxString(conf.Flow); flow != "" {
|
||||||
|
outbound["flow"] = flow
|
||||||
|
}
|
||||||
|
if tls := buildSingBoxTLS(conf); tls != nil {
|
||||||
|
outbound["tls"] = tls
|
||||||
|
}
|
||||||
|
if transport := buildSingBoxTransport(conf); transport != nil {
|
||||||
|
outbound["transport"] = transport
|
||||||
|
}
|
||||||
case "trojan":
|
case "trojan":
|
||||||
outbound["type"] = "trojan"
|
outbound["type"] = "trojan"
|
||||||
outbound["password"] = password
|
outbound["password"] = password
|
||||||
@@ -133,3 +159,128 @@ func generateSingBoxFallback(servers []model.Server, user model.User) (string, e
|
|||||||
data, err := json.MarshalIndent(config, "", " ")
|
data, err := json.MarshalIndent(config, "", " ")
|
||||||
return string(data), err
|
return string(data), err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func buildSingBoxTLS(conf service.NodeServerConfig) map[string]any {
|
||||||
|
switch singBoxInt(conf.Tls) {
|
||||||
|
case 1:
|
||||||
|
tls := map[string]any{
|
||||||
|
"enabled": true,
|
||||||
|
}
|
||||||
|
if tlsSettings, ok := conf.TlsSettings.(map[string]any); ok {
|
||||||
|
tls["insecure"] = singBoxBool(tlsSettings["allow_insecure"])
|
||||||
|
if serverName := singBoxString(tlsSettings["server_name"]); serverName != "" {
|
||||||
|
tls["server_name"] = serverName
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return tls
|
||||||
|
case 2:
|
||||||
|
tls := map[string]any{
|
||||||
|
"enabled": true,
|
||||||
|
}
|
||||||
|
if tlsSettings, ok := conf.TlsSettings.(map[string]any); ok {
|
||||||
|
tls["insecure"] = singBoxBool(tlsSettings["allow_insecure"])
|
||||||
|
if serverName := singBoxString(tlsSettings["server_name"]); serverName != "" {
|
||||||
|
tls["server_name"] = serverName
|
||||||
|
}
|
||||||
|
tls["reality"] = map[string]any{
|
||||||
|
"enabled": true,
|
||||||
|
"public_key": singBoxString(tlsSettings["public_key"]),
|
||||||
|
"short_id": singBoxString(tlsSettings["short_id"]),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return tls
|
||||||
|
default:
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func buildSingBoxTransport(conf service.NodeServerConfig) map[string]any {
|
||||||
|
network := singBoxString(conf.Network)
|
||||||
|
settings, _ := conf.NetworkSettings.(map[string]any)
|
||||||
|
switch network {
|
||||||
|
case "ws":
|
||||||
|
transport := map[string]any{
|
||||||
|
"type": "ws",
|
||||||
|
}
|
||||||
|
if settings != nil {
|
||||||
|
if path := singBoxString(settings["path"]); path != "" {
|
||||||
|
transport["path"] = path
|
||||||
|
}
|
||||||
|
if headers, ok := settings["headers"].(map[string]any); ok {
|
||||||
|
if host := singBoxString(headers["Host"]); host != "" {
|
||||||
|
transport["headers"] = map[string]any{"Host": host}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return transport
|
||||||
|
case "grpc":
|
||||||
|
transport := map[string]any{
|
||||||
|
"type": "grpc",
|
||||||
|
}
|
||||||
|
if settings != nil {
|
||||||
|
if serviceName := singBoxString(settings["serviceName"]); serviceName != "" {
|
||||||
|
transport["service_name"] = serviceName
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return transport
|
||||||
|
case "httpupgrade":
|
||||||
|
transport := map[string]any{
|
||||||
|
"type": "httpupgrade",
|
||||||
|
}
|
||||||
|
if settings != nil {
|
||||||
|
if path := singBoxString(settings["path"]); path != "" {
|
||||||
|
transport["path"] = path
|
||||||
|
}
|
||||||
|
if host := singBoxString(settings["host"]); host != "" {
|
||||||
|
transport["host"] = host
|
||||||
|
}
|
||||||
|
if headers, ok := settings["headers"].(map[string]any); ok && len(headers) > 0 {
|
||||||
|
transport["headers"] = headers
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return transport
|
||||||
|
default:
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func singBoxString(value any) string {
|
||||||
|
switch typed := value.(type) {
|
||||||
|
case string:
|
||||||
|
return typed
|
||||||
|
case nil:
|
||||||
|
return ""
|
||||||
|
default:
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func singBoxInt(value any) int {
|
||||||
|
switch typed := value.(type) {
|
||||||
|
case int:
|
||||||
|
return typed
|
||||||
|
case int64:
|
||||||
|
return int(typed)
|
||||||
|
case float64:
|
||||||
|
return int(typed)
|
||||||
|
default:
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func singBoxBool(value any) bool {
|
||||||
|
switch typed := value.(type) {
|
||||||
|
case bool:
|
||||||
|
return typed
|
||||||
|
case int:
|
||||||
|
return typed != 0
|
||||||
|
case int64:
|
||||||
|
return typed != 0
|
||||||
|
case float64:
|
||||||
|
return typed != 0
|
||||||
|
case string:
|
||||||
|
return typed == "1" || typed == "true"
|
||||||
|
default:
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -68,6 +68,8 @@ type NodeServerConfig struct {
|
|||||||
Name string `json:"-"`
|
Name string `json:"-"`
|
||||||
Protocol string `json:"protocol"`
|
Protocol string `json:"protocol"`
|
||||||
RawHost string `json:"-"`
|
RawHost string `json:"-"`
|
||||||
|
Port int `json:"-"`
|
||||||
|
Ports string `json:"-"`
|
||||||
ListenIP string `json:"listen_ip"`
|
ListenIP string `json:"listen_ip"`
|
||||||
ServerPort int `json:"server_port"`
|
ServerPort int `json:"server_port"`
|
||||||
Network any `json:"network"`
|
Network any `json:"network"`
|
||||||
@@ -230,10 +232,13 @@ func CurrentRate(server *model.Server) float64 {
|
|||||||
|
|
||||||
func BuildNodeConfig(node *model.Server) NodeServerConfig {
|
func BuildNodeConfig(node *model.Server) NodeServerConfig {
|
||||||
settings := parseObject(node.ProtocolSettings)
|
settings := parseObject(node.ProtocolSettings)
|
||||||
|
clientPort, portRange := resolveClientPort(node.Port, node.ServerPort)
|
||||||
response := NodeServerConfig{
|
response := NodeServerConfig{
|
||||||
Name: node.Name,
|
Name: node.Name,
|
||||||
Protocol: node.Type,
|
Protocol: node.Type,
|
||||||
RawHost: node.Host,
|
RawHost: node.Host,
|
||||||
|
Port: clientPort,
|
||||||
|
Ports: portRange,
|
||||||
ListenIP: "0.0.0.0",
|
ListenIP: "0.0.0.0",
|
||||||
ServerPort: node.ServerPort,
|
ServerPort: node.ServerPort,
|
||||||
Network: getMapAny(settings, "network"),
|
Network: getMapAny(settings, "network"),
|
||||||
@@ -408,6 +413,31 @@ func uuidPrefixBase64(uuid string, size int) string {
|
|||||||
return base64.StdEncoding.EncodeToString([]byte(uuid[:size]))
|
return base64.StdEncoding.EncodeToString([]byte(uuid[:size]))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func resolveClientPort(rawPort string, fallback int) (int, string) {
|
||||||
|
rawPort = strings.TrimSpace(rawPort)
|
||||||
|
if rawPort == "" {
|
||||||
|
return fallback, ""
|
||||||
|
}
|
||||||
|
|
||||||
|
if strings.Contains(rawPort, "-") {
|
||||||
|
parts := strings.SplitN(rawPort, "-", 2)
|
||||||
|
start, errStart := strconv.Atoi(strings.TrimSpace(parts[0]))
|
||||||
|
end, errEnd := strconv.Atoi(strings.TrimSpace(parts[1]))
|
||||||
|
if errStart == nil && errEnd == nil && start > 0 && end >= start {
|
||||||
|
if start == end {
|
||||||
|
return start, rawPort
|
||||||
|
}
|
||||||
|
return start + int(time.Now().UnixNano()%int64(end-start+1)), rawPort
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if port, err := strconv.Atoi(rawPort); err == nil && port > 0 {
|
||||||
|
return port, ""
|
||||||
|
}
|
||||||
|
|
||||||
|
return fallback, ""
|
||||||
|
}
|
||||||
|
|
||||||
func parseIntSlice(raw *string) []int {
|
func parseIntSlice(raw *string) []int {
|
||||||
if raw == nil || strings.TrimSpace(*raw) == "" {
|
if raw == nil || strings.TrimSpace(*raw) == "" {
|
||||||
return nil
|
return nil
|
||||||
|
|||||||
Reference in New Issue
Block a user