clone

fifteen puzzle games for the terminal, with daily puzzles, weekly ladders and xp, built on bubble tea

feat/app-decomposition
puzzletea / app / spawn.go
spawn.go 1.9K
1package app23import (4 "context"5 "math/rand/v2"6 "time"78 "github.com/FelineStateMachine/puzzletea/game"9 "github.com/FelineStateMachine/puzzletea/store"1011 tea "charm.land/bubbletea/v2"12)1314const spawnTimeout = 10 * time.Second1516type spawnCompleteMsg struct {17 jobID int6418 result game.SpawnCompleteMsg19}2021// spawnCmd returns a tea.Cmd that runs Spawn() off the main goroutine.22func spawnCmd(spawner game.Spawner, ctx context.Context, jobID int64) tea.Cmd {23 return func() tea.Msg {24 var (25 g game.Gamer26 err error27 )28 if cancellable, ok := spawner.(game.CancellableSpawner); ok {29 g, err = cancellable.SpawnContext(ctx)30 } else {31 g, err = spawner.Spawn()32 }33 return spawnCompleteMsg{34 jobID: jobID,35 result: game.SpawnCompleteMsg{Game: g, Err: err},36 }37 }38}3940// spawnSeededCmd returns a tea.Cmd that runs SpawnSeeded() off the main goroutine.41// The caller must not use rng after this call — *rand.Rand is not goroutine-safe42// and ownership is transferred to the spawned goroutine.43func spawnSeededCmd(spawner game.SeededSpawner, rng *rand.Rand, ctx context.Context, jobID int64) tea.Cmd {44 return func() tea.Msg {45 var (46 g game.Gamer47 err error48 )49 if cancellable, ok := spawner.(game.CancellableSeededSpawner); ok {50 g, err = cancellable.SpawnSeededContext(ctx, rng)51 } else {52 g, err = spawner.SpawnSeeded(rng)53 }54 return spawnCompleteMsg{55 jobID: jobID,56 result: game.SpawnCompleteMsg{Game: g, Err: err},57 }58 }59}6061func (m *model) cancelActiveSpawn() {62 newSessionController(m).cancelActiveSpawn()63}6465func (m model) handleSpawnComplete(jobID int64, msg game.SpawnCompleteMsg) (tea.Model, tea.Cmd) {66 cmd := newSessionController(&m).handleSpawnComplete(jobID, msg)67 return m, cmd68}6970// saveCurrentGame saves the current game state to the DB if a game is active.71func saveCurrentGame(m model, status store.GameStatus) model {72 newSessionController(&m).saveCurrentGame(status)73 return m74}