diff --git a/cmd/bgammon-server/main.go b/cmd/bgammon-server/main.go index 87327ee..9ef047f 100644 --- a/cmd/bgammon-server/main.go +++ b/cmd/bgammon-server/main.go @@ -7,6 +7,8 @@ import ( "net/http" _ "net/http/pprof" "os" + + "code.rocket9labs.com/tslocum/bgammon/pkg/server" ) func main() { @@ -47,16 +49,12 @@ func main() { }() } - if debugCommands { - allowDebugCommands = debugCommands - } - - s := newServer(tz, dataSource) + s := server.NewServer(tz, dataSource, debugCommands) if tcpAddress != "" { - s.listen("tcp", tcpAddress) + s.Listen("tcp", tcpAddress) } if wsAddress != "" { - s.listen("ws", wsAddress) + s.Listen("ws", wsAddress) } select {} } @@ -67,8 +65,8 @@ func printRollStatistics() { total := 1000000 for i := 0; i < total; i++ { - roll1 := randInt(6) + 1 - roll2 := randInt(6) + 1 + roll1 := server.RandInt(6) + 1 + roll2 := server.RandInt(6) + 1 if roll1 == lastroll1 || roll1 == lastroll2 || roll2 == lastroll1 || roll2 == lastroll2 { oneSame++ diff --git a/cmd/bgammon-server/account.go b/pkg/server/account.go similarity index 78% rename from cmd/bgammon-server/account.go rename to pkg/server/account.go index 8247d0b..3aca9e4 100644 --- a/cmd/bgammon-server/account.go +++ b/pkg/server/account.go @@ -1,4 +1,4 @@ -package main +package server type account struct { id int diff --git a/cmd/bgammon-server/client.go b/pkg/server/client.go similarity index 99% rename from cmd/bgammon-server/client.go rename to pkg/server/client.go index acde38f..eb6db74 100644 --- a/cmd/bgammon-server/client.go +++ b/pkg/server/client.go @@ -1,4 +1,4 @@ -package main +package server import ( "bytes" diff --git a/cmd/bgammon-server/client_socket.go b/pkg/server/client_socket.go similarity index 99% rename from cmd/bgammon-server/client_socket.go rename to pkg/server/client_socket.go index cce1038..15244cb 100644 --- a/cmd/bgammon-server/client_socket.go +++ b/pkg/server/client_socket.go @@ -1,4 +1,4 @@ -package main +package server import ( "bufio" diff --git a/cmd/bgammon-server/client_websocket.go b/pkg/server/client_websocket.go similarity index 99% rename from cmd/bgammon-server/client_websocket.go rename to pkg/server/client_websocket.go index c134e2f..40b4988 100644 --- a/cmd/bgammon-server/client_websocket.go +++ b/pkg/server/client_websocket.go @@ -1,4 +1,4 @@ -package main +package server import ( "bytes" diff --git a/cmd/bgammon-server/database.go b/pkg/server/database.go similarity index 84% rename from cmd/bgammon-server/database.go rename to pkg/server/database.go index a08c311..ee1ad68 100644 --- a/cmd/bgammon-server/database.go +++ b/pkg/server/database.go @@ -1,4 +1,6 @@ -package main +//go:build database + +package server import ( "context" @@ -23,16 +25,15 @@ CREATE TABLE game ( ); ` -func connectDB(dataSource string) (*pgx.Conn, error) { +var db *pgx.Conn + +func connectDB(dataSource string) error { var err error - db, err := pgx.Connect(context.Background(), dataSource) - if err != nil { - return nil, err - } - return db, nil + db, err = pgx.Connect(context.Background(), dataSource) + return err } -func begin(db *pgx.Conn) (pgx.Tx, error) { +func begin() (pgx.Tx, error) { tx, err := db.Begin(context.Background()) if err != nil { return nil, err @@ -45,12 +46,12 @@ func begin(db *pgx.Conn) (pgx.Tx, error) { return tx, nil } -func testDBConnection(db *pgx.Conn) error { +func testDBConnection() error { _, err := db.Exec(context.Background(), "SELECT 1=1") return err } -func initDB(db *pgx.Conn) { +func initDB() { tx, err := begin(db) if err != nil { log.Fatalf("failed to initialize database: %s", err) @@ -72,8 +73,8 @@ func initDB(db *pgx.Conn) { log.Println("Initialized database schema") } -func recordGameResult(conn *pgx.Conn, g *bgammon.Game, winType int) error { - if g.Started.IsZero() || g.Ended.IsZero() || g.Winner == 0 { +func recordGameResult(g *bgammon.Game, winType int) error { + if db == nil || g.Started.IsZero() || g.Ended.IsZero() || g.Winner == 0 { return nil } @@ -91,16 +92,7 @@ func recordGameResult(conn *pgx.Conn, g *bgammon.Game, winType int) error { return err } -type serverStatsEntry struct { - Date string - Games int -} - -type serverStatsResult struct { - History []*serverStatsEntry -} - -func serverStats(conn *pgx.Conn, tz *time.Location) (*serverStatsResult, error) { +func serverStats(tz *time.Location) (*serverStatsResult, error) { tx, err := begin(conn) if err != nil { return nil, err @@ -155,18 +147,7 @@ func serverStats(conn *pgx.Conn, tz *time.Location) (*serverStatsResult, error) return result, nil } -type wildBGStatsEntry struct { - Date string - Percent float64 - Wins int - Losses int -} - -type wildBGStatsResult struct { - History []*wildBGStatsEntry -} - -func wildBGStats(conn *pgx.Conn, tz *time.Location) (*wildBGStatsResult, error) { +func wildBGStats(tz *time.Location) (*wildBGStatsResult, error) { tx, err := begin(conn) if err != nil { return nil, err diff --git a/pkg/server/database_common.go b/pkg/server/database_common.go new file mode 100644 index 0000000..b79bf4d --- /dev/null +++ b/pkg/server/database_common.go @@ -0,0 +1,21 @@ +package server + +type serverStatsEntry struct { + Date string + Games int +} + +type serverStatsResult struct { + History []*serverStatsEntry +} + +type wildBGStatsEntry struct { + Date string + Percent float64 + Wins int + Losses int +} + +type wildBGStatsResult struct { + History []*wildBGStatsEntry +} diff --git a/pkg/server/database_disabled.go b/pkg/server/database_disabled.go new file mode 100644 index 0000000..c9d309e --- /dev/null +++ b/pkg/server/database_disabled.go @@ -0,0 +1,32 @@ +//go:build !database + +package server + +import ( + "time" + + "code.rocket9labs.com/tslocum/bgammon" +) + +func connectDB(dataSource string) error { + return nil +} + +func testDBConnection() error { + return nil +} + +func initDB() { +} + +func recordGameResult(g *bgammon.Game, winType int) error { + return nil +} + +func serverStats(tz *time.Location) (*serverStatsResult, error) { + return &serverStatsResult{}, nil +} + +func wildBGStats(tz *time.Location) (*wildBGStatsResult, error) { + return &wildBGStatsResult{}, nil +} diff --git a/cmd/bgammon-server/game.go b/pkg/server/game.go similarity index 98% rename from cmd/bgammon-server/game.go rename to pkg/server/game.go index 6bccd84..f58a906 100644 --- a/cmd/bgammon-server/game.go +++ b/pkg/server/game.go @@ -1,4 +1,4 @@ -package main +package server import ( "bufio" @@ -45,12 +45,12 @@ func (g *serverGame) roll(player int) bool { if g.Roll1 != 0 { return false } - g.Roll1 = randInt(6) + 1 + g.Roll1 = RandInt(6) + 1 } else { if g.Roll2 != 0 { return false } - g.Roll2 = randInt(6) + 1 + g.Roll2 = RandInt(6) + 1 } if g.Started.IsZero() { @@ -66,8 +66,8 @@ func (g *serverGame) roll(player int) bool { return false } - g.Roll1 = randInt(6) + 1 - g.Roll2 = randInt(6) + 1 + g.Roll1 = RandInt(6) + 1 + g.Roll2 = RandInt(6) + 1 return true } @@ -249,7 +249,7 @@ func (g *serverGame) addClient(client *serverClient) (spectator bool) { client.playerNumber = 1 playerNumber = 1 default: - if randInt(2) == 0 { + if RandInt(2) == 0 { g.client1 = client g.Player1.Name = string(client.name) client.playerNumber = 1 diff --git a/cmd/bgammon-server/server.go b/pkg/server/server.go similarity index 97% rename from cmd/bgammon-server/server.go rename to pkg/server/server.go index 85d8e5e..5cb3570 100644 --- a/cmd/bgammon-server/server.go +++ b/pkg/server/server.go @@ -1,4 +1,4 @@ -package main +package server import ( "bytes" @@ -16,7 +16,6 @@ import ( "time" "code.rocket9labs.com/tslocum/bgammon" - "github.com/jackc/pgx/v5" ) const clientTimeout = 40 * time.Second @@ -50,11 +49,9 @@ type server struct { gamesCacheLock sync.Mutex tz *time.Location - - db *pgx.Conn } -func newServer(tz string, dataSource string) *server { +func NewServer(tz string, dataSource string, allowDebug bool) *server { const bufferSize = 10 s := &server{ newGameIDs: make(chan int), @@ -74,22 +71,23 @@ func newServer(tz string, dataSource string) *server { } if dataSource != "" { - var err error - s.db, err = connectDB(dataSource) + err := connectDB(dataSource) if err != nil { log.Fatalf("failed to connect to database: %s", err) } - err = testDBConnection(s.db) + err = testDBConnection() if err != nil { log.Fatalf("failed to test database connection: %s", err) } - initDB(s.db) + initDB() log.Println("Connected to database successfully") } + allowDebugCommands = allowDebug + go s.handleNewGameIDs() go s.handleNewClientIDs() go s.handleCommands() @@ -136,12 +134,9 @@ func (s *server) handleListMatches(w http.ResponseWriter, r *http.Request) { } func (s *server) handlePrintStats(w http.ResponseWriter, r *http.Request) { - if s.db == nil { - return - } w.Header().Set("Content-Type", "application/json") - stats, err := serverStats(s.db, s.tz) + stats, err := serverStats(s.tz) if err != nil { log.Fatalf("failed to fetch server statistics: %s", err) } @@ -153,12 +148,9 @@ func (s *server) handlePrintStats(w http.ResponseWriter, r *http.Request) { } func (s *server) handlePrintWildBGStats(w http.ResponseWriter, r *http.Request) { - if s.db == nil { - return - } w.Header().Set("Content-Type", "application/json") - stats, err := wildBGStats(s.db, s.tz) + stats, err := wildBGStats(s.tz) if err != nil { log.Fatalf("failed to fetch wildbg statistics: %s", err) } @@ -205,7 +197,21 @@ func (s *server) listenWebSocket(address string) { log.Fatalf("failed to listen on %s: %s", address, err) } -func (s *server) listen(network string, address string) { +func (s *server) handleLocal(conns chan net.Conn) { + for { + local, remote := net.Pipe() + conns <- local + go s.handleConnection(remote) + } +} + +func (s *server) ListenLocal() chan net.Conn { + conns := make(chan net.Conn) + go s.handleLocal(conns) + return conns +} + +func (s *server) Listen(network string, address string) { if strings.ToLower(network) == "ws" { go s.listenWebSocket(address) return @@ -380,7 +386,7 @@ func (s *server) handleNewClientIDs() { // randomUsername returns a random guest username, and assumes clients are already locked. func (s *server) randomUsername() []byte { for { - name := []byte(fmt.Sprintf("Guest%d", 100+randInt(900))) + name := []byte(fmt.Sprintf("Guest%d", 100+RandInt(900))) if s.clientByUsername(name) == nil { return name @@ -864,11 +870,9 @@ COMMANDS: winEvent.Player = clientGame.Player2.Name } - if s.db != nil { - err := recordGameResult(s.db, clientGame.Game, 4) - if err != nil { - log.Fatalf("failed to record game result: %s", err) - } + err := recordGameResult(clientGame.Game, 4) + if err != nil { + log.Fatalf("failed to record game result: %s", err) } } clientGame.eachClient(func(client *serverClient) { @@ -1094,11 +1098,9 @@ COMMANDS: } } - if s.db != nil { - err := recordGameResult(s.db, clientGame.Game, winPoints) - if err != nil { - log.Fatalf("failed to record game result: %s", err) - } + err := recordGameResult(clientGame.Game, winPoints) + if err != nil { + log.Fatalf("failed to record game result: %s", err) } } @@ -1357,7 +1359,7 @@ COMMANDS: } } -func randInt(max int) int { +func RandInt(max int) int { i, err := rand.Int(rand.Reader, big.NewInt(int64(max))) if err != nil { panic(err)