-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathroom_table.go
More file actions
131 lines (107 loc) · 3.27 KB
/
room_table.go
File metadata and controls
131 lines (107 loc) · 3.27 KB
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
// Copyright (c) 2014 The WebRTC project authors. All Rights Reserved.
// Use of this source code is governed by a BSD-style license
// that can be found in the LICENSE file in the root of the source
// tree.
package collider
import (
"io"
"log"
"sync"
"time"
)
// A thread-safe map of rooms.
type roomTable struct {
lock sync.Mutex
rooms map[string]*room
registerTimeout time.Duration
roomSrvUrl string
}
func newRoomTable(to time.Duration, rs string) *roomTable {
return &roomTable{rooms: make(map[string]*room), registerTimeout: to, roomSrvUrl: rs}
}
// room returns the room specified by |id|, or creates the room if it does not exist.
func (rt *roomTable) room(id string) *room {
rt.lock.Lock()
defer rt.lock.Unlock()
return rt.roomLocked(id)
}
// roomLocked gets or creates the room without acquiring the lock. Used when the caller already acquired the lock.
func (rt *roomTable) roomLocked(id string) *room {
if r, ok := rt.rooms[id]; ok {
return r
}
rt.rooms[id] = newRoom(rt, id, rt.registerTimeout, rt.roomSrvUrl)
log.Printf("Created room %s", id)
return rt.rooms[id]
}
// remove removes the client. If the room becomes empty, it also removes the room.
func (rt *roomTable) remove(rid string, cid string) {
rt.lock.Lock()
defer rt.lock.Unlock()
rt.removeLocked(rid, cid)
}
// removeLocked removes the client without acquiring the lock. Used when the caller already acquired the lock.
func (rt *roomTable) removeLocked(rid string, cid string) {
if r := rt.rooms[rid]; r != nil {
r.remove(cid)
if r.empty() {
delete(rt.rooms, rid)
log.Printf("Removed room %s", rid)
}
}
}
// send forwards the message to the room. If the room does not exist, it will create one.
func (rt *roomTable) send(rid string, srcID string, msg string) error {
rt.lock.Lock()
defer rt.lock.Unlock()
r := rt.roomLocked(rid)
return r.send(srcID, msg)
}
// register forwards the register request to the room. If the room does not exist, it will create one.
func (rt *roomTable) register(rid string, cid string, rwc io.ReadWriteCloser) error {
rt.lock.Lock()
defer rt.lock.Unlock()
r := rt.roomLocked(rid)
return r.register(cid, rwc)
}
// deregister clears the client's websocket registration.
// We keep the client around until after a timeout, so that users roaming between networks can seamlessly reconnect.
func (rt *roomTable) deregister(rid string, cid string) {
rt.lock.Lock()
defer rt.lock.Unlock()
if r := rt.rooms[rid]; r != nil {
if c := r.clients[cid]; c != nil {
if c.registered() {
c.deregister()
c.setTimer(time.AfterFunc(rt.registerTimeout, func() {
rt.removeIfUnregistered(rid, c)
}))
log.Printf("Deregistered client %s from room %s", c.id, rid)
return
}
}
}
}
// removeIfUnregistered removes the client if it has not registered.
func (rt *roomTable) removeIfUnregistered(rid string, c *client) {
log.Printf("Removing client %s from room %s due to timeout", c.id, rid)
rt.lock.Lock()
defer rt.lock.Unlock()
if r := rt.rooms[rid]; r != nil {
if c == r.clients[c.id] {
if !c.registered() {
rt.removeLocked(rid, c.id)
return
}
}
}
}
func (rt *roomTable) wsCount() int {
rt.lock.Lock()
defer rt.lock.Unlock()
count := 0
for _, r := range rt.rooms {
count = count + r.wsCount()
}
return count
}