Separate create room logic

This commit is contained in:
giongto35 2019-05-01 21:06:05 +08:00
parent 7ea7e9b5f0
commit c00d7c8491
6 changed files with 103 additions and 46 deletions

View file

@ -116,7 +116,6 @@ func initClient(t *testing.T, host string) {
RoomID: "",
PlayerIndex: 1,
}, func(resp cws.WSPacket) {
fmt.Println("Received response")
fmt.Println("RoomID:", resp.RoomID)
roomID <- resp.RoomID
})

View file

@ -2,6 +2,7 @@ package handler
import (
"encoding/json"
"fmt"
"log"
"github.com/giongto35/cloud-game/config"
@ -80,7 +81,6 @@ func (s *Session) RegisterBrowserClient() {
s.GameName = resp.Data
s.RoomID = resp.RoomID
s.PlayerIndex = resp.PlayerIndex
isNewRoom := false
log.Println("Starting game")
// If we are connecting to overlord, request serverID from roomID
@ -94,9 +94,11 @@ func (s *Session) RegisterBrowserClient() {
}
}
s.RoomID, isNewRoom = startSession(s.peerconnection, s.GameName, s.RoomID, s.PlayerIndex)
room := s.handler.createNewRoom(s.GameName, s.RoomID, s.PlayerIndex)
room.addConnectionToRoom(s.peerconnection, s.PlayerIndex)
s.RoomID = room.ID
// Register room to overlord if we are connecting to overlord
if isNewRoom && s.OverlordClient != nil {
if room != nil && s.OverlordClient != nil {
s.OverlordClient.Send(cws.WSPacket{
ID: "registerRoom",
Data: s.RoomID,
@ -105,6 +107,7 @@ func (s *Session) RegisterBrowserClient() {
req.ID = "start"
req.RoomID = s.RoomID
req.SessionID = s.ID
fmt.Println("Response from start", req)
return req
})

View file

@ -97,6 +97,7 @@ func (h *Handler) WS(w http.ResponseWriter, r *http.Request) {
BrowserClient: client,
OverlordClient: h.oClient,
peerconnection: webrtc.NewWebRTC(),
handler: h,
}
wssession.RegisterBrowserClient()
fmt.Println("oclient : ", h.oClient)

View file

@ -9,6 +9,8 @@ import (
"github.com/gorilla/websocket"
)
// OverlordClient maintans connection to overlord
// We expect only one OverlordClient for each server
type OverlordClient struct {
*cws.Client
peerconnections map[string]*webrtc.WebRTC
@ -26,6 +28,7 @@ func NewOverlordClient(oc *websocket.Conn) *OverlordClient {
return oclient
}
// RegisterOverlordClient routes overlord Client
func (s *Session) RegisterOverlordClient() {
oclient := s.OverlordClient
@ -64,7 +67,7 @@ func (s *Session) RegisterOverlordClient() {
},
)
// Received start from overlord. This is happens when bridging
// Received start from overlord. This happens when bridging
// TODO: refactor
oclient.Receive(
"start",
@ -74,16 +77,24 @@ func (s *Session) RegisterOverlordClient() {
peerconnection := oclient.peerconnections[resp.SessionID]
log.Println("start session")
roomID, isNewRoom := startSession(peerconnection, resp.Data, resp.RoomID, resp.PlayerIndex)
//room := s.handler.createNewRoom(s.GameName, s.RoomID, s.PlayerIndex)
room := s.handler.getRoom(s.RoomID)
if room == nil {
log.Println("Room not found", s.RoomID)
return cws.EmptyPacket
}
room.addConnectionToRoom(peerconnection, s.PlayerIndex)
//roomID, isNewRoom := startSession(peerconnection, resp.Data, resp.RoomID, resp.PlayerIndex)
log.Println("Done, sending back")
// Bridge always access to old room
// TODO: log warn
if isNewRoom == true {
if room != nil {
log.Fatal("Bridge should not spawn new room")
}
req.ID = "start"
req.RoomID = roomID
req.RoomID = room.ID
return req
},
)

View file

@ -14,6 +14,8 @@ import (
// Room is a game session. multi webRTC sessions can connect to a same game.
// A room stores all the channel for interaction between all webRTCs session and emulator
type Room struct {
ID string
imageChannel chan *image.RGBA
audioChannel chan float32
inputChannel chan int
@ -36,7 +38,7 @@ func generateRoomID() string {
}
// init initilizes a room returns roomID
func initRoom(roomID, gameName string) string {
func (h *Handler) initRoom(roomID, gameName string) *Room {
// if no roomID is given, generate it
if roomID == "" {
roomID = generateRoomID()
@ -50,6 +52,8 @@ func initRoom(roomID, gameName string) string {
director := emulator.NewDirector(roomID, imageChannel, audioChannel, inputChannel)
room := &Room{
ID: roomID,
imageChannel: imageChannel,
audioChannel: audioChannel,
inputChannel: inputChannel,
@ -58,18 +62,17 @@ func initRoom(roomID, gameName string) string {
director: director,
Done: make(chan struct{}),
}
rooms[roomID] = room
go room.startVideo()
go room.startAudio()
go director.Start([]string{"games/" + gameName})
go director.Start([]string{"../games/" + gameName})
return roomID
return room
}
// isRoomRunning check if there is any running sessions.
// TODO: If we remove sessions from room anytime a session is closed, we can check if the sessions list is empty or not.
func isRoomRunning(roomID string) bool {
func (h *Handler) isRoomRunning(roomID string) bool {
// If no roomID is registered
if _, ok := rooms[roomID]; !ok {
return false
@ -84,24 +87,32 @@ func isRoomRunning(roomID string) bool {
return false
}
func (r *Room) addConnectionToRoom(peerconnection *webrtc.WebRTC, playerIndex int) {
r.cleanSession(peerconnection)
peerconnection.AttachRoomID(r.ID)
go r.startWebRTCSession(peerconnection, playerIndex)
r.rtcSessions = append(r.rtcSessions, peerconnection)
}
// startWebRTCSession fan-in of the same room to inputChannel
func startWebRTCSession(room *Room, webRTC *webrtc.WebRTC, playerIndex int) {
inputChannel := room.inputChannel
log.Println("room, inputChannel", room, inputChannel)
func (r *Room) startWebRTCSession(peerconnection *webrtc.WebRTC, playerIndex int) {
inputChannel := r.inputChannel
log.Println("room, inputChannel", r, inputChannel)
for {
select {
case <-webRTC.Done:
removeSession(webRTC, room)
case <-peerconnection.Done:
r.removeSession(peerconnection)
default:
}
// Client stopped
if webRTC.IsClosed() {
if peerconnection.IsClosed() {
return
}
// encode frame
if webRTC.IsConnected() {
input := <-webRTC.InputChannel
if peerconnection.IsConnected() {
input := <-peerconnection.InputChannel
// the first 8 bits belong to player 1
// the next 8 belongs to player 2 ...
// We standardize and put it to inputChannel (16 bits)
@ -111,26 +122,22 @@ func startWebRTCSession(room *Room, webRTC *webrtc.WebRTC, playerIndex int) {
}
}
func cleanSession(w *webrtc.WebRTC) {
room, ok := rooms[w.RoomID]
if !ok {
return
}
removeSession(w, room)
func (r *Room) cleanSession(peerconnection *webrtc.WebRTC) {
r.removeSession(peerconnection)
}
func removeSession(w *webrtc.WebRTC, room *Room) {
room.sessionsLock.Lock()
defer room.sessionsLock.Unlock()
for i, s := range room.rtcSessions {
func (r *Room) removeSession(w *webrtc.WebRTC) {
r.sessionsLock.Lock()
defer r.sessionsLock.Unlock()
for i, s := range r.rtcSessions {
if s == w {
room.rtcSessions = append(room.rtcSessions[:i], room.rtcSessions[i+1:]...)
r.rtcSessions = append(r.rtcSessions[:i], r.rtcSessions[i+1:]...)
break
}
}
// If room has no sessions, close room
if len(room.rtcSessions) == 0 {
room.Done <- struct{}{}
if len(r.rtcSessions) == 0 {
r.Done <- struct{}{}
}
}

View file

@ -13,30 +13,66 @@ type Session struct {
OverlordClient *OverlordClient
peerconnection *webrtc.WebRTC
// TODO: Decouple this
handler *Handler
ServerID string
GameName string
RoomID string
PlayerIndex int
}
// startSession handles one session call
func startSession(webRTC *webrtc.WebRTC, gameName string, roomID string, playerIndex int) (rRoomID string, isNewRoom bool) {
isNewRoom = false
cleanSession(webRTC)
// getRoom returns room from roomID
func (h *Handler) getRoom(roomID string) *Room {
room, ok := h.rooms[roomID]
if !ok {
return nil
}
return room
}
// createNewRoom creates a new room
// Return nil in case of room is existed
func (h *Handler) createNewRoom(gameName string, roomID string, playerIndex int) *Room {
//cleanSession(peerconnection)
// If the roomID is empty,
// or the roomID doesn't have any running sessions (room was closed)
// we spawn a new room
if roomID == "" || !isRoomRunning(roomID) {
roomID = initRoom(roomID, gameName)
isNewRoom = true
if roomID == "" || !h.isRoomRunning(roomID) {
room := h.initRoom(roomID, gameName)
h.rooms[roomID] = room
return room
}
// TODO: Might have race condition
rooms[roomID].rtcSessions = append(rooms[roomID].rtcSessions, webRTC)
room := rooms[roomID]
//rooms[roomID].rtcSessions = append(rooms[roomID].rtcSessions, peerconnection)
//room := rooms[roomID]
webRTC.AttachRoomID(roomID)
go startWebRTCSession(room, webRTC, playerIndex)
//peerconnection.AttachRoomID(roomID)
//go startWebRTCSession(room, peerconnection, playerIndex)
return roomID, isNewRoom
return nil
}
// startPeerConnection handles one peerconnection call
//func (s *Handler) startPeerConnection( gameName string, roomID string, playerIndex int) (rRoomID string, isNewRoom bool) {
//isNewRoom = false
//cleanSession(peerconnection)
//// If the roomID is empty,
//// or the roomID doesn't have any running sessions (room was closed)
//// we spawn a new room
//if roomID == "" || !isRoomRunning(roomID) {
//roomID = initRoom(roomID, gameName)
//isNewRoom = true
//}
//// TODO: Might have race condition
//rooms[roomID].rtcSessions = append(rooms[roomID].rtcSessions, peerconnection)
//room := rooms[roomID]
//peerconnection.AttachRoomID(roomID)
//go startWebRTCSession(room, peerconnection, playerIndex)
//return roomID, isNewRoom
//}