From 9a33235c7e7f7a1703d28e77a240b3fe05f9d6b7 Mon Sep 17 00:00:00 2001 From: set Date: Thu, 2 Apr 2026 18:02:41 +0200 Subject: [PATCH] =?UTF-8?q?=D0=90=D0=B2=D1=82=D0=BE=D0=BC=D0=B0=D1=82?= =?UTF-8?q?=D0=B8=D1=87=D0=B5=D1=81=D0=BA=D0=BE=D0=B5=20=D1=83=D0=B4=D0=B0?= =?UTF-8?q?=D0=BB=D0=B5=D0=BD=D0=B8=D0=B5=20=D0=BA=D0=BE=D0=BC=D0=BD=D0=B0?= =?UTF-8?q?=D1=82=20=D0=BF=D1=80=D0=B8=20=D0=BD=D0=B5=D0=B0=D0=BA=D1=82?= =?UTF-8?q?=D0=B8=D0=B2=D0=BD=D0=BE=D1=81=D1=82=D0=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .env | 4 ++-- sfu/rooms.go | 57 ++++++++++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 57 insertions(+), 4 deletions(-) diff --git a/.env b/.env index 39e7a54..b5f3644 100644 --- a/.env +++ b/.env @@ -9,7 +9,7 @@ PORT=1001 # SFU SECTION # ############### #Публичный IP адрес, который будет использоваться для ICE кандидатов (если SFU работает за NAT) -SFU_PUBLIC_IP=192.168.6.82 +SFU_PUBLIC_IP=10.211.55.2 #Диапазон портов для ICE кандидатов SFU_PORT_RANGE_FROM=30000 SFU_PORT_RANGE_TO=39999 @@ -19,7 +19,7 @@ SFU_PORT_RANGE_TO=39999 #Разрешить использовать этот SFU как TURN сервер тоже (для ретрансляции медиа трафика на сам SFU) TURN_ALLOW=true #TURN имя пользователя и пароль для аутентификации на TURN сервере (если используется) -TURN_PUBLIC_IP=192.168.6.82 +TURN_PUBLIC_IP=10.211.55.2 TURN_USER=user TURN_PASS=pass #Диапазон занимемых TURN сервером портов (tcp/udp) diff --git a/sfu/rooms.go b/sfu/rooms.go index 06bfa8e..1e44569 100644 --- a/sfu/rooms.go +++ b/sfu/rooms.go @@ -4,6 +4,7 @@ import ( "g365sfu/logger" connection "g365sfu/socket/struct" "sync" + "time" "github.com/pion/webrtc/v4" ) @@ -34,6 +35,8 @@ type Room struct { Tracks []RoomTrack mu sync.RWMutex + + emptyTimer *time.Timer } // Общие переменные @@ -42,6 +45,46 @@ var ( roomsMu sync.RWMutex ) +const emptyRoomTTL = 30 * time.Second + +func scheduleEmptyRoomDeletion(room *Room) { + room.mu.Lock() + if len(room.Peers) > 0 { + if room.emptyTimer != nil { + room.emptyTimer.Stop() + room.emptyTimer = nil + } + room.mu.Unlock() + return + } + if room.emptyTimer != nil { + room.mu.Unlock() + return + } + roomID := room.RoomID + var timer *time.Timer + timer = time.AfterFunc(emptyRoomTTL, func() { + currentRoom, exists := GetRoom(roomID) + if !exists { + return + } + + currentRoom.mu.Lock() + if currentRoom.emptyTimer != timer || len(currentRoom.Peers) > 0 { + currentRoom.mu.Unlock() + return + } + currentRoom.emptyTimer = nil + currentRoom.mu.Unlock() + + if err := DeleteRoom(roomID); err != nil && err != ErrRoomNotFound { + logger.LogWarnMessage("scheduleEmptyRoomDeletion: failed to delete room " + roomID + ": " + err.Error()) + } + }) + room.emptyTimer = timer + room.mu.Unlock() +} + // CreateRoom создает комнату func CreateRoom(server *connection.Connection, roomID string) (*Room, error) { roomsMu.Lock() @@ -53,6 +96,7 @@ func CreateRoom(server *connection.Connection, roomID string) (*Room, error) { Peers: []Peer{}, } rooms[roomID] = room + scheduleEmptyRoomDeletion(room) return room, nil } @@ -110,6 +154,10 @@ func JoinWithOffer(roomID string, peerID string, offer webrtc.SessionDescription // Добавляем peer в комнату и сразу снимаем snapshot существующих треков // в одном локе — чтобы не было race с OnTrack room.mu.Lock() + if room.emptyTimer != nil { + room.emptyTimer.Stop() + room.emptyTimer = nil + } room.Peers = append(room.Peers, Peer{ PeerID: peerID, PeerConnection: peerConnection, @@ -164,6 +212,10 @@ func DeleteRoom(roomID string) error { roomsMu.Unlock() room.mu.Lock() + if room.emptyTimer != nil { + room.emptyTimer.Stop() + room.emptyTimer = nil + } peers := make([]Peer, len(room.Peers)) copy(peers, room.Peers) room.Peers = nil @@ -227,9 +279,10 @@ func LeaveRoom(roomID string, peerID string) error { } cleanupForwardingState(roomID, peerID) - // Комната пустая -> удаляем + // Комната пустая -> планируем удаление через TTL if shouldDrop { - return DeleteRoom(roomID) + scheduleEmptyRoomDeletion(room) + return nil } // renegotiation оставшимся peer после удаления треков/peer