Initial commit

This commit is contained in:
2026-06-30 15:14:37 +08:00
commit 15dab96872
311 changed files with 95639 additions and 0 deletions
+93
View File
@@ -0,0 +1,93 @@
package connect
import (
"context"
"fmt"
"net"
"time"
"go.uber.org/zap"
)
// DirectFactory Direct-UDP 直连工厂(Layer 1
type DirectFactory struct {
stunServers []string
logger *zap.Logger
}
// NewDirectFactory 创建 Direct-UDP 工厂
func NewDirectFactory(stunServers []string, logger *zap.Logger) *DirectFactory {
return &DirectFactory{
stunServers: stunServers,
logger: logger,
}
}
// Layer 返回传输层类型
func (f *DirectFactory) Layer() Layer {
return LayerDirectUDP
}
// Name 返回传输方式名称
func (f *DirectFactory) Name() string {
return "Direct-UDP"
}
// Dial 建立 Direct-UDP 直连
func (f *DirectFactory) Dial(ctx context.Context, config *DialConfig) (net.Conn, error) {
f.logger.Info("开始建立 Direct-UDP 直连",
zap.String("peer_id", config.PeerID))
servers := f.stunServers
if len(servers) == 0 {
servers = config.STUNServers
}
if len(servers) == 0 {
f.logger.Warn("未配置 STUN 服务器列表,仅尝试内部 P2P 打洞")
}
var candidates []string
if len(servers) > 0 {
// 1. 创建 STUN 客户端收集候选地址
stun := NewSTUNClient(servers, f.logger)
candidates = stun.CollectCandidates()
}
if len(candidates) == 0 {
f.logger.Warn("未能收集到任何 STUN 候选地址,回退至 PeerID")
// As a fallback, maybe PeerID contains IP:PORT
candidates = append(candidates, config.PeerID)
}
f.logger.Info("STUN 候选地址收集完成",
zap.Strings("candidates", candidates))
// 2. 实际 P2P 连接尝试
f.logger.Warn("当前尝试所有候选地址...")
dialer := &net.Dialer{
Timeout: 5 * time.Second,
}
// 建立 UDP 连接并返回最近可用的
var lastErr error
for _, candidate := range candidates {
if candidate == "" { continue }
conn, err := dialer.DialContext(ctx, "udp", candidate)
if err == nil {
f.logger.Info("Direct-UDP 直连建立成功",
zap.String("peer_id", config.PeerID),
zap.String("remote_addr", conn.RemoteAddr().String()))
return conn, nil
}
f.logger.Warn("候选地址连接失败",
zap.String("candidate", candidate),
zap.Error(err))
lastErr = err
}
return nil, fmt.Errorf("所有候选地址 UDP 连接均失败,最后错误:%w", lastErr)
}