dkforest

A forum and chat platform (onion)
git clone https://git.dasho.dev/n0tr1v/dkforest.git
Log | Files | Refs | LICENSE

commit 9573bf8ba659e0a5079281bc2a5cef9b6f4fbe97
parent d681f6144c0031731520c0a043bfb52d16da3cf2
Author: n0tr1v <n0tr1v@protonmail.com>
Date:   Wed,  6 Dec 2023 05:23:31 -0500

data race

Diffstat:
Mpkg/web/handlers/poker/poker.go | 66+++++++++++++++++++++++++++++++++++++++++++++++++++++-------------
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>`)