diff --git a/handler/browser.go b/handler/browser.go index 6c174f5f..cd57bbd9 100644 --- a/handler/browser.go +++ b/handler/browser.go @@ -46,6 +46,9 @@ func (s *Session) RouteBrowser() { req.Data = "ok" if s.RoomID != "" { room := s.handler.getRoom(s.RoomID) + if room == nil { + return + } err := room.SaveGame() if err != nil { log.Println("[!] Cannot save game state: ", err) @@ -95,17 +98,27 @@ func (s *Session) RouteBrowser() { } } - // Create new room + // Get Room in local server // TODO: check if roomID is in the current server room := s.handler.getRoom(s.RoomID) log.Println("Got Room from local ", room, " ID: ", s.RoomID) + // If room is not running if room == nil { + // Create new room room = s.handler.createNewRoom(s.GameName, s.RoomID, s.PlayerIndex) + // Wait for done signal from room + go func() { + <-room.Done + s.handler.detachRoom(room.ID) + }() } - // Attach peerconnection to room - s.handler.detachPeerConn(s.peerconnection) - room.AddConnectionToRoom(s.peerconnection, s.PlayerIndex) + // Attach peerconnection to room. If PC is already in room, don't detach + log.Println("Is PC in room", room.IsPCInRoom(s.peerconnection)) + if !room.IsPCInRoom(s.peerconnection) { + s.handler.detachPeerConn(s.peerconnection) + room.AddConnectionToRoom(s.peerconnection, s.PlayerIndex) + } s.RoomID = room.ID // Register room to overlord if we are connecting to overlord diff --git a/handler/handlers.go b/handler/handlers.go index fd54d663..9f9a3102 100644 --- a/handler/handlers.go +++ b/handler/handlers.go @@ -112,18 +112,14 @@ func (h *Handler) WS(w http.ResponseWriter, r *http.Request) { Data: gamelist.GetEncodedGameList(h.gamePath), }, nil) - wssession.BrowserClient.Listen() - - // TODO: Use callback // If peerconnection is done (client.Done is signalled), we close peerconnection go func() { - for { - <-client.Done - h.detachPeerConn(wssession.peerconnection) - return - } + <-client.Done + log.Println("Socket terminated, detach connection") + h.detachPeerConn(wssession.peerconnection) }() + wssession.BrowserClient.Listen() } // Detach peerconnection detach/remove a peerconnection from current room @@ -147,6 +143,11 @@ func (h *Handler) getRoom(roomID string) *room.Room { return room } +// detachRoom detach room from Handler +func (h *Handler) detachRoom(roomID string) { + delete(h.rooms, roomID) +} + // createNewRoom creates a new room // Return nil in case of room is existed func (h *Handler) createNewRoom(gameName string, roomID string, playerIndex int) *room.Room { @@ -172,5 +173,5 @@ func (h *Handler) isRoomRunning(roomID string) bool { return false } - return room.IsRunning() + return room.IsRunningSessions() } diff --git a/handler/room/media.go b/handler/room/media.go index 0bf6d7c6..24fe7083 100644 --- a/handler/room/media.go +++ b/handler/room/media.go @@ -33,7 +33,7 @@ func (r *Room) startAudio() { log.Println("Warn: Room ", r.ID, " audio channel closed unexpectedly") return } - if r.Done { + if !r.IsRunning { log.Println("Room ", r.ID, " audio channel closed") return } @@ -88,7 +88,7 @@ func (r *Room) startVideo() { log.Println("Warn: Room ", r.ID, " video channel closed unexpectedly") return } - if r.Done { + if !r.IsRunning { log.Println("Room ", r.ID, " video channel closed") return } diff --git a/handler/room/room.go b/handler/room/room.go index a5b6f5f0..eedd8587 100644 --- a/handler/room/room.go +++ b/handler/room/room.go @@ -1,7 +1,6 @@ package room import ( - "fmt" "image" "io/ioutil" "log" @@ -20,17 +19,22 @@ import ( type Room struct { ID string + // imageChannel is image stream from director imageChannel chan *image.RGBA + // audioChannel is audio stream from director audioChannel chan float32 + // inputChannel is input stream from websocket to room inputChannel chan int - // Done channel is to fire exit event when there is no webRTC session running - Done bool - - rtcSessions []*webrtc.WebRTC + // State of room + IsRunning bool + // Done channel is to fire exit event when room is closed + Done chan struct{} + // List of peerconnections in the room + rtcSessions []*webrtc.WebRTC + // NOTE: Not in use, lock rtcSessions sessionsLock *sync.Mutex - + // Director is emulator director *emulator.Director - // Cloud storage to store room state online onlineStorage *storage.Client } @@ -58,8 +62,10 @@ func NewRoom(roomID, gamepath, gameName string, onlineStorage *storage.Client) * rtcSessions: []*webrtc.WebRTC{}, sessionsLock: &sync.Mutex{}, director: director, - Done: false, + IsRunning: true, onlineStorage: onlineStorage, + + Done: make(chan struct{}), } go room.startVideo() @@ -122,7 +128,7 @@ func (r *Room) startWebRTCSession(peerconnection *webrtc.WebRTC, playerIndex int // might consider continue here } - if peerconnection.Done || !peerconnection.IsConnected() || r.Done { + if peerconnection.Done || !peerconnection.IsConnected() || !r.IsRunning { return } @@ -147,14 +153,13 @@ func (r *Room) CleanSession(peerconnection *webrtc.WebRTC) { } func (r *Room) removeSession(w *webrtc.WebRTC) { - fmt.Println("Cleaning session: ", w) - fmt.Println("Sessions list", r.rtcSessions) + log.Println("Cleaning session: ", w.ID) // TODO: get list of r.rtcSessions in lock for i, s := range r.rtcSessions { - fmt.Println("found session: ", s, w) + log.Println("found session: ", w.ID) if s.ID == w.ID { r.rtcSessions = append(r.rtcSessions[:i], r.rtcSessions[i+1:]...) - fmt.Println("found session: ", len(r.rtcSessions)) + log.Println("Removed session ", s.ID, " from room: ", r.ID) // If room has no sessions, close room // Note: this logic cannot be brought outside of forloop because we only close room if room had at least one session @@ -169,17 +174,28 @@ func (r *Room) removeSession(w *webrtc.WebRTC) { } } +// TODO: Reuse for remove Session +func (r *Room) IsPCInRoom(w *webrtc.WebRTC) bool { + for _, s := range r.rtcSessions { + if s.ID == w.ID { + return true + } + } + return false +} + func (r *Room) Close() { - if r.Done { + if !r.IsRunning { return } + r.IsRunning = false log.Println("Closing room", r.ID) log.Println("Closing director of room ", r.ID) close(r.director.Done) log.Println("Closing input of room ", r.ID) close(r.inputChannel) - r.Done = true + close(r.Done) // Close here is a bit wrong because this read channel //close(r.imageChannel) //close(r.audioChannel) @@ -223,7 +239,7 @@ func (r *Room) LoadGame() error { return err } -func (r *Room) IsRunning() bool { +func (r *Room) IsRunningSessions() bool { // If there is running session for _, s := range r.rtcSessions { if s.IsConnected() { diff --git a/webrtc/webrtc.go b/webrtc/webrtc.go index f1b0b1cd..cdad7be7 100644 --- a/webrtc/webrtc.go +++ b/webrtc/webrtc.go @@ -93,12 +93,12 @@ type WebRTC struct { // StartClient start webrtc func (w *WebRTC) StartClient(remoteSession string, width, height int) (string, error) { - defer func() { - if err := recover(); err != nil { - log.Println(err) - w.StopClient() - } - }() + //defer func() { + //if err := recover(); err != nil { + //log.Println(err) + //w.StopClient() + //} + //}() // reset client if w.isConnected { @@ -156,19 +156,13 @@ func (w *WebRTC) StartClient(remoteSession string, width, height int) (string, e // Register text message handling inputTrack.OnMessage(func(msg webrtc.DataChannelMessage) { - //layout .:= "2006-01-02T15:04:05.000Z" - //if t, err := time.Parse(layout, string(msg.Data[1])); err == nil { - //fmt.Println("Delay ", time.Now().Sub(t)) - //} else { + // TODO: Can add recover here w.InputChannel <- int(msg.Data[0]) - //} }) inputTrack.OnClose(func() { log.Println("Data channel closed") log.Println("Closed webrtc") - //close(w.Done) - //w.StopClient() }) // WebRTC state callback