Files
ant-black 70132417ad publish: 1.2.0 snapshot (f3d7ec5)
channel: master

version: 1.2.0

source-ref: D:\code\open_source\ant-chrome master

source-commit: f3d7ec5

merged-public-base: 3d264eb
2026-05-05 18:08:10 +08:00

85 lines
2.3 KiB
Go

package proxy
import (
"fmt"
"net/url"
"strings"
"gopkg.in/yaml.v3"
)
func parseClashNode(src string) (map[string]interface{}, string, error) {
data := strings.TrimSpace(src)
if strings.HasPrefix(strings.ToLower(data), "clash://") {
raw := strings.TrimPrefix(data, "clash://")
raw, _ = url.QueryUnescape(raw)
decoded, err := decodeBase64String(raw)
if err != nil {
return nil, "", err
}
data = string(decoded)
}
var payload interface{}
if err := yaml.Unmarshal([]byte(data), &payload); err != nil {
return nil, "", err
}
nodeMap := pickClashNode(payload)
if nodeMap == nil {
return nil, "", fmt.Errorf("clash 节点解析失败")
}
nodeType := strings.ToLower(getMapString(nodeMap, "type"))
switch nodeType {
case "socks5", "http", "https":
return nil, buildStandardProxyFromClash(nodeMap, nodeType), nil
case "vmess":
return buildOutboundFromClashVmess(nodeMap)
case "vless":
return buildOutboundFromClashVless(nodeMap)
case "trojan":
return buildOutboundFromClashTrojan(nodeMap)
case "ss", "shadowsocks":
return buildOutboundFromClashSS(nodeMap)
case "ssr":
return nil, "", fmt.Errorf("不支持 ShadowsocksR 协议,Xray 不支持 SSR,请使用 SS/vmess/vless/trojan")
case "hysteria2", "hysteria":
return buildOutboundFromClashHysteria2(nodeMap)
}
return nil, "", fmt.Errorf("不支持的节点类型")
}
func pickClashNode(payload interface{}) map[string]interface{} {
if m := toStringMap(payload); m != nil {
if proxies, ok := m["proxies"]; ok {
if arr, ok := proxies.([]interface{}); ok && len(arr) > 0 {
return toStringMap(arr[0])
}
}
if proxyItem, ok := m["proxy"]; ok {
if node := toStringMap(proxyItem); node != nil {
return node
}
}
return m
}
if arr, ok := payload.([]interface{}); ok && len(arr) > 0 {
return toStringMap(arr[0])
}
return nil
}
func buildStandardProxyFromClash(node map[string]interface{}, scheme string) string {
host := getMapString(node, "server")
port := getMapInt(node, "port")
username := getMapString(node, "username")
password := getMapString(node, "password")
if host == "" || port == 0 {
return ""
}
address := fmt.Sprintf("%s:%d", host, port)
if username != "" {
user := url.UserPassword(username, password)
return fmt.Sprintf("%s://%s@%s", scheme, user.String(), address)
}
return fmt.Sprintf("%s://%s", scheme, address)
}