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
+333
View File
@@ -0,0 +1,333 @@
package core
import (
"context"
"fmt"
"net"
"time"
"git.zkcoi.com/zkcoi/meshray/core/connect"
"git.zkcoi.com/zkcoi/meshray/core/plugins/wg"
"git.zkcoi.com/zkcoi/meshray/core/transport"
"go.uber.org/zap"
)
// Engine 引擎实例 - 一个组网的引擎实例
type Engine struct {
logger *zap.Logger
scheduler *connect.StrategyScheduler
connMgr *transport.ConnManager
relay *transport.Relay
plugin transport.ProtocolPlugin
metrics *Metrics
// 候选地址存储(用于 NotifyPeerInfo
candidateStore map[string][]Candidate
routeIDStore map[string]uint32
}
// NewEngine 创建引擎实例
func NewEngine(logger *zap.Logger, metrics *Metrics) *Engine {
// 创建 WG 插件
plugin := wg.NewWGPlugin()
// 创建连接管理器
connMgr := transport.NewConnManager(logger)
// 创建数据转发器
relay := transport.NewRelay(plugin, connMgr, logger)
// 创建策略调度器
scheduler := connect.NewStrategyScheduler(logger)
scheduler.OnConnectionUpdate = func(peerID string, conn net.Conn, err error) {
if err != nil {
logger.Warn("收到策略调度器连接错误更新", zap.String("peer_id", peerID), zap.Error(err))
}
if conn != nil {
logger.Info("策略调度器连接已建立,开始双向转发", zap.String("peer_id", peerID))
connMgr.Add(peerID, conn)
// 启动远端接收协程
relay.StartReadFromRemoteConn(context.Background(), peerID, conn)
}
}
scheduler.RegisterFactory(connect.NewDirectFactory(nil, logger)) // 1. Direct-UDP
scheduler.RegisterFactory(connect.NewFakeTCPFactory(logger)) // 2. FakeTCP
scheduler.RegisterFactory(connect.NewRealTCPFactory(logger)) // 3. RealTCP
scheduler.RegisterFactory(connect.NewTURNFactory(connect.TURNProtocolUDP, nil, "", "", logger)) // 4. TURN-UDP
// scheduler.RegisterFactory(connect.NewTURNFactoryQUIC(nil, "", "", logger)) // 5. TURN-QUIC (暂不启用)
scheduler.RegisterFactory(connect.NewTURNFactory(connect.TURNProtocolTCP, nil, "", "", logger)) // 6. TURN-TCP
scheduler.RegisterFactory(connect.NewTURNFactory(connect.TURNProtocolTLS, nil, "", "", logger)) // 7. TURN-TLS
scheduler.RegisterFactory(connect.NewWebRTCFactory(&connect.ICEConfig{}, logger)) // 8. WebRTC
scheduler.RegisterFactory(connect.NewWSFactory(nil, logger)) // 9. WS/WSS
engine := &Engine{
logger: logger,
scheduler: scheduler,
connMgr: connMgr,
relay: relay,
plugin: plugin,
metrics: metrics,
candidateStore: make(map[string][]Candidate),
routeIDStore: make(map[string]uint32),
}
// 设置拨号触发器:当 WG 发包但没连接时自动 9 层拨号
relay.OnDialTrigger = func(peerKey string) {
go engine.initiateConnection(peerKey)
}
return engine
}
// Start 启动引擎
func (e *Engine) Start() error {
e.logger.Info("Core 引擎启动")
return nil
}
// Stop 停止引擎
func (e *Engine) Stop() error {
e.logger.Info("Core 引擎停止")
// 关闭所有连接
if e.connMgr != nil {
e.connMgr.CloseAll()
}
return nil
}
// SetICEConfig 设置 ICE 配置(用于 WebRTC
func (e *Engine) SetICEConfig(config connect.ICEConfig) error {
e.logger.Info("更新 ICE 配置",
zap.Int("stun_servers", len(config.STUNServers)),
zap.Int("turn_servers", len(config.TURNServers)))
// TODO: 实现 ICE 配置更新逻辑
// 1. 找到 WebRTC 工厂
// 2. 更新其 ICE 配置
// 3. 重新注册工厂
// 目前先记录日志,P3 阶段实现
e.logger.Warn("SetICEConfig 暂未实现,将在 P3 阶段完成")
return nil
}
// GetScheduler 获取策略调度器
func (e *Engine) GetScheduler() *connect.StrategyScheduler {
return e.scheduler
}
// GetConnMgr 获取连接管理器
func (e *Engine) GetConnMgr() *transport.ConnManager {
return e.connMgr
}
// GetRelay 获取数据转发器
func (e *Engine) GetRelay() *transport.Relay {
return e.relay
}
// GetMetrics 获取监控指标
func (e *Engine) GetMetrics() *Metrics {
return e.metrics
}
// Bind 为指定 Peer 开启本地端口,开始建连
// peerKey: 对端公钥哈希(8 字符)
// localPort: 本地监听端口(传 0 表示系统自动分配)
// 返回值:实际绑定的端口号
func (e *Engine) Bind(peerKey string, localPort int) (int, error) {
// 1. 在本地端口监听
addr := &net.UDPAddr{IP: net.IPv4(127, 0, 0, 1), Port: localPort}
conn, err := net.ListenUDP("udp", addr)
if err != nil {
return 0, fmt.Errorf("监听本地端口失败:%w", err)
}
actualPort := conn.LocalAddr().(*net.UDPAddr).Port
// 2. 提取 route_id(从 peerKey 派生)
routeID := extractRouteID(peerKey)
// 3. 注册到 Relay
e.relay.RegisterLocalPort(routeID, conn)
// 4. 注册到 ConnManager
e.connMgr.Add(peerKey, nil) // conn 初始为 nil,建连后设置
// 5. 启动读取协程
ctx := context.Background()
e.relay.StartReadFromLocalPort(ctx, routeID, peerKey)
e.logger.Info("Bind 成功",
zap.String("peer_key", peerKey),
zap.Int("local_port", actualPort),
zap.Uint32("route_id", routeID))
return actualPort, nil
}
// Unbind 停止指定 Peer 的端口监听
func (e *Engine) Unbind(peerKey string) error {
// 1. 提取 route_id
routeID := extractRouteID(peerKey)
// 2. 从 Relay 注销
e.relay.UnregisterLocalPort(routeID)
// 3. 从 ConnManager 移除
e.connMgr.Remove(peerKey)
// 4. 清理存储
delete(e.candidateStore, peerKey)
delete(e.routeIDStore, peerKey)
e.logger.Info("Unbind 成功",
zap.String("peer_key", peerKey),
zap.Uint32("route_id", routeID))
return nil
}
// EngineStatus Engine 状态
type EngineStatus struct {
PeerCount int `json:"peer_count"`
Peers map[string]*PeerStatus `json:"peers"`
// Metrics
ActiveConnections int64 `json:"active_connections"`
TotalConnections int64 `json:"total_connections"`
BytesSent uint64 `json:"bytes_sent"`
BytesReceived uint64 `json:"bytes_received"`
StrategyFallbacks int64 `json:"strategy_fallbacks"`
LastSwitchTime int64 `json:"last_switch_time"` // unix timestamp
}
// PeerStatus Peer 状态
type PeerStatus struct {
PeerKey string `json:"peer_key"`
Connected bool `json:"connected"`
Layer string `json:"layer,omitempty"` // 当前传输层
}
// GetStatus 查询 Engine 状态
func (e *Engine) GetStatus() (*EngineStatus, error) {
status := &EngineStatus{
PeerCount: e.connMgr.Count(),
Peers: make(map[string]*PeerStatus),
}
// 收集 Metrics
if e.metrics != nil {
status.ActiveConnections = e.metrics.GetActiveConnections()
status.TotalConnections = e.metrics.GetTotalConnections()
status.BytesSent = e.metrics.GetBytesSent()
status.BytesReceived = e.metrics.GetBytesReceived()
status.StrategyFallbacks = e.metrics.GetStrategyFallbacks()
status.LastSwitchTime = e.metrics.GetLastSwitchTime().Unix()
}
// 收集所有 Peer 状态
for peerKey, conn := range e.connMgr.GetAll() {
peerStatus := &PeerStatus{
PeerKey: peerKey,
Connected: conn != nil,
}
if conn != nil {
peerStatus.Layer = e.scheduler.GetPeerLayer(peerKey).String()
}
status.Peers[peerKey] = peerStatus
}
return status, nil
}
// Candidate 候选地址(与 connect.Candidate 对齐)
type Candidate struct {
Addr string `json:"addr"` // 候选地址(ip:port
Type string `json:"type"` // 候选类型:host/srflx/relay
Priority int `json:"priority"` // 优先级
Protocol string `json:"protocol"` // 协议:udp/tcp
}
// NotifyPeerInfo 下发对端候选地址和 route_id
// peerKey: 对端公钥哈希
// candidates: 对端候选地址列表(由信使服务器转发)
// routeID: 路由 ID(用于数据转发)
func (e *Engine) NotifyPeerInfo(peerKey string, candidates []Candidate, routeID uint32) error {
// 1. 存储候选地址(用于后续建连)
e.candidateStore[peerKey] = candidates
// 2. 存储 route_id 映射
e.routeIDStore[peerKey] = routeID
// 3. 触发建连流程
go e.initiateConnection(peerKey)
e.logger.Info("NotifyPeerInfo 成功",
zap.String("peer_key", peerKey),
zap.Int("candidate_count", len(candidates)),
zap.Uint32("route_id", routeID))
return nil
}
// initiateConnection 触发建连流程
func (e *Engine) initiateConnection(peerKey string) {
// 1. 获取候选地址
candidates := e.candidateStore[peerKey]
if len(candidates) == 0 {
return
}
// 2. 检查是否已经在拨号或已连接
if conn, ok := e.connMgr.Get(peerKey); ok && conn != nil {
return
}
// 2. 初始化 DialConfig
config := &connect.DialConfig{
PeerID: peerKey,
Timeout: 10 * time.Second,
Logger: e.logger,
}
e.logger.Info("开始建立连接到对端",
zap.String("peer_key", peerKey),
zap.Int("candidate_count", len(candidates)))
// 3. 获取 RouteID
_, ok := e.routeIDStore[peerKey]
if !ok {
e.logger.Warn("未找到 route_id",
zap.String("peer_key", peerKey))
return
}
// 4. 使用策略调度器尝试建连
conn, err := e.scheduler.Dial(config)
if err != nil {
e.logger.Error("所有策略层尝试连接均失败",
zap.String("peer_key", peerKey),
zap.Error(err))
return
}
// 5. 连接成功,更新到 ConnManager
e.connMgr.Add(peerKey, conn)
e.logger.Info("连接建立并更新成功", zap.String("peer_key", peerKey))
}
// extractRouteID 从 peerKey 提取 route_id(简化版本)
// 实际应该使用一致的哈希算法
func extractRouteID(peerKey string) uint32 {
// 简单哈希:取前 4 个字符的 ASCII 码和
var sum uint32 = 0
for i := 0; i < len(peerKey) && i < 4; i++ {
sum += uint32(peerKey[i])
}
return sum
}