commit 9573bf8ba659e0a5079281bc2a5cef9b6f4fbe97
parent d681f6144c0031731520c0a043bfb52d16da3cf2
Author: n0tr1v <n0tr1v@protonmail.com>
Date: Wed, 6 Dec 2023 05:23:31 -0500
data race
Diffstat:
1 file changed, 53 insertions(+), 13 deletions(-)
diff --git a/pkg/web/handlers/poker/poker.go b/pkg/web/handlers/poker/poker.go
@@ -73,15 +73,17 @@ type PlayerEvent struct {
var PokerInstance = NewPoker()
type Ongoing struct {
- Deck []string
- Players []*PokerPlayer
- Events []PokerEvent
- EventsMtx sync.RWMutex
- LogEvents []LogEvent
- LogEventsMtx sync.RWMutex
- CommunityCards []string
- WaitTurnEvent PokerWaitTurnEvent
- MainPot int
+ Deck []string
+ Players []*PokerPlayer
+ Events []PokerEvent
+ EventsMtx sync.RWMutex
+ LogEvents []LogEvent
+ LogEventsMtx sync.RWMutex
+ CommunityCards []string
+ WaitTurnEvent PokerWaitTurnEvent
+ WaitTurnEventMtx sync.RWMutex
+ MainPot int
+ MainPotMtx sync.RWMutex
}
type PokerStandingPlayer struct {
@@ -94,6 +96,7 @@ type PokerPlayer struct {
Bet int
Cash int
Cards []PlayerCard
+ CardsMtx sync.RWMutex
Folded bool
}
@@ -229,7 +232,10 @@ OUTER:
}
evt := PokerWaitTurnEvent{Idx: i}
PokerPubSub.Pub(roomTopic, evt)
+
+ g.Ongoing.WaitTurnEventMtx.Lock()
g.Ongoing.WaitTurnEvent = evt
+ g.Ongoing.WaitTurnEventMtx.Unlock()
// Maximum time allowed for the player to send his action
waitCh := time.After(MaxUserCountdown * time.Second)
@@ -250,8 +256,10 @@ OUTER:
if p.Bet < minBet {
player.Folded = true
+ player.CardsMtx.RLock()
evt1 := PokerEvent{ID: "card" + itoa(player.Cards[0].Idx), Name: "", Idx: player.Cards[0].Idx, Top: BurnStackY, Left: BurnStackX, Reveal: false}
evt2 := PokerEvent{ID: "card" + itoa(player.Cards[1].Idx), Name: "", Idx: player.Cards[1].Idx, Top: BurnStackY, Left: BurnStackX, Reveal: false}
+ player.CardsMtx.RUnlock()
PokerPubSub.Pub(roomTopic, evt1)
PokerPubSub.Pub(roomTopic, evt2)
g.Ongoing.AddEvent(evt1, evt2)
@@ -341,19 +349,27 @@ OUTER:
evt := PokerWaitTurnEvent{Idx: -1}
PokerPubSub.Pub(roomTopic, evt)
+
+ g.Ongoing.WaitTurnEventMtx.Lock()
g.Ongoing.WaitTurnEvent = evt
+ g.Ongoing.WaitTurnEventMtx.Unlock()
time.Sleep(time.Second)
// Transfer players bets into the main pot
for i := range g.Ongoing.Players {
if g.Ongoing.Players[i] != nil {
+ g.Ongoing.MainPotMtx.Lock()
g.Ongoing.MainPot += g.Ongoing.Players[i].Bet
+ g.Ongoing.MainPotMtx.Unlock()
g.Ongoing.Players[i].Bet = 0
}
}
- PokerPubSub.Pub(roomTopic, PokerMainPotUpdatedEvent{MainPot: g.Ongoing.MainPot})
+ g.Ongoing.MainPotMtx.RLock()
+ mainPot := g.Ongoing.MainPot
+ g.Ongoing.MainPotMtx.RUnlock()
+ PokerPubSub.Pub(roomTopic, PokerMainPotUpdatedEvent{MainPot: mainPot})
return playerAlive == 1
}
@@ -450,7 +466,10 @@ func dealerThread(g *PokerGame, roomID string) {
PokerPubSub.Pub(roomTopic, evt)
PokerPubSub.Pub(roomTopic+"_"+p.Username, YourCardEvent{Idx: cardIdx, Name: card})
+ g.Ongoing.Players[i].CardsMtx.Lock()
g.Ongoing.Players[i].Cards = append(g.Ongoing.Players[i].Cards, PlayerCard{Idx: idx, Name: card})
+ g.Ongoing.Players[i].CardsMtx.Unlock()
+
g.Ongoing.AddEvent(evt)
}
}
@@ -508,8 +527,10 @@ func dealerThread(g *PokerGame, roomID string) {
// Show cards
for idx, p := range g.Ongoing.Players {
if p != nil && !p.Folded {
+ p.CardsMtx.RLock()
evt1 := PokerEvent{ID: "card" + itoa(p.Cards[0].Idx), Name: p.Cards[0].Name, Idx: p.Cards[0].Idx, Top: seats[idx].Top, Left: seats[idx].Left, Reveal: true}
evt2 := PokerEvent{ID: "card" + itoa(p.Cards[1].Idx), Name: p.Cards[1].Name, Idx: p.Cards[1].Idx, Top: seats[idx].Top, Left: seats[idx].Left + 53, Reveal: true}
+ p.CardsMtx.RUnlock()
PokerPubSub.Pub(roomTopic, evt1)
PokerPubSub.Pub(roomTopic, evt2)
g.Ongoing.AddEvent(evt1, evt2)
@@ -518,14 +539,20 @@ func dealerThread(g *PokerGame, roomID string) {
for _, p := range g.Ongoing.Players {
if p != nil {
+
+ p.CardsMtx.RLock()
+ playerCard1 := p.Cards[0].Name
+ playerCard2 := p.Cards[1].Name
+ p.CardsMtx.RUnlock()
+
hand := []poker.Card{
poker.NewCard(cardToPokerCard(g.Ongoing.CommunityCards[0])),
poker.NewCard(cardToPokerCard(g.Ongoing.CommunityCards[1])),
poker.NewCard(cardToPokerCard(g.Ongoing.CommunityCards[2])),
poker.NewCard(cardToPokerCard(g.Ongoing.CommunityCards[3])),
poker.NewCard(cardToPokerCard(g.Ongoing.CommunityCards[4])),
- poker.NewCard(cardToPokerCard(p.Cards[0].Name)),
- poker.NewCard(cardToPokerCard(p.Cards[1].Name)),
+ poker.NewCard(cardToPokerCard(playerCard1)),
+ poker.NewCard(cardToPokerCard(playerCard2)),
}
e := poker.Evaluate(hand)
// TODO: handle split pot
@@ -549,8 +576,15 @@ END:
}
}
- winner.Cash += g.Ongoing.MainPot
+ g.Ongoing.MainPotMtx.RLock()
+ mainPot := g.Ongoing.MainPot
+ g.Ongoing.MainPotMtx.RUnlock()
+
+ winner.Cash += mainPot
+
+ g.Ongoing.MainPotMtx.Lock()
g.Ongoing.MainPot = 0
+ g.Ongoing.MainPotMtx.Unlock()
// Sync "ongoing players" with "room players" objects
for idx := range g.Players {
@@ -774,7 +808,9 @@ func buildYourCardsHtml(authUser *database.User, g *PokerGame) string {
if g.Ongoing != nil {
cards := make([]PlayerCard, 0)
if p := g.Ongoing.GetPlayer(authUser.Username.String()); p != nil {
+ p.CardsMtx.RLock()
cards = p.Cards
+ p.CardsMtx.RUnlock()
}
html += `<style>`
if len(cards) >= 1 {
@@ -811,7 +847,9 @@ func buildMainPotHtml(g *PokerGame) string {
html := `<div id="mainPot"></div>`
mainPot := 0
if g.Ongoing != nil {
+ g.Ongoing.MainPotMtx.RLock()
mainPot = g.Ongoing.MainPot
+ g.Ongoing.MainPotMtx.RUnlock()
}
html += `<style>#mainPot:before { content: "Pot: ` + itoa(mainPot) + `"; }</style>`
return html
@@ -1282,7 +1320,9 @@ func PokerHandler(c echo.Context) error {
send(`<div id="deckHash"></div>`)
if g.Ongoing != nil {
+ g.Ongoing.WaitTurnEventMtx.RLock()
send(drawCountDownStyle(g.Ongoing.WaitTurnEvent))
+ g.Ongoing.WaitTurnEventMtx.RUnlock()
send(`<style>#deckHash:before { content: "` + g.Ongoing.GetDeckHash() + `"; }</style>`)
if g.IsGameDone {
send(`<style>#deckStr:before { content: "` + g.Ongoing.GetDeckStr() + `"; }</style>`)