package controller import ( "errors" "fmt" "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 } type Controller struct { Repo Repo Cache *Cache } type Param struct { StoragePath string } type Config func(*Param) func NewController(config Config) (*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 }