cloud-game/worker/handlers.go
2019-06-06 23:14:29 +08:00

164 lines
3.8 KiB
Go

package worker
import (
"log"
"time"
"github.com/giongto35/cloud-game/webrtc"
storage "github.com/giongto35/cloud-game/worker/cloud-storage"
"github.com/giongto35/cloud-game/worker/room"
"github.com/gorilla/websocket"
)
const (
gameboyIndex = "./static/game.html"
debugIndex = "./static/game.html"
)
// Flag to determine if the server is overlord or not
var upgrader = websocket.Upgrader{}
type Handler struct {
// Client that connects to overlord
oClient *OverlordClient
// Raw address of overlord
overlordHost string
// Rooms map : RoomID -> Room
rooms map[string]*room.Room
// ID of the current server globalwise
serverID string
// Path to game list
gamePath string
// onlineStorage is client accessing to online storage (GCP)
onlineStorage *storage.Client
// sessions handles all sessions server is handler (key is sessionID)
sessions map[string]*Session
}
// NewHandler returns a new server
func NewHandler(overlordHost string, gamePath string) *Handler {
onlineStorage := storage.NewInitClient()
return &Handler{
rooms: map[string]*room.Room{},
sessions: map[string]*Session{},
overlordHost: overlordHost,
gamePath: gamePath,
onlineStorage: onlineStorage,
}
}
// Run starts a Handler running logic
func (h *Handler) Run() {
for {
oClient, err := setupOverlordConnection(h.overlordHost)
if err != nil {
log.Println("Cannot connect to overlord. Retrying...")
time.Sleep(time.Second)
continue
}
h.oClient = oClient
log.Println("Connected to overlord successfully.")
go h.oClient.Heartbeat()
h.RouteOverlord()
h.oClient.Listen()
// If cannot listen, reconnect to overlord
}
}
func setupOverlordConnection(ohost string) (*OverlordClient, error) {
conn, err := createOverlordConnection(ohost)
if err != nil {
return nil, err
}
return NewOverlordClient(conn), nil
}
func createOverlordConnection(ohost string) (*websocket.Conn, error) {
c, _, err := websocket.DefaultDialer.Dial(ohost, nil)
if err != nil {
return nil, err
}
return c, nil
}
func (h *Handler) GetOverlordClient() *OverlordClient {
return h.oClient
}
// detachPeerConn detach/remove a peerconnection from current room
func (h *Handler) detachPeerConn(pc *webrtc.WebRTC) {
log.Println("Detach peerconnection")
roomID := pc.RoomID
room := h.getRoom(roomID)
if room == nil {
return
}
// If room has no sessions, close room
if !room.EmptySessions() {
room.RemoveSession(pc)
if room.EmptySessions() {
log.Println("No session in room")
room.Close()
// Signal end of input Channel
log.Println("Signal input chan")
pc.InputChannel <- -1
}
}
}
// getRoom returns room from roomID
func (h *Handler) getRoom(roomID string) *room.Room {
room, ok := h.rooms[roomID]
if !ok {
return nil
}
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 {
// If the roomID is empty,
// or the roomID doesn't have any running sessions (room was closed)
// we spawn a new room
if roomID == "" || !h.isRoomRunning(roomID) {
room := room.NewRoom(roomID, h.gamePath, gameName, h.onlineStorage)
// TODO: Might have race condition
h.rooms[room.ID] = room
return room
}
return nil
}
// 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 (h *Handler) isRoomRunning(roomID string) bool {
// If no roomID is registered
room, ok := h.rooms[roomID]
if !ok {
return false
}
return room.IsRunningSessions()
}
func (h *Handler) Close() {
if h.oClient != nil {
h.oClient.Close()
}
// Close all room
for _, room := range h.rooms {
room.Close()
}
}