mirror of
https://github.com/MatrixSeven/file-transfer-go.git
synced 2026-03-16 21:37:43 +08:00
feat:桌面共享UI/逻辑优化
This commit is contained in:
@@ -10,6 +10,7 @@ import (
|
||||
|
||||
type Handler struct {
|
||||
webrtcService *services.WebRTCService
|
||||
turnService *services.TurnService
|
||||
}
|
||||
|
||||
func NewHandler() *Handler {
|
||||
@@ -18,6 +19,11 @@ func NewHandler() *Handler {
|
||||
}
|
||||
}
|
||||
|
||||
// SetTurnService 设置TURN服务实例
|
||||
func (h *Handler) SetTurnService(turnService *services.TurnService) {
|
||||
h.turnService = turnService
|
||||
}
|
||||
|
||||
// HandleWebRTCWebSocket 处理WebRTC信令WebSocket连接
|
||||
func (h *Handler) HandleWebRTCWebSocket(w http.ResponseWriter, r *http.Request) {
|
||||
h.webrtcService.HandleWebSocket(w, r)
|
||||
@@ -105,3 +111,101 @@ func (h *Handler) GetRoomStatusHandler(w http.ResponseWriter, r *http.Request) {
|
||||
status := h.webrtcService.GetRoomStatus(code)
|
||||
json.NewEncoder(w).Encode(status)
|
||||
}
|
||||
|
||||
// TurnStatsHandler 获取TURN服务器统计信息API
|
||||
func (h *Handler) TurnStatsHandler(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
|
||||
if r.Method != http.MethodGet {
|
||||
json.NewEncoder(w).Encode(map[string]interface{}{
|
||||
"success": false,
|
||||
"message": "方法不允许",
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
if h.turnService == nil {
|
||||
json.NewEncoder(w).Encode(map[string]interface{}{
|
||||
"success": false,
|
||||
"message": "TURN服务器未启用",
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
stats := h.turnService.GetStats()
|
||||
response := map[string]interface{}{
|
||||
"success": true,
|
||||
"data": stats,
|
||||
}
|
||||
|
||||
json.NewEncoder(w).Encode(response)
|
||||
}
|
||||
|
||||
// TurnConfigHandler 获取TURN服务器配置信息API(用于前端WebRTC配置)
|
||||
func (h *Handler) TurnConfigHandler(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
|
||||
if r.Method != http.MethodGet {
|
||||
json.NewEncoder(w).Encode(map[string]interface{}{
|
||||
"success": false,
|
||||
"message": "方法不允许",
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
if h.turnService == nil || !h.turnService.IsRunning() {
|
||||
json.NewEncoder(w).Encode(map[string]interface{}{
|
||||
"success": false,
|
||||
"message": "TURN服务器未启用或未运行",
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
turnInfo := h.turnService.GetTurnServerInfo()
|
||||
response := map[string]interface{}{
|
||||
"success": true,
|
||||
"data": turnInfo,
|
||||
}
|
||||
|
||||
json.NewEncoder(w).Encode(response)
|
||||
}
|
||||
|
||||
// AdminStatusHandler 获取服务器总体状态API
|
||||
func (h *Handler) AdminStatusHandler(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
|
||||
if r.Method != http.MethodGet {
|
||||
json.NewEncoder(w).Encode(map[string]interface{}{
|
||||
"success": false,
|
||||
"message": "方法不允许",
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
// 获取WebRTC服务状态
|
||||
// 这里简化,实际可以从WebRTC服务获取更多信息
|
||||
webrtcStatus := map[string]interface{}{
|
||||
"isRunning": true, // WebRTC服务总是运行的
|
||||
}
|
||||
|
||||
// 获取TURN服务状态
|
||||
var turnStatus interface{}
|
||||
if h.turnService != nil {
|
||||
turnStatus = h.turnService.GetStats()
|
||||
} else {
|
||||
turnStatus = map[string]interface{}{
|
||||
"isRunning": false,
|
||||
"message": "TURN服务器未启用",
|
||||
}
|
||||
}
|
||||
|
||||
response := map[string]interface{}{
|
||||
"success": true,
|
||||
"data": map[string]interface{}{
|
||||
"webrtc": webrtcStatus,
|
||||
"turn": turnStatus,
|
||||
},
|
||||
}
|
||||
|
||||
json.NewEncoder(w).Encode(response)
|
||||
}
|
||||
|
||||
234
internal/services/turn_service.go
Normal file
234
internal/services/turn_service.go
Normal file
@@ -0,0 +1,234 @@
|
||||
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"`
|
||||
}
|
||||
Reference in New Issue
Block a user