diff --git a/game/lobby.go b/game/lobby.go index 3a18fb0..a2609a0 100644 --- a/game/lobby.go +++ b/game/lobby.go @@ -4,6 +4,8 @@ import ( "fmt" "math/rand" "sync" + + "github.com/tolelom/catacombs/config" ) type RoomStatus int @@ -36,13 +38,15 @@ type OnlinePlayer struct { type Lobby struct { mu sync.RWMutex + cfg *config.Config rooms map[string]*LobbyRoom online map[string]*OnlinePlayer // fingerprint -> player activeSessions map[string]string // fingerprint -> room code (for reconnect) } -func NewLobby() *Lobby { +func NewLobby(cfg *config.Config) *Lobby { return &Lobby{ + cfg: cfg, rooms: make(map[string]*LobbyRoom), online: make(map[string]*OnlinePlayer), activeSessions: make(map[string]string), diff --git a/game/lobby_test.go b/game/lobby_test.go index 64543fa..3177d42 100644 --- a/game/lobby_test.go +++ b/game/lobby_test.go @@ -1,9 +1,19 @@ package game -import "testing" +import ( + "testing" + + "github.com/tolelom/catacombs/config" +) + +func testConfig(t *testing.T) *config.Config { + t.Helper() + cfg, _ := config.Load("") + return cfg +} func TestCreateRoom(t *testing.T) { - lobby := NewLobby() + lobby := NewLobby(testConfig(t)) code := lobby.CreateRoom("Test Room") if len(code) != 4 { t.Errorf("Room code length: got %d, want 4", len(code)) @@ -15,7 +25,7 @@ func TestCreateRoom(t *testing.T) { } func TestJoinRoom(t *testing.T) { - lobby := NewLobby() + lobby := NewLobby(testConfig(t)) code := lobby.CreateRoom("Test Room") err := lobby.JoinRoom(code, "player1", "fp-player1") if err != nil { @@ -28,7 +38,7 @@ func TestJoinRoom(t *testing.T) { } func TestRoomStatusTransition(t *testing.T) { - l := NewLobby() + l := NewLobby(testConfig(t)) code := l.CreateRoom("Test") l.JoinRoom(code, "Alice", "fp-alice") r := l.GetRoom(code) @@ -47,7 +57,7 @@ func TestRoomStatusTransition(t *testing.T) { } func TestJoinRoomFull(t *testing.T) { - lobby := NewLobby() + lobby := NewLobby(testConfig(t)) code := lobby.CreateRoom("Test Room") for i := 0; i < 4; i++ { lobby.JoinRoom(code, "player", "fp-player") @@ -59,7 +69,7 @@ func TestJoinRoomFull(t *testing.T) { } func TestSetPlayerClass(t *testing.T) { - l := NewLobby() + l := NewLobby(testConfig(t)) code := l.CreateRoom("Test") l.JoinRoom(code, "Alice", "fp-alice") l.SetPlayerClass(code, "fp-alice", "Warrior") @@ -70,7 +80,7 @@ func TestSetPlayerClass(t *testing.T) { } func TestAllReady(t *testing.T) { - l := NewLobby() + l := NewLobby(testConfig(t)) code := l.CreateRoom("Test") l.JoinRoom(code, "Alice", "fp-alice") l.JoinRoom(code, "Bob", "fp-bob") @@ -91,7 +101,7 @@ func TestAllReady(t *testing.T) { } func TestAllReadyEmptyRoom(t *testing.T) { - l := NewLobby() + l := NewLobby(testConfig(t)) code := l.CreateRoom("Test") if l.AllReady(code) { t.Error("empty room should not be all ready") diff --git a/main.go b/main.go index daa5ab0..271b788 100644 --- a/main.go +++ b/main.go @@ -1,9 +1,11 @@ package main import ( + "fmt" "log" "os" + "github.com/tolelom/catacombs/config" "github.com/tolelom/catacombs/game" "github.com/tolelom/catacombs/server" "github.com/tolelom/catacombs/store" @@ -13,23 +15,35 @@ import ( func main() { os.MkdirAll("data", 0755) + cfg, err := config.Load("config.yaml") + if err != nil { + if os.IsNotExist(err) { + cfg, _ = config.Load("") + } else { + log.Fatalf("Failed to load config: %v", err) + } + } + db, err := store.Open("data/catacombs.db") if err != nil { log.Fatalf("Failed to open database: %v", err) } defer db.Close() - lobby := game.NewLobby() + lobby := game.NewLobby(cfg) + + sshAddr := fmt.Sprintf("0.0.0.0:%d", cfg.Server.SSHPort) + webAddr := fmt.Sprintf(":%d", cfg.Server.HTTPPort) // Start web terminal server in background go func() { - if err := web.Start(":8080", 2222); err != nil { + if err := web.Start(webAddr, cfg.Server.SSHPort); err != nil { log.Printf("Web server error: %v", err) } }() - log.Println("Catacombs server starting — SSH :2222, Web :8080") - if err := server.Start("0.0.0.0", 2222, lobby, db); err != nil { + log.Printf("Catacombs server starting — SSH :%d, Web :%d", cfg.Server.SSHPort, cfg.Server.HTTPPort) + if err := server.Start(sshAddr, lobby, db); err != nil { log.Fatal(err) } } diff --git a/server/ssh.go b/server/ssh.go index 83b2898..0fb3e17 100644 --- a/server/ssh.go +++ b/server/ssh.go @@ -14,9 +14,9 @@ import ( "github.com/tolelom/catacombs/ui" ) -func Start(host string, port int, lobby *game.Lobby, db *store.DB) error { +func Start(addr string, lobby *game.Lobby, db *store.DB) error { s, err := wish.NewServer( - wish.WithAddress(fmt.Sprintf("%s:%d", host, port)), + wish.WithAddress(addr), wish.WithHostKeyPath(".ssh/catacombs_host_key"), wish.WithPublicKeyAuth(func(_ ssh.Context, _ ssh.PublicKey) bool { return true // accept all keys @@ -40,6 +40,6 @@ func Start(host string, port int, lobby *game.Lobby, db *store.DB) error { return fmt.Errorf("could not create server: %w", err) } - log.Printf("Starting SSH server on %s:%d", host, port) + log.Printf("Starting SSH server on %s", addr) return s.ListenAndServe() } diff --git a/ui/model_test.go b/ui/model_test.go index e33ea4d..2ece3fd 100644 --- a/ui/model_test.go +++ b/ui/model_test.go @@ -1,12 +1,13 @@ package ui import ( + "os" "testing" tea "github.com/charmbracelet/bubbletea" + "github.com/tolelom/catacombs/config" "github.com/tolelom/catacombs/game" "github.com/tolelom/catacombs/store" - "os" ) func testDB(t *testing.T) *store.DB { @@ -18,7 +19,7 @@ func testDB(t *testing.T) *store.DB { } func TestTitleToLobby(t *testing.T) { - lobby := game.NewLobby() + lobby := game.NewLobby(func() *config.Config { c, _ := config.Load(""); return c }()) db := testDB(t) defer func() { db.Close(); os.Remove("test_ui.db") }() @@ -55,7 +56,7 @@ func TestTitleToLobby(t *testing.T) { } func TestLobbyCreateRoom(t *testing.T) { - lobby := game.NewLobby() + lobby := game.NewLobby(func() *config.Config { c, _ := config.Load(""); return c }()) db := testDB(t) defer func() { db.Close(); os.Remove("test_ui.db") }() @@ -86,7 +87,7 @@ func TestLobbyCreateRoom(t *testing.T) { } func TestClassSelectToGame(t *testing.T) { - lobby := game.NewLobby() + lobby := game.NewLobby(func() *config.Config { c, _ := config.Load(""); return c }()) db := testDB(t) defer func() { db.Close(); os.Remove("test_ui.db") }()