/
room.go
133 lines (114 loc) · 2.63 KB
/
room.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
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
package websocket
import (
"context"
"math/rand"
"sync"
"github.com/go-kit/kit/log/level"
)
type room struct {
Clients []*client
ClientLock sync.Mutex
ID int
}
func newRoom(id int) *room {
return &room{
Clients: make([]*client, 0, 2),
ID: id,
}
}
func (r *room) broadcast(message messageFrame) {
r.ClientLock.Lock()
for _, client := range r.Clients {
client.Send <- message
}
r.ClientLock.Unlock()
}
// RemoveClientFromRoom removes the client with the spcified id from the room.
// If the client or the room doesn't exist this function does nothing.
func (s *Server) RemoveClientFromRoom(roomNumber int, userID int) {
s.rooms.RLock()
room, ok := s.rooms.m[roomNumber]
s.rooms.RUnlock()
if !ok {
return
}
room.ClientLock.Lock()
defer room.ClientLock.Unlock()
clientIndex := -1
for i, c := range room.Clients {
if c.id == userID {
clientIndex = i
break
}
}
if clientIndex == -1 {
return
}
room.Clients[clientIndex] = room.Clients[len(room.Clients)-1]
room.Clients = room.Clients[:len(room.Clients)-1]
}
// AddRoom adds a new room to the room map.
func (s *Server) AddRoom(roomNumber int, initialClientID int) {
s.rooms.RLock()
_, ok := s.rooms.m[roomNumber]
s.rooms.RUnlock()
if ok {
return
}
room := newRoom(roomNumber)
s.rooms.Lock()
s.rooms.m[roomNumber] = room
s.rooms.Unlock()
clients.RLock()
client, ok := clients.m[initialClientID]
clients.RUnlock()
if ok {
room.ClientLock.Lock()
room.Clients = append(room.Clients, client)
room.ClientLock.Unlock()
}
}
func (s *Server) RemoveRoom(roomNumber int) {
s.rooms.Lock()
delete(s.rooms.m, roomNumber)
s.rooms.Unlock()
}
// JoinRoom adds a client to a room
// If either the room or the client does not exist, nothing is done.
func (s *Server) JoinRoom(roomNumber int, userID int) {
s.rooms.RLock()
room, ok := s.rooms.m[roomNumber]
s.rooms.RUnlock()
if !ok {
return
}
clients.RLock()
client, ok := clients.m[userID]
clients.RUnlock()
if !ok {
return
}
room.ClientLock.Lock()
room.Clients = append(room.Clients, client)
room.ClientLock.Unlock()
}
// BroadcastToRoom sends a RESTCommand with payload to every member of the
// specified room.
func (s *Server) BroadcastToRoom(roomNumber int, payload interface{}, ctx context.Context) {
command := ctx.Value("command").(RESTCommand)
id := ctx.Value("id").(int)
if id == -1 {
id = rand.Int()
}
s.rooms.RLock()
room, ok := s.rooms.m[roomNumber]
s.rooms.RUnlock()
if ok {
room.broadcast(newFrame(roomNumber, id, command, payload))
} else {
level.Warn(s.logger).Log(
"Function", "BroadcastToRoom",
"roomNumber", roomNumber,
"err", "No such room")
}
}