Alow embedding server

This commit is contained in:
Trevor Slocum 2023-11-30 13:17:30 -08:00
parent 3286105c9c
commit 817f86dcf9
10 changed files with 117 additions and 83 deletions

View file

@ -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++

View file

@ -1,4 +1,4 @@
package main
package server
type account struct {
id int

View file

@ -1,4 +1,4 @@
package main
package server
import (
"bytes"

View file

@ -1,4 +1,4 @@
package main
package server
import (
"bufio"

View file

@ -1,4 +1,4 @@
package main
package server
import (
"bytes"

View file

@ -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

View file

@ -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
}

View file

@ -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
}

View file

@ -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

View file

@ -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)