mirror of
https://github.com/MatrixSeven/file-transfer-go.git
synced 2026-02-04 03:25:03 +08:00
234 lines
6.0 KiB
Go
234 lines
6.0 KiB
Go
package services
|
||
|
||
import (
|
||
"fmt"
|
||
"log"
|
||
"net"
|
||
"sync"
|
||
|
||
"github.com/pion/turn/v3"
|
||
)
|
||
|
||
// TurnService TURN服务器结构
|
||
type TurnService struct {
|
||
server *turn.Server
|
||
config TurnServiceConfig
|
||
stats *TurnStats
|
||
isRunning bool
|
||
mu sync.RWMutex
|
||
}
|
||
|
||
// TurnServiceConfig TURN服务器配置
|
||
type TurnServiceConfig struct {
|
||
Port int
|
||
Username string
|
||
Password string
|
||
Realm string
|
||
}
|
||
|
||
// TurnStats TURN服务器统计信息
|
||
type TurnStats struct {
|
||
ActiveAllocations int64
|
||
TotalAllocations int64
|
||
BytesTransferred int64
|
||
PacketsTransferred int64
|
||
Connections int64
|
||
mu sync.RWMutex
|
||
}
|
||
|
||
// NewTurnService 创建新的TURN服务实例
|
||
func NewTurnService(config TurnServiceConfig) *TurnService {
|
||
return &TurnService{
|
||
config: config,
|
||
stats: &TurnStats{},
|
||
}
|
||
}
|
||
|
||
// Start 启动TURN服务器
|
||
func (ts *TurnService) Start() error {
|
||
ts.mu.Lock()
|
||
defer ts.mu.Unlock()
|
||
|
||
if ts.isRunning {
|
||
return fmt.Errorf("TURN服务器已在运行")
|
||
}
|
||
|
||
// 监听UDP端口
|
||
udpListener, err := net.ListenPacket("udp4", fmt.Sprintf("0.0.0.0:%d", ts.config.Port))
|
||
if err != nil {
|
||
return fmt.Errorf("无法监听UDP端口: %v", err)
|
||
}
|
||
|
||
// 监听TCP端口
|
||
tcpListener, err := net.Listen("tcp4", fmt.Sprintf("0.0.0.0:%d", ts.config.Port))
|
||
if err != nil {
|
||
udpListener.Close()
|
||
return fmt.Errorf("无法监听TCP端口: %v", err)
|
||
}
|
||
|
||
// 创建TURN服务器配置
|
||
turnConfig := turn.ServerConfig{
|
||
Realm: ts.config.Realm,
|
||
AuthHandler: ts.authHandler,
|
||
PacketConnConfigs: []turn.PacketConnConfig{
|
||
{
|
||
PacketConn: udpListener,
|
||
RelayAddressGenerator: &turn.RelayAddressGeneratorStatic{
|
||
RelayAddress: net.ParseIP("127.0.0.1"), // 在生产环境中应该使用公网IP
|
||
Address: "0.0.0.0",
|
||
},
|
||
},
|
||
},
|
||
ListenerConfigs: []turn.ListenerConfig{
|
||
{
|
||
Listener: tcpListener,
|
||
RelayAddressGenerator: &turn.RelayAddressGeneratorStatic{
|
||
RelayAddress: net.ParseIP("127.0.0.1"), // 在生产环境中应该使用公网IP
|
||
Address: "0.0.0.0",
|
||
},
|
||
},
|
||
},
|
||
}
|
||
|
||
// 创建TURN服务器
|
||
server, err := turn.NewServer(turnConfig)
|
||
if err != nil {
|
||
udpListener.Close()
|
||
tcpListener.Close()
|
||
return fmt.Errorf("创建TURN服务器失败: %v", err)
|
||
}
|
||
|
||
ts.server = server
|
||
ts.isRunning = true
|
||
|
||
log.Printf("🔄 TURN服务器启动成功,监听端口: %d", ts.config.Port)
|
||
log.Printf(" 用户名: %s, 域: %s", ts.config.Username, ts.config.Realm)
|
||
|
||
return nil
|
||
}
|
||
|
||
// Stop 停止TURN服务器
|
||
func (ts *TurnService) Stop() error {
|
||
ts.mu.Lock()
|
||
defer ts.mu.Unlock()
|
||
|
||
if !ts.isRunning {
|
||
return fmt.Errorf("TURN服务器未运行")
|
||
}
|
||
|
||
if ts.server != nil {
|
||
if err := ts.server.Close(); err != nil {
|
||
return fmt.Errorf("关闭TURN服务器失败: %v", err)
|
||
}
|
||
}
|
||
|
||
ts.isRunning = false
|
||
log.Printf("🛑 TURN服务器已停止")
|
||
|
||
return nil
|
||
}
|
||
|
||
// IsRunning 检查TURN服务器是否正在运行
|
||
func (ts *TurnService) IsRunning() bool {
|
||
ts.mu.RLock()
|
||
defer ts.mu.RUnlock()
|
||
return ts.isRunning
|
||
}
|
||
|
||
// authHandler 认证处理器
|
||
func (ts *TurnService) authHandler(username string, realm string, srcAddr net.Addr) ([]byte, bool) {
|
||
// 记录连接统计
|
||
ts.stats.mu.Lock()
|
||
ts.stats.Connections++
|
||
ts.stats.mu.Unlock()
|
||
|
||
log.Printf("🔐 TURN认证请求: 用户=%s, 域=%s, 地址=%s", username, realm, srcAddr.String())
|
||
|
||
// 简单的用户名密码验证
|
||
if username == ts.config.Username && realm == ts.config.Realm {
|
||
// 记录分配统计
|
||
ts.stats.mu.Lock()
|
||
ts.stats.ActiveAllocations++
|
||
ts.stats.TotalAllocations++
|
||
ts.stats.mu.Unlock()
|
||
|
||
log.Printf("📊 TURN认证成功: 活跃分配=%d, 总分配=%d", ts.stats.ActiveAllocations, ts.stats.TotalAllocations)
|
||
|
||
// 返回密码的key
|
||
return turn.GenerateAuthKey(username, ts.config.Realm, ts.config.Password), true
|
||
}
|
||
|
||
log.Printf("❌ TURN认证失败: 用户=%s", username)
|
||
return nil, false
|
||
}
|
||
|
||
// GetStats 获取统计信息
|
||
func (ts *TurnService) GetStats() TurnStatsResponse {
|
||
ts.stats.mu.RLock()
|
||
defer ts.stats.mu.RUnlock()
|
||
|
||
return TurnStatsResponse{
|
||
IsRunning: ts.IsRunning(),
|
||
ActiveAllocations: ts.stats.ActiveAllocations,
|
||
TotalAllocations: ts.stats.TotalAllocations,
|
||
BytesTransferred: ts.stats.BytesTransferred,
|
||
PacketsTransferred: ts.stats.PacketsTransferred,
|
||
Connections: ts.stats.Connections,
|
||
Port: ts.config.Port,
|
||
Username: ts.config.Username,
|
||
Realm: ts.config.Realm,
|
||
}
|
||
}
|
||
|
||
// GetTurnServerInfo 获取TURN服务器信息用于客户端
|
||
func (ts *TurnService) GetTurnServerInfo() TurnServerInfo {
|
||
if !ts.IsRunning() {
|
||
return TurnServerInfo{}
|
||
}
|
||
|
||
return TurnServerInfo{
|
||
URLs: []string{fmt.Sprintf("turn:localhost:%d", ts.config.Port)},
|
||
Username: ts.config.Username,
|
||
Credential: ts.config.Password,
|
||
}
|
||
}
|
||
|
||
// UpdateStats 更新传输统计 (可以从外部调用)
|
||
func (ts *TurnService) UpdateStats(bytes, packets int64) {
|
||
ts.stats.mu.Lock()
|
||
defer ts.stats.mu.Unlock()
|
||
|
||
ts.stats.BytesTransferred += bytes
|
||
ts.stats.PacketsTransferred += packets
|
||
}
|
||
|
||
// DecrementActiveAllocations 减少活跃分配数(当连接关闭时调用)
|
||
func (ts *TurnService) DecrementActiveAllocations() {
|
||
ts.stats.mu.Lock()
|
||
defer ts.stats.mu.Unlock()
|
||
|
||
if ts.stats.ActiveAllocations > 0 {
|
||
ts.stats.ActiveAllocations--
|
||
log.Printf("📊 TURN分配释放: 活跃分配=%d", ts.stats.ActiveAllocations)
|
||
}
|
||
}
|
||
|
||
// TurnStatsResponse TURN统计响应结构
|
||
type TurnStatsResponse struct {
|
||
IsRunning bool `json:"isRunning"`
|
||
ActiveAllocations int64 `json:"activeAllocations"`
|
||
TotalAllocations int64 `json:"totalAllocations"`
|
||
BytesTransferred int64 `json:"bytesTransferred"`
|
||
PacketsTransferred int64 `json:"packetsTransferred"`
|
||
Connections int64 `json:"connections"`
|
||
Port int `json:"port"`
|
||
Username string `json:"username"`
|
||
Realm string `json:"realm"`
|
||
}
|
||
|
||
// TurnServerInfo TURN服务器信息结构 (用于WebRTC配置)
|
||
type TurnServerInfo struct {
|
||
URLs []string `json:"urls"`
|
||
Username string `json:"username"`
|
||
Credential string `json:"credential"`
|
||
} |