Skip to content

Commit

Permalink
♻️ refactor: Refine logic and add admin checks in liveClassService
Browse files Browse the repository at this point in the history
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: YJU-OKURA#80
  • Loading branch information
yuminn-k committed Apr 17, 2024
1 parent 0c640f1 commit 26fb5b0
Showing 1 changed file with 59 additions and 36 deletions.
95 changes: 59 additions & 36 deletions services/live_class_service.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
)

Expand All @@ -19,6 +21,8 @@ type Room struct {
ID string
Members map[*websocket.Conn]bool
PeerConnection *webrtc.PeerConnection
IsSharing bool
AdminID string
}

type RoomMap struct {
Expand All @@ -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 {
Expand All @@ -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
}

0 comments on commit 26fb5b0

Please sign in to comment.