Skip to content

Commit

Permalink
Add app state interface
Browse files Browse the repository at this point in the history
  • Loading branch information
sergystepanov committed Jul 14, 2023
1 parent a06ea71 commit 2a705ef
Show file tree
Hide file tree
Showing 5 changed files with 48 additions and 39 deletions.
7 changes: 3 additions & 4 deletions pkg/worker/caged/caged.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,7 @@ type App interface {
}

type State interface {
EnableAutosave(periodS int)
HasSave() bool
LoadGame() error
SaveGame() error
Autosave(periodS int)
LoadState() error
SaveState() error
}
37 changes: 15 additions & 22 deletions pkg/worker/coordinatorhandlers.go
Original file line number Diff line number Diff line change
Expand Up @@ -77,8 +77,10 @@ func (c *coordinator) HandleGameStart(rq api.StartGameRequest[com.Uid], w *Worke
}
w.log.Info().Msgf("Starting game: %v", rq.Game.Name)

room := w.router.FindRoom(rq.Rid)
if room == nil {
var room GameRoom
r := w.router.FindRoom(rq.Rid)

if r == nil {
room = NewRoom(
rq.Room.Rid,
games.GameMetadata(rq.Game),
Expand All @@ -93,30 +95,21 @@ func (c *coordinator) HandleGameStart(rq api.StartGameRequest[com.Uid], w *Worke
user.SetPlayerIndex(rq.PlayerIndex)

if w.storage != nil {
cs := &StorageRoom{
GameRoom: room,
stateLocalPath: room.Emulator().GetHashPath(),
stateName: room.Id(),
storage: w.storage,
}
if err := cs.Download(); err != nil {
room.Log().Warn().Err(err).Msgf("[%v] is not in the cloud", cs.stateName)
} else {
room.Log().Debug().Msgf("Downloaded [%v] from the cloud", cs.stateName)
}
room = cs
room = WithCloudStorage(room, room.Emulator().GetHashPath(), room.Id(), w.storage)
}
if w.conf.Recording.Enabled {
room = WithRecording(room.(*Room), rq.Record, rq.RecordUser, rq.Game.Name, w.conf)
room = WithRecording(room, rq.Record, rq.RecordUser, rq.Game.Name, w.conf)
}
w.router.SetRoom(room)

room.StartEmulator()

if w.conf.Emulator.AutosaveSec > 0 {
// !to can crash if emulator starts earlier
go room.EnableAutosave(w.conf.Emulator.AutosaveSec)
// !to can crash if the emulator starts later
go room.Autosave(w.conf.Emulator.AutosaveSec)
}
} else {
room = r.(GameRoom)
}

if room == nil {
Expand All @@ -142,7 +135,7 @@ func (c *coordinator) HandleTerminateSession(rq api.TerminateSessionRequest[com.
user.Disconnect()
if room := user.Room(); room != nil {
user.SetRoom(nil)
room.Expel(user)
room.(GameRoom).Expel(user)
}
}
}
Expand All @@ -154,7 +147,7 @@ func (c *coordinator) HandleQuitGame(rq api.GameQuitRequest[com.Uid], w *Worker)
// since users hold their room reference
// !to remove rid, maybe
if room := w.router.FindRoom(rq.Rid); room != nil {
room.Expel(user)
room.(GameRoom).Expel(user)
}
}
}
Expand All @@ -164,7 +157,7 @@ func (c *coordinator) HandleSaveGame(rq api.SaveGameRequest[com.Uid], w *Worker)
if room == nil {
return api.ErrPacket
}
if err := room.SaveGame(); err != nil {
if err := room.SaveState(); err != nil {
c.log.Error().Err(err).Msg("cannot save game state")
return api.ErrPacket
}
Expand All @@ -176,7 +169,7 @@ func (c *coordinator) HandleLoadGame(rq api.LoadGameRequest[com.Uid], w *Worker)
if room == nil {
return api.ErrPacket
}
if err := room.LoadGame(); err != nil {
if err := room.LoadState(); err != nil {
c.log.Error().Err(err).Msg("cannot load game state")
return api.ErrPacket
}
Expand All @@ -198,7 +191,7 @@ func (c *coordinator) HandleToggleMultitap(rq api.ToggleMultitapRequest[com.Uid]
if room == nil {
return api.ErrPacket
}
room.ToggleMultitap()
room.(GameRoom).ToggleMultitap()
return api.OkPacket
}

Expand Down
15 changes: 11 additions & 4 deletions pkg/worker/room.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,20 @@ type GameRoom interface {
Emulator() emulator.Emulator
Expel(*Session)
HasUser(*Session) bool
HasSave() bool
Id() string
Log() *logger.Logger
PollUserInput(*Session)
StartEmulator()
ToggleMultitap()
}

type AppRoom interface {
caged.State
Close()
Id() string
}

type Room struct {
closed bool
done chan struct{}
Expand Down Expand Up @@ -79,13 +86,13 @@ func (r *Room) HasSave() bool { return os.Exists(r.emulator.GetHas
func (r *Room) HasUser(u *Session) bool { return r != nil && r.users.Has(u.id) }
func (r *Room) Id() string { return r.id }
func (r *Room) IsEmpty() bool { return r.users.Len() == 0 }
func (r *Room) LoadGame() error { return r.emulator.LoadGameState() }
func (r *Room) LoadState() error { return r.emulator.LoadGameState() }
func (r *Room) Log() *logger.Logger { return r.log }
func (r *Room) SaveGame() error { return r.emulator.SaveGameState() }
func (r *Room) SaveState() error { return r.emulator.SaveGameState() }
func (r *Room) StartEmulator() { go r.emulator.Start() }
func (r *Room) ToggleMultitap() { r.emulator.ToggleMultitap() }

func (r *Room) EnableAutosave(periodSec int) {
func (r *Room) Autosave(periodSec int) {
r.log.Info().Msgf("Autosave every [%vs]", periodSec)
ticker := time.NewTicker(time.Duration(periodSec) * time.Second)
defer ticker.Stop()
Expand Down Expand Up @@ -168,7 +175,7 @@ func (r *Room) Close() {
// Save game on quit if it was saved before (shared or click-saved).
if r.HasSave() {
r.log.Debug().Msg("Save on quit")
if err := r.SaveGame(); err != nil {
if err := r.SaveState(); err != nil {
r.log.Error().Err(err).Msg("save on quit failed")
}
}
Expand Down
14 changes: 7 additions & 7 deletions pkg/worker/router.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,21 +6,21 @@ import (
"github.com/pion/webrtc/v3/pkg/media"
)

// Router tracks and routes freshly connected users to a game room.
// Router tracks and routes freshly connected users to an app room.
// Basically, it holds user connection data until some user makes (connects to)
// a new room (game), then it manages all the cross-references between room and users.
// a new room (app), then it manages all the cross-references between room and users.
// Rooms and users has 1-to-n relationship.
type Router struct {
room GameRoom
room AppRoom
users com.NetMap[*Session]
}

// Session represents WebRTC connection of the user.
type Session struct {
conn *webrtc.Peer
id com.Uid
pi int // player index
room GameRoom // back reference
pi int // player index
room AppRoom // back reference
}

func NewRouter() Router { return Router{users: com.NewNetMap[*Session]()} }
Expand All @@ -31,7 +31,7 @@ func (r *Router) Close() {
r.room.Close()
}
}
func (r *Router) FindRoom(id string) GameRoom {
func (r *Router) FindRoom(id string) AppRoom {
if r.room != nil && r.room.Id() == id {
return r.room
}
Expand All @@ -48,7 +48,7 @@ func (s *Session) Id() com.Uid { return s.id }
func (s *Session) IsConnected() bool { return s.conn.IsConnected() }
func (s *Session) PeerConn() *webrtc.Peer { return s.conn }
func (s *Session) PlayerIndex() int { return s.pi }
func (s *Session) Room() GameRoom { return s.room }
func (s *Session) Room() AppRoom { return s.room }
func (s *Session) SendAudio(sample *media.Sample) error { return s.conn.WriteAudio(sample) }
func (s *Session) SendVideo(sample *media.Sample) error { return s.conn.WriteVideo(sample) }
func (s *Session) SetPlayerIndex(index int) { s.pi = index }
Expand Down
14 changes: 12 additions & 2 deletions pkg/worker/storage.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,16 @@ type StorageRoom struct {
storage Storage // a cloud storage to store room state online
}

func WithCloudStorage(parent GameRoom, stateLocal string, stateName string, storage Storage) *StorageRoom {
r := &StorageRoom{GameRoom: parent, stateLocalPath: stateLocal, stateName: stateName, storage: storage}
if err := r.Download(); err != nil {
parent.Log().Warn().Err(err).Msgf("[%v] is not in the cloud", stateName)
} else {
parent.Log().Debug().Msgf("Downloaded [%v] from the cloud", stateName)
}
return r
}

func (c *StorageRoom) Download() error {
// saveOnlineRoomToLocal save online room to local.
// !Supports only one file of main save state.
Expand All @@ -54,8 +64,8 @@ func (c *StorageRoom) HasSave() bool {
return c.GameRoom.HasSave()
}

func (c *StorageRoom) SaveGame() error {
if err := c.GameRoom.SaveGame(); err != nil {
func (c *StorageRoom) SaveState() error {
if err := c.GameRoom.SaveState(); err != nil {
return err
}
if err := c.storage.Save(c.stateName, c.stateLocalPath); err != nil {
Expand Down

0 comments on commit 2a705ef

Please sign in to comment.