-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathscorekeeper.go
110 lines (92 loc) · 2.89 KB
/
scorekeeper.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
package main
import (
"fmt"
"sync"
"time"
)
// ScoreUpdate response sent back
type ScoreUpdate struct {
CurrentScore Score `json:"currentScore"`
LastScore LastScore `json:"lastScore"`
}
// Score keep track of the scores
type Score struct {
Blue int `json:"blue"`
Red int `json:"red"`
}
// LastScore keeps track of the last game score
type LastScore struct {
Score Score `json:"score"`
Timestamp time.Time `json:"timestamp"`
Displayable bool `json:"displayable"`
}
// ScoreKeeper contains score keeping logic
type ScoreKeeper struct {
Blue int `json:"blue"`
Red int `json:"red"`
subscribers []chan ScoreUpdate
mutex sync.Mutex
lastScore LastScore
}
// ResetScore resets the score
func (currentScore *ScoreKeeper) ResetScore() {
currentScore.Red = 0
currentScore.Blue = 0
go currentScore.broadcast()
}
// UpdateScore increments the current score
func (currentScore *ScoreKeeper) UpdateScore(addScore Score) {
currentScore.Red += addScore.Red
currentScore.Blue += addScore.Blue
if currentScore.Red >= 10 || currentScore.Blue >= 10 {
currentScore.lastScore = LastScore{Score{currentScore.Blue, currentScore.Red}, time.Now(), true}
currentScore.Red = 0
currentScore.Blue = 0
}
go currentScore.broadcast()
}
/*
Send message to each subscriber with current score
*/
func (currentScore *ScoreKeeper) broadcast() {
for _, subscriber := range currentScore.subscribers {
score := Score{Red: currentScore.Red, Blue: currentScore.Blue}
subscriber <- ScoreUpdate{CurrentScore: score, LastScore: currentScore.lastScore}
}
}
// Subscribe Create new channel, add to subscriber list synchronously and then send current score to the channel (async)
func (currentScore *ScoreKeeper) Subscribe() chan ScoreUpdate {
c := make(chan ScoreUpdate)
currentScore.mutex.Lock()
currentScore.subscribers = append(currentScore.subscribers, c)
currentScore.mutex.Unlock()
go func() {
score := Score{Red: currentScore.Red, Blue: currentScore.Blue}
c <- ScoreUpdate{CurrentScore: score, LastScore: currentScore.lastScore}
}()
return c
}
// Unsubscribe Search the channel c between the subscribers synchronously, close it and remove it
func (currentScore *ScoreKeeper) Unsubscribe(c chan ScoreUpdate) {
go func() {
var foundIndex int
var found = false
currentScore.mutex.Lock()
for index, subscriber := range currentScore.subscribers {
if subscriber == c {
found = true
foundIndex = index
close(c)
}
}
if found {
currentScore.subscribers = append(currentScore.subscribers[:foundIndex], currentScore.subscribers[foundIndex+1:]...)
}
currentScore.mutex.Unlock()
fmt.Printf("Removed index: %d, %d remaining subscribers.\n", foundIndex, len(currentScore.subscribers))
}()
}
// ScoreKeeperBuilder Scorekeeper "class" constructor
func ScoreKeeperBuilder() ScoreKeeper {
return ScoreKeeper{0, 0, []chan ScoreUpdate{}, sync.Mutex{}, LastScore{}}
}