fscan/Common/proxy/Factory.go
ZacharyZcR 879293e680 refactor: 重构代理系统为模块化架构
将Proxy.go的代理连接逻辑重构为完整的模块化系统,
提供更好的性能、可维护性和功能扩展。

主要变更:
- Proxy.go: 从192行单体实现重构为简洁包装层
- 新增proxy模块包含5个核心文件:Types.go、Manager.go等
- 支持多种代理类型:HTTP、HTTPS、SOCKS5、直连
- 实现连接池、缓存机制和智能资源管理
- 添加详细的连接统计和性能监控
- 提供线程安全的配置管理和动态更新
- 完全保持API向后兼容性,无需修改调用代码

新增功能:
- HTTP/HTTPS代理支持(原来仅支持SOCKS5)
- 连接跟踪和统计分析
- 错误分类和详细上下文信息
- 配置验证和URL解析
- 全局代理管理实例

测试验证:
- 编译无错误 ✓
- 基础连接功能正常 ✓
- 向后兼容性验证通过 ✓
2025-08-05 03:36:53 +08:00

186 lines
4.2 KiB
Go

package proxy
import (
"fmt"
"net/url"
"strconv"
"strings"
"time"
)
// ParseProxyURL 解析代理URL
func ParseProxyURL(proxyURL string) (*ProxyConfig, error) {
if proxyURL == "" {
return DefaultProxyConfig(), nil
}
u, err := url.Parse(proxyURL)
if err != nil {
return nil, NewProxyError(ErrTypeConfig, "代理URL解析失败", 6001, err)
}
config := DefaultProxyConfig()
// 设置代理类型
switch strings.ToLower(u.Scheme) {
case "http":
config.Type = ProxyTypeHTTP
case "https":
config.Type = ProxyTypeHTTPS
case "socks5":
config.Type = ProxyTypeSOCKS5
default:
return nil, NewProxyError(ErrTypeConfig,
fmt.Sprintf("不支持的代理协议: %s", u.Scheme), 6002, nil)
}
// 设置地址
config.Address = u.Host
// 设置认证信息
if u.User != nil {
config.Username = u.User.Username()
config.Password, _ = u.User.Password()
}
// 解析查询参数中的配置
query := u.Query()
// 超时设置
if timeout := query.Get("timeout"); timeout != "" {
if t, err := time.ParseDuration(timeout); err == nil {
config.Timeout = t
}
}
// 最大重试次数
if retries := query.Get("retries"); retries != "" {
if r, err := strconv.Atoi(retries); err == nil {
config.MaxRetries = r
}
}
// 保活时间
if keepalive := query.Get("keepalive"); keepalive != "" {
if ka, err := time.ParseDuration(keepalive); err == nil {
config.KeepAlive = ka
}
}
return config, nil
}
// CreateProxyManager 创建代理管理器
func CreateProxyManager(proxyURL string) (ProxyManager, error) {
config, err := ParseProxyURL(proxyURL)
if err != nil {
return nil, err
}
return NewProxyManager(config), nil
}
// ValidateProxyConfig 验证代理配置
func ValidateProxyConfig(config *ProxyConfig) error {
if config == nil {
return NewProxyError(ErrTypeConfig, "配置不能为空", 6003, nil)
}
// 验证代理类型
if config.Type < ProxyTypeNone || config.Type > ProxyTypeSOCKS5 {
return NewProxyError(ErrTypeConfig, "无效的代理类型", 6004, nil)
}
// 如果不是直连,必须有地址
if config.Type != ProxyTypeNone && config.Address == "" {
return NewProxyError(ErrTypeConfig, "代理地址不能为空", 6005, nil)
}
// 验证超时时间
if config.Timeout <= 0 {
return NewProxyError(ErrTypeConfig, "超时时间必须大于0", 6006, nil)
}
// 验证重试次数
if config.MaxRetries < 0 {
return NewProxyError(ErrTypeConfig, "最大重试次数不能为负数", 6007, nil)
}
// 验证连接池配置
if config.MaxIdleConns < 0 {
return NewProxyError(ErrTypeConfig, "最大空闲连接数不能为负数", 6008, nil)
}
return nil
}
// GetProxyTypeFromString 从字符串获取代理类型
func GetProxyTypeFromString(typeStr string) ProxyType {
switch strings.ToLower(typeStr) {
case "none", "direct":
return ProxyTypeNone
case "http":
return ProxyTypeHTTP
case "https":
return ProxyTypeHTTPS
case "socks5":
return ProxyTypeSOCKS5
default:
return ProxyTypeNone
}
}
// BuildProxyURL 构建代理URL
func BuildProxyURL(config *ProxyConfig) string {
if config == nil || config.Type == ProxyTypeNone {
return ""
}
var scheme string
switch config.Type {
case ProxyTypeHTTP:
scheme = "http"
case ProxyTypeHTTPS:
scheme = "https"
case ProxyTypeSOCKS5:
scheme = "socks5"
default:
return ""
}
url := fmt.Sprintf("%s://", scheme)
if config.Username != "" {
if config.Password != "" {
url += fmt.Sprintf("%s:%s@", config.Username, config.Password)
} else {
url += fmt.Sprintf("%s@", config.Username)
}
}
url += config.Address
return url
}
// IsProxyEnabled 检查是否启用了代理
func IsProxyEnabled(config *ProxyConfig) bool {
return config != nil && config.Type != ProxyTypeNone && config.Address != ""
}
// GetDefaultProxyConfigForType 获取指定类型的默认配置
func GetDefaultProxyConfigForType(proxyType ProxyType, address string) *ProxyConfig {
config := DefaultProxyConfig()
config.Type = proxyType
config.Address = address
// 根据类型调整默认配置
switch proxyType {
case ProxyTypeHTTP, ProxyTypeHTTPS:
config.Timeout = 15 * time.Second
case ProxyTypeSOCKS5:
config.Timeout = 30 * time.Second
}
return config
}