108 lines
2.0 KiB
Go
108 lines
2.0 KiB
Go
package common
|
|
|
|
import (
|
|
"bufio"
|
|
"fmt"
|
|
"net/url"
|
|
"os"
|
|
"strconv"
|
|
"strings"
|
|
)
|
|
|
|
// ReadNodesFile 读取nodes.txt文件并解析所有节点
|
|
func ReadNodesFile(filename string) ([]*Node, error) {
|
|
file, err := os.Open(filename)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
defer file.Close()
|
|
|
|
var nodes []*Node
|
|
nodeSet := make(map[string]bool) // 用于去重
|
|
|
|
scanner := bufio.NewScanner(file)
|
|
for scanner.Scan() {
|
|
line := strings.TrimSpace(scanner.Text())
|
|
if line == "" {
|
|
continue
|
|
}
|
|
|
|
// 检查是否已经存在
|
|
if _, exists := nodeSet[line]; exists {
|
|
continue // 跳过重复的节点
|
|
}
|
|
|
|
node, err := ParseNodeURL(line)
|
|
if err != nil {
|
|
fmt.Printf("解析节点失败: %v\n", err)
|
|
continue // 跳过解析失败的行
|
|
}
|
|
|
|
nodes = append(nodes, node)
|
|
nodeSet[line] = true // 标记为已存在
|
|
}
|
|
|
|
if err := scanner.Err(); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return nodes, nil
|
|
}
|
|
|
|
// ParseNodeURL 解析代理URL字符串为Node结构
|
|
func ParseNodeURL(urlStr string) (*Node, error) {
|
|
u, err := url.Parse(urlStr)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("解析URL失败: %v", err)
|
|
}
|
|
|
|
// 获取用户信息
|
|
username := ""
|
|
password := ""
|
|
if u.User != nil {
|
|
username = u.User.Username()
|
|
if pass, ok := u.User.Password(); ok {
|
|
password = pass
|
|
}
|
|
}
|
|
|
|
// 解析端口
|
|
port := 443 // 默认端口
|
|
if u.Port() != "" {
|
|
port, err = strconv.Atoi(u.Port())
|
|
if err != nil {
|
|
return nil, fmt.Errorf("解析端口失败: %v", err)
|
|
}
|
|
}
|
|
|
|
return &Node{
|
|
Protocol: u.Scheme,
|
|
Username: username,
|
|
Password: password,
|
|
Addr: u.Hostname(),
|
|
Port: port,
|
|
}, nil
|
|
}
|
|
|
|
// SaveAvailableNodes 保存可用的节点到文件
|
|
func SaveAvailableNodes(filename string, nodes []*Node) error {
|
|
file, err := os.Create(filename)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer file.Close()
|
|
|
|
for _, node := range nodes {
|
|
// 重新构建URL格式
|
|
url := fmt.Sprintf("https://%s:%s@%s:%d\n",
|
|
node.Username,
|
|
node.Password,
|
|
node.Addr,
|
|
node.Port)
|
|
if _, err := file.WriteString(url); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
return nil
|
|
} |