From 26fb5b0a9a73364454c40f9d943cc98eb27cbf3c Mon Sep 17 00:00:00 2001 From: devYuMinKim Date: Wed, 17 Apr 2024 16:16:18 +0900 Subject: [PATCH] =?UTF-8?q?=E2=99=BB=EF=B8=8F=20refactor:=20Refine=20logic?= =?UTF-8?q?=20and=20add=20admin=20checks=20in=20liveClassService?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Refactored the liveClassService to incorporate more robust admin checks and streamline the peer connection setup process for starting and stopping screen shares. This refactor enhances security and improves the reliability of the screen sharing feature by ensuring only authorized users can control the session. Related issue: #80 --- services/live_class_service.go | 95 +++++++++++++++++++++------------- 1 file changed, 59 insertions(+), 36 deletions(-) diff --git a/services/live_class_service.go b/services/live_class_service.go index b56b9ff..81c6102 100644 --- a/services/live_class_service.go +++ b/services/live_class_service.go @@ -2,10 +2,12 @@ package services import ( "fmt" + "github.com/YJU-OKURA/project_minori-gin-deployment-repo/repositories" "github.com/google/uuid" "github.com/gorilla/websocket" "github.com/pion/webrtc/v4" "log" + "strconv" "sync" ) @@ -19,6 +21,8 @@ type Room struct { ID string Members map[*websocket.Conn]bool PeerConnection *webrtc.PeerConnection + IsSharing bool + AdminID string } type RoomMap struct { @@ -35,97 +39,94 @@ func NewRoomMap() *RoomMap { type LiveClassService interface { CreateRoom() (string, error) InsertIntoRoom(roomID string, conn *websocket.Conn) error - StartScreenShare(roomID string) (*webrtc.PeerConnection, error) - StopScreenShare(roomID string) error + StartScreenShare(roomID string, userID string) (*webrtc.PeerConnection, error) + StopScreenShare(roomID string, userID string) error } +// liveClassService implements the LiveClassService interface to manage live classroom sessions. + type liveClassService struct { - roomMap *RoomMap + roomMap *RoomMap + classUserRepo repositories.ClassUserRepository } -func NewLiveClassService(roomMap *RoomMap) LiveClassService { +func NewLiveClassService(roomMap *RoomMap, repo repositories.ClassUserRepository) LiveClassService { return &liveClassService{ - roomMap: roomMap, + roomMap: roomMap, + classUserRepo: repo, } } func (s *liveClassService) CreateRoom() (string, error) { - return s.roomMap.CreateRoom() -} - -func (s *liveClassService) InsertIntoRoom(roomID string, conn *websocket.Conn) error { - return s.roomMap.InsertIntoRoom(roomID, conn) -} - -func (m *RoomMap) CreateRoom() (string, error) { - m.mu.Lock() - defer m.mu.Unlock() + s.roomMap.mu.Lock() + defer s.roomMap.mu.Unlock() roomID := uuid.New().String() - m.rooms[roomID] = &Room{ + s.roomMap.rooms[roomID] = &Room{ ID: roomID, Members: make(map[*websocket.Conn]bool), } log.Printf("Created new room with ID: %s", roomID) return roomID, nil } -func (m *RoomMap) InsertIntoRoom(roomID string, conn *websocket.Conn) error { - m.mu.Lock() - defer m.mu.Unlock() - room, ok := m.rooms[roomID] +func (s *liveClassService) InsertIntoRoom(roomID string, conn *websocket.Conn) error { + s.roomMap.mu.Lock() + defer s.roomMap.mu.Unlock() + + room, ok := s.roomMap.rooms[roomID] if !ok { - log.Printf("Attempted to access non-existing room: %s", roomID) return fmt.Errorf("no room found with ID %s", roomID) } room.Members[conn] = true - log.Printf("Added connection to room: %s", roomID) return nil } -func (s *liveClassService) StartScreenShare(roomID string) (*webrtc.PeerConnection, error) { +func (s *liveClassService) StartScreenShare(roomID string, userID string) (*webrtc.PeerConnection, error) { s.roomMap.mu.Lock() defer s.roomMap.mu.Unlock() room, exists := s.roomMap.rooms[roomID] - if !exists { - log.Printf("Room not found: %s", roomID) - return nil, fmt.Errorf("room not found: %s", roomID) + if !exists || !s.isRoomAdmin(userID, roomID) { + return nil, fmt.Errorf("room %s does not exist", roomID) + } + if !s.isRoomAdmin(userID, roomID) { + return nil, fmt.Errorf("user %s is not an admin of room %s", userID, roomID) + } + if room.IsSharing { + return nil, fmt.Errorf("screen sharing is already in progress in room %s", roomID) } pc, err := webrtc.NewPeerConnection(webrtcConfig) if err != nil { - log.Printf("Failed to create peer connection: %v", err) return nil, fmt.Errorf("failed to create peer connection: %v", err) } videoTrack, err := webrtc.NewTrackLocalStaticRTP(webrtc.RTPCodecCapability{MimeType: "video/vp8"}, "video", "pion") if err != nil { - pc.Close() // Ensure resources are freed on error - log.Printf("Failed to create video track: %v", err) + pc.Close() return nil, fmt.Errorf("failed to create video track: %v", err) } if _, err = pc.AddTrack(videoTrack); err != nil { - pc.Close() // Ensure resources are freed on error - log.Printf("Failed to add track: %v", err) + pc.Close() return nil, fmt.Errorf("failed to add track: %v", err) } room.PeerConnection = pc - log.Printf("Started screen sharing in room ID: %s", roomID) + room.IsSharing = true + log.Printf("Screen sharing started in room %s by user %s", roomID, userID) return pc, nil } -func (s *liveClassService) StopScreenShare(roomID string) error { +func (s *liveClassService) StopScreenShare(roomID string, userID string) error { s.roomMap.mu.Lock() defer s.roomMap.mu.Unlock() room, exists := s.roomMap.rooms[roomID] - if !exists { - log.Printf("Attempt to stop screen sharing in non-existing room: %s", roomID) - return fmt.Errorf("no room found with ID %s", roomID) + if !exists || !s.isRoomAdmin(userID, roomID) { + return fmt.Errorf("room %s does not exist", roomID) } if room.PeerConnection != nil { @@ -137,5 +138,27 @@ func (s *liveClassService) StopScreenShare(roomID string) error { log.Printf("Stopped screen sharing in room ID: %s", roomID) } + room.IsSharing = false return nil } + +func (s *liveClassService) isRoomAdmin(userID string, roomID string) bool { + uid, err := strconv.ParseUint(userID, 10, 32) + if err != nil { + log.Printf("Error converting userID to uint: %v", err) + return false + } + + cid, err := strconv.ParseUint(roomID, 10, 32) + if err != nil { + log.Printf("Error converting roomID to uint: %v", err) + return false + } + + roleID, err := s.classUserRepo.GetRole(uint(uid), uint(cid)) + if err != nil { + log.Printf("Error checking admin status: %v", err) + return false + } + return roleID == 2 +}