Skip to content

Commit

Permalink
better support for multi-table
Browse files Browse the repository at this point in the history
  • Loading branch information
ardan-bkennedy committed Jan 26, 2024
1 parent 159490c commit d2c5c2b
Show file tree
Hide file tree
Showing 13 changed files with 273 additions and 242 deletions.
2 changes: 2 additions & 0 deletions app/cli/liars/board/keyboard.go
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,8 @@ func (b *Board) newGame() error {

b.lastStatus = status

b.drawInit(true)

return nil
}

Expand Down
5 changes: 4 additions & 1 deletion app/cli/liars/engine/engine.go
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,10 @@ func (e *Engine) Events(f func(event string, address common.Address)) (func(), e
url := strings.Replace(e.url, "http", "ws", 1)
url = fmt.Sprintf("%s/v1/game/events", url)

socket, _, err := websocket.DefaultDialer.Dial(url, nil)
req := make(http.Header)
req.Add("authorization", fmt.Sprintf("Bearer %s", e.token))

socket, _, err := websocket.DefaultDialer.Dial(url, req)
if err != nil {
return nil, fmt.Errorf("dial: %w", err)
}
Expand Down
8 changes: 0 additions & 8 deletions app/services/engine/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@ import (
"github.com/ardanlabs/liarsdice/business/web/v1/auth"
"github.com/ardanlabs/liarsdice/business/web/v1/debug"
"github.com/ardanlabs/liarsdice/business/web/v1/mux"
"github.com/ardanlabs/liarsdice/foundation/events"
"github.com/ardanlabs/liarsdice/foundation/keystore"
"github.com/ardanlabs/liarsdice/foundation/logger"
"github.com/ardanlabs/liarsdice/foundation/web"
Expand Down Expand Up @@ -190,8 +189,6 @@ func run(ctx context.Context, log *logger.Logger) error {
oneETHToUSD, oneUSDToETH := converter.Values()
log.Info(ctx, "currency values", "oneETHToUSD", oneETHToUSD, "oneUSDToETH", oneUSDToETH)

evts := events.New()

ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()

Expand Down Expand Up @@ -242,7 +239,6 @@ func run(ctx context.Context, log *logger.Logger) error {
Auth: authClient,
Converter: converter,
Bank: bankClient,
Evts: evts,
AnteUSD: cfg.Game.AnteUSD,
ActiveKID: cfg.Auth.ActiveKID,
BankTimeout: cfg.Bank.Timeout,
Expand Down Expand Up @@ -276,10 +272,6 @@ func run(ctx context.Context, log *logger.Logger) error {
log.Info(ctx, "shutdown", "status", "shutdown started", "signal", sig)
defer log.Info(ctx, "shutdown", "status", "shutdown complete", "signal", sig)

// Release any web sockets that are currently active.
log.Info(ctx, "shutdown", "status", "shutdown web socket channels")
evts.Shutdown()

ctx, cancel := context.WithTimeout(context.Background(), cfg.Web.ShutdownTimeout)
defer cancel()

Expand Down
1 change: 0 additions & 1 deletion app/services/engine/v1/build/all/all.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@ func (add) Add(app *web.App, cfg mux.Config) {
Auth: cfg.Auth,
Converter: cfg.Converter,
Bank: cfg.Bank,
Evts: cfg.Evts,
AnteUSD: cfg.AnteUSD,
ActiveKID: cfg.ActiveKID,
BankTimeout: cfg.BankTimeout,
Expand Down
136 changes: 136 additions & 0 deletions app/services/engine/v1/handlers/gamegrp/events.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
package gamegrp

import (
"fmt"
"sync"
)

// These types exist for documentation purposes. The API will
// will accept a string.
type (
gameID string
playerID string
)

// evts maintains the set player channels for sending messages over
// the players web socket.
var evts = newEvents()

// events maintains a mapping of unique id and channels so goroutines
// can register and receive events.
type events struct {
players map[playerID]chan string
games map[gameID]map[playerID]struct{}
mu sync.RWMutex
}

func newEvents() *events {
return &events{
players: make(map[playerID]chan string),
games: make(map[gameID]map[playerID]struct{}),
}
}

func (evt *events) acquire(pID string) chan string {
evt.mu.Lock()
defer evt.mu.Unlock()

// Since a message will be dropped if the websocket receiver is
// not ready to receive, this arbitrary buffer should give the receiver
// enough time to not lose a message. Websocket send could take long.
const messageBuffer = 100

playID := playerID(pID)

ch, exists := evt.players[playID]
if !exists {
ch = make(chan string, messageBuffer)
evt.players[playID] = ch
}

return ch
}

func (evt *events) release(pID string) error {
evt.mu.Lock()
defer evt.mu.Unlock()

playID := playerID(pID)

ch, exists := evt.players[playID]
if !exists {
return fmt.Errorf("player id %q does not exist", pID)
}

delete(evt.players, playID)
close(ch)

return nil
}

func (evt *events) addPlayerToGame(gID string, pID string) error {
evt.mu.Lock()
defer evt.mu.Unlock()

gameID := gameID(gID)
playID := playerID(pID)

if _, exists := evt.players[playID]; !exists {
return fmt.Errorf("player id %q does not exist", pID)
}

playerMap, exists := evt.games[gameID]
if !exists {
playerMap = make(map[playerID]struct{})
evt.games[gameID] = playerMap
}

playerMap[playID] = struct{}{}

return nil
}

func (evt *events) removePlayersFromGame(gID string) error {
evt.mu.Lock()
defer evt.mu.Unlock()

gameID := gameID(gID)

playerMap, exists := evt.games[gameID]
if !exists {
return nil
}

for playID := range playerMap {
delete(playerMap, playID)
}
delete(evt.games, gameID)

return nil
}

// send signals a message to every registered channel for the specified
// game. Send will not block waiting for a receiver on any given channel.
func (evt *events) send(gID string, s string) {
evt.mu.RLock()
defer evt.mu.RUnlock()

gameID := gameID(gID)

playerMap, exists := evt.games[gameID]
if !exists {
return
}

for playID := range playerMap {
ch, exists := evt.players[playID]
if !exists {
continue
}

select {
case ch <- s:
default:
}
}
}
Loading

0 comments on commit d2c5c2b

Please sign in to comment.