-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathconnectionPair.go
83 lines (75 loc) · 2.53 KB
/
connectionPair.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
package main
import (
"log"
"sync"
"time"
)
// timeoutBeforeReBroadcast sets the time in seconds after where we rebroadcast the gameState
// to all clients. This way we see if the opponent is still there
const timeoutBeforeReBroadcast = 5 //TODO: should probably be set higher in real world usages...
// timeoutBeforeConnectionDrop sets the time in seconds after after we drop a connection
// which is not answering
const timeoutBeforeConnectionDrop = 1
// connectionPair handles the update of the gameState between two players
type connectionPair struct {
// the mutex to protect connections
connectionsMx sync.RWMutex
// Registered connections.
connections map[*connection]struct{}
// Inbound messages from the connections.
receiveMove chan bool
logMx sync.RWMutex
log [][]byte
gs gameState
}
// newConnectionPair is the constructor for the connectionPair struct
func newConnectionPair() *connectionPair {
cp := &connectionPair{
connectionsMx: sync.RWMutex{},
receiveMove: make(chan bool),
connections: make(map[*connection]struct{}),
gs: newGameState(),
}
go func() {
for {
select {
//waiting for an update of one of the clients in the connection pair
case <-cp.receiveMove:
case <-time.After(timeoutBeforeReBroadcast * time.Second): //After x seconds we do broadcast again to see if the opp. is still there
}
cp.connectionsMx.RLock()
for c := range cp.connections {
select {
case c.doBroadcast <- true:
// stop trying to send to this connection after trying for 1 second.
// if we have to stop, it means that a reader died so remove the connection also.
case <-time.After(timeoutBeforeConnectionDrop * time.Second):
cp.removeConnection(c)
}
}
cp.connectionsMx.RUnlock()
}
}()
return cp
}
// addConnection adds a players connection to the connectionPair
func (h *connectionPair) addConnection(conn *connection) {
h.connectionsMx.Lock()
defer h.connectionsMx.Unlock()
// TODO: Should be checking if the same user gets paired to himself
// TODO: by reloading the page. We could achieve that with setting
// TODO: cookies to re-identify users
log.Println("connection", conn)
h.connections[conn] = struct{}{}
}
// removeConnection removes a players connection from the connectionPair
func (h *connectionPair) removeConnection(conn *connection) {
h.connectionsMx.Lock()
defer h.connectionsMx.Unlock()
if _, ok := h.connections[conn]; ok {
delete(h.connections, conn)
close(conn.doBroadcast)
}
log.Println("Player disconnected")
h.gs.resetGame()
}