From 1d2dfbf55422fac7ac733cb63945d69702c0ec04 Mon Sep 17 00:00:00 2001 From: giongto35 Date: Sat, 4 May 2019 04:03:08 +0800 Subject: [PATCH] Save game load game to cloud --- emulator/director.go | 14 +++++++- handler/cloud-storage/storage.go | 1 + handler/handlers.go | 8 ++++- handler/room/room.go | 58 ++++++++++++++++++++++++++------ 4 files changed, 69 insertions(+), 12 deletions(-) diff --git a/emulator/director.go b/emulator/director.go index ce3a3ea4..29696885 100644 --- a/emulator/director.go +++ b/emulator/director.go @@ -19,7 +19,9 @@ type Director struct { Done chan struct{} roomID string - hash string + // Hash represents a game state (roomID, gamePath). + // It is used for save file name + hash string } const FPS = 60 @@ -126,3 +128,13 @@ func (d *Director) LoadGame() error { return nil } } + +// GetHash return hash +func (d *Director) GetHash() string { + return d.hash +} + +// GetHashPath return the full path to hash file +func (d *Director) GetHashPath() string { + return savePath(d.hash) +} diff --git a/handler/cloud-storage/storage.go b/handler/cloud-storage/storage.go index f9c822ca..3aa0d6c4 100644 --- a/handler/cloud-storage/storage.go +++ b/handler/cloud-storage/storage.go @@ -10,6 +10,7 @@ import ( "cloud.google.com/go/storage" ) +// TODO: Add interface, abstract out Gstorage type Client struct { bucket *storage.BucketHandle gclient *storage.Client diff --git a/handler/handlers.go b/handler/handlers.go index 60d57e90..2d444d2b 100644 --- a/handler/handlers.go +++ b/handler/handlers.go @@ -7,6 +7,7 @@ import ( "net/http" "github.com/giongto35/cloud-game/cws" + storage "github.com/giongto35/cloud-game/handler/cloud-storage" "github.com/giongto35/cloud-game/handler/gamelist" "github.com/giongto35/cloud-game/handler/room" "github.com/giongto35/cloud-game/webrtc" @@ -36,11 +37,14 @@ type Handler struct { // All webrtc peerconnections are handled by the server // ID -> peerconnections peerconnections map[string]*webrtc.WebRTC + // onlineStorage is client accessing to online storage (GCP) + onlineStorage *storage.Client } // NewHandler returns a new server func NewHandler(overlordConn *websocket.Conn, isDebug bool, gamePath string) *Handler { log.Println("new OverlordClient") + return &Handler{ oClient: NewOverlordClient(overlordConn), rooms: map[string]*room.Room{}, @@ -48,6 +52,8 @@ func NewHandler(overlordConn *websocket.Conn, isDebug bool, gamePath string) *Ha isDebug: isDebug, gamePath: gamePath, + + onlineStorage: storage.NewInitClient(), } } @@ -132,7 +138,7 @@ func (h *Handler) createNewRoom(gameName string, roomID string, playerIndex int) // 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) + room := room.NewRoom(roomID, h.gamePath, gameName, h.onlineStorage) // TODO: Might have race condition h.rooms[room.ID] = room return room diff --git a/handler/room/room.go b/handler/room/room.go index 78067e8f..ace0c589 100644 --- a/handler/room/room.go +++ b/handler/room/room.go @@ -3,12 +3,15 @@ package room import ( "fmt" "image" + "io/ioutil" "log" "math/rand" "strconv" "sync" + "time" emulator "github.com/giongto35/cloud-game/emulator" + storage "github.com/giongto35/cloud-game/handler/cloud-storage" "github.com/giongto35/cloud-game/webrtc" ) @@ -27,10 +30,13 @@ type Room struct { sessionsLock *sync.Mutex director *emulator.Director + + // Cloud storage to store room state online + onlineStorage *storage.Client } // NewRoom creates a new room -func NewRoom(roomID, gamepath, gameName string) *Room { +func NewRoom(roomID, gamepath, gameName string, onlineStorage *storage.Client) *Room { // if no roomID is given, generate it if roomID == "" { roomID = generateRoomID() @@ -46,13 +52,14 @@ func NewRoom(roomID, gamepath, gameName string) *Room { room := &Room{ ID: roomID, - imageChannel: imageChannel, - audioChannel: audioChannel, - inputChannel: inputChannel, - rtcSessions: []*webrtc.WebRTC{}, - sessionsLock: &sync.Mutex{}, - director: director, - Done: make(chan struct{}), + imageChannel: imageChannel, + audioChannel: audioChannel, + inputChannel: inputChannel, + rtcSessions: []*webrtc.WebRTC{}, + sessionsLock: &sync.Mutex{}, + director: director, + Done: make(chan struct{}), + onlineStorage: onlineStorage, } go room.startVideo() @@ -135,11 +142,42 @@ func (r *Room) Close() { } func (r *Room) SaveGame() error { - return r.director.SaveGame() + // TODO: Move to game view + if err := r.director.SaveGame(); err != nil { + return err + } + time.Sleep(1000 * time.Millisecond) + + // Try to save the game to gCloud + // TODO: Add goroutine + if err := r.onlineStorage.SaveFile(r.director.GetHash(), r.director.GetHashPath()); err != nil { + return err + } + + return nil } func (r *Room) LoadGame() error { - return r.director.LoadGame() + err := r.director.LoadGame() + time.Sleep(1000 * time.Millisecond) + if err != nil { + // TODO: Put in GoRoutine + // If the game is not on local server + // Try to load from gcloud + data, err := r.onlineStorage.LoadFile(r.director.GetHash()) + if err != nil { + return err + } + // Save the data fetched from gcloud to local server + ioutil.WriteFile(r.director.GetHashPath(), data, 0644) + // Reload game again + err = r.director.LoadGame() + if err != nil { + return err + } + } + + return err } func (r *Room) IsRunning() bool {