Files
galaxy-game/internal/controller/controller.go
T
2026-02-08 20:47:46 +02:00

108 lines
2.4 KiB
Go

package controller
import (
"errors"
"fmt"
"github.com/google/uuid"
"github.com/iliadenisov/galaxy/internal/model/game"
"github.com/iliadenisov/galaxy/internal/model/report"
"github.com/iliadenisov/galaxy/internal/repo"
)
type Repo interface {
// Lock must be called before any repository operations
Lock() error
// Release must be called after first and only repository operation
Release() error
// SaveTurn stores just generated new turn
SaveNewTurn(uint, *game.Game) error
// SaveState stores current game state updated between turns
SaveLastState(*game.Game) error
// LoadState retrieves game current state with required lock acquisition
LoadState() (*game.Game, error)
// LoadStateSafe retrieves game current state without preliminary locking
LoadStateSafe() (*game.Game, error)
// SaveBattle stores a new battle protocol and battle meta data for turn t
SaveBattle(uint, *report.BattleReport, *game.BattleMeta) error
// SaveBombing stores all prodused bombings for turn t
SaveBombings(uint, []*game.Bombing) error
// SaveReport stores latest report for a race
SaveReport(uint, *report.Report) error
// LoadReport loads report for specific turn and player id
LoadReport(uint, uuid.UUID) (*report.Report, error)
}
type Controller struct {
Repo Repo
Cache *Cache
}
type Param struct {
StoragePath string
}
type Configurer func(*Param)
func NewController(config Configurer) (*Controller, error) {
c := &Param{
StoragePath: ".",
}
if config != nil {
config(c)
}
r, err := repo.NewFileRepo(c.StoragePath)
if err != nil {
return nil, err
}
return &Controller{
Repo: r,
}, nil
}
func NewRepoController(r Repo) *Controller {
return &Controller{
Repo: r,
}
}
func (c *Controller) ExecuteState(consumer func(Repo) error) (err error) {
if err := c.Repo.Lock(); err != nil {
return fmt.Errorf("execute: lock failed: %s", err)
}
defer func() {
err = errors.Join(err, c.Repo.Release())
}()
err = consumer(c.Repo)
return
}
func (c *Controller) ExecuteCommand(consumer func(Repo, *game.Game) error) (err error) {
if err := c.Repo.Lock(); err != nil {
return fmt.Errorf("execute: lock failed: %s", err)
}
g, err := c.Repo.LoadState()
if err != nil {
return err
}
defer func() {
err = errors.Join(err, c.Repo.Release())
}()
c.Cache = NewCache(g)
err = consumer(c.Repo, g)
if err == nil {
g.Stage += 1
c.Repo.SaveLastState(g)
}
return
}