Initial commit
This commit is contained in:
@@ -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)
|
||||
}
|
||||
Reference in New Issue
Block a user