步骤 1:创建项目和初始化
创建一个新的Go项目,进入项目目录:
mkdir clash-node-converter cd clash-node-converter
初始化一个Go模块:
go mod init yourusername/yourmodule
步骤 2:编写转换工具
创建一个新的Go文件,main.go:
package main
import (
"encoding/json"
"flag"
"fmt"
"os"
"path/filepath"
"reflect"
"strings"
)
type Node struct {
Type string `json:"type"`
Name string `json:"name"`
Port int `json:"port"`
Protocol string `json:"protocol"`
Listen string `json:"listen"`
Destination string `json:"destination"`
}
type HTTPNode struct {
Name string `json:"name"`
ServerName string `json:"server_name"`
Port int `json:"port"`
Routes []Route `json:"routes"`
}
type Route struct {
Path string `json:"path"`
Method string `json:"method"`
Handler string `json:"handler"`
}
type TCPSocket struct {
Name string `json:"name"`
LocalIP string `json:"local_ip"`
LocalPort int `json:"local_port"`
RemoteIP string `json:"remote_ip"`
RemotePort int `json:"remote_port"`
Protocol string `json:"protocol"`
}
type SSLsocket struct {
Name string `json:"name"`
CertFile string `json:"cert_file"`
KeyFile string `json:"key_file"`
ServerName string `json:"server_name"`
TLSVersion string `json:"tls_version"`
}
func main() {
var configfile string
var outputformat string
flags := flag.New()
flags.StringVar(&configfile, "c", "", "Clash configuration file")
flags.StringVar(&outputformat, "o", "json", "Output format (json or yaml)")
args := os.Args
if len(args) < 2 {
flag.Usage()
os.Exit(1)
}
if !filepath.Exists(configfile) {
fmt.Printf("Error: configuration file %s not found\n", configfile)
os.Exit(1)
}
// Load Clash configuration
data, err := os.ReadFile(configfile)
if err != nil {
fmt.Printf("Error: failed to read configuration file\n", err)
os.Exit(1)
}
var nodes []Node
// Parse configuration data
err = json.Unmarshal(data, &nodes)
if err != nil {
fmt.Printf("Error: failed to parse configuration\n", err)
os.Exit(1)
}
// Convert nodes based on type
for _, node := range nodes {
switch node.Type {
case "http":
httpNode := node.(*HTTPNode)
// Convert httpNode to desired format
case "tcp":
tcpNode := node.(*TCPSocket)
// Convert tcpNode to desired format
case "udp":
udpNode := node.(*UDPsocket)
// Convert udpNode to desired format
case "ssl":
sslNode := node.(*SSLsocket)
// Convert sslNode to desired format
default:
fmt.Printf("Error: unsupported node type %s\n", node.Type)
os.Exit(1)
}
}
// Serialize to desired format
switch outputformat {
case "json":
err := json.Unmarshal(data, &nodes)
if err != nil {
fmt.Printf("Error: failed to serialize to JSON\n", err)
os.Exit(1)
}
case "yaml":
// Implement YAML conversion
// For example, using gorey library
// ...
// Then serialize
default:
fmt.Printf("Error: invalid output format %s\n", outputformat)
os.Exit(1)
}
// Output the result
fmt.Printf("Successfully converted nodes to %s format\n", outputformat)
}
步骤 3:实现节点转换逻辑
在 main.go 中,添加每个节点类型的转换逻辑,对于HTTP节点:
httpNode := node.(*HTTPNode) // 添加路由规则时,可以构建新的结构体或直接序列化
对于TCP节点:
tcpNode := node.(*TCPSocket) // 构建新的TCPSocket结构体或直接序列化
步骤 4:处理序列化输出
根据选定的输出格式(JSON或YAML)进行序列化,使用 json 包处理JSON,使用第三方库如 gorey 处理YAML。
步骤 5:编写测试用例
创建测试用例,确保工具能够正确读取Clash配置文件并转换为目标格式。
步骤 6:运行工具
运行工具时,可以指定输入配置文件和输出格式:
go run main.go -c config.json -o json
完整示例
以下是一个完整的转换工具,假设你有一个Clash配置文件:
package main
import (
"encoding/json"
"flag"
"fmt"
"os"
"path/filepath"
"reflect"
"strings"
)
type Node struct {
Type string `json:"type"`
Name string `json:"name"`
Port int `json:"port"`
Protocol string `json:"protocol"`
Listen string `json:"listen"`
Destination string `json:"destination"`
}
type HTTPNode struct {
Name string `json:"name"`
ServerName string `json:"server_name"`
Port int `json:"port"`
Routes []Route `json:"routes"`
}
type Route struct {
Path string `json:"path"`
Method string `json:"method"`
Handler string `json:"handler"`
}
type TCPSocket struct {
Name string `json:"name"`
LocalIP string `json:"local_ip"`
LocalPort int `json:"local_port"`
RemoteIP string `json:"remote_ip"`
RemotePort int `json:"remote_port"`
Protocol string `json:"protocol"`
}
type SSLsocket struct {
Name string `json:"name"`
CertFile string `json:"cert_file"`
KeyFile string `json:"key_file"`
ServerName string `json:"server_name"`
TLSVersion string `json:"tls_version"`
}
func main() {
var configfile string
var outputformat string
flags := flag.New()
flags.StringVar(&configfile, "c", "", "Clash configuration file")
flags.StringVar(&outputformat, "o", "json", "Output format (json or yaml)")
args := os.Args
if len(args) < 2 {
flag.Usage()
os.Exit(1)
}
if !filepath.Exists(configfile) {
fmt.Printf("Error: configuration file %s not found\n", configfile)
os.Exit(1)
}
data, err := os.ReadFile(configfile)
if err != nil {
fmt.Printf("Error: failed to read configuration file\n", err)
os.Exit(1)
}
var nodes []Node
err = json.Unmarshal(data, &nodes)
if err != nil {
fmt.Printf("Error: failed to parse configuration\n", err)
os.Exit(1)
}
for _, node := range nodes {
switch node.Type {
case "http":
httpNode := node.(*HTTPNode)
// 处理HTTP节点
case "tcp":
tcpNode := node.(*TCPSocket)
// 处理TCP节点
case "udp":
udpNode := node.(*UDPsocket)
// 处理UDP节点
case "ssl":
sslNode := node.(*SSLsocket)
// 处理SSL节点
default:
fmt.Printf("Error: unsupported node type %s\n", node.Type)
os.Exit(1)
}
}
switch outputformat {
case "json":
err = json.Unmarshal(data, &nodes)
if err != nil {
fmt.Printf("Error: failed to serialize to JSON\n", err)
os.Exit(1)
}
case "yaml":
// 使用gorey库进行YAML序列化
// ...
// 实现YAML转换
default:
fmt.Printf("Error: invalid output format %s\n", outputformat)
os.Exit(1)
}
fmt.Printf("Successfully converted nodes to %s format\n", outputformat)
}
使用说明
-
安装必要的库:确保安装了
gorey库来支持YAML转换。 -
运行工具:
go run main.go -c config.json -o json
- 输入输出格式:









