gosocketio/vendor/github.com/googollee/go-socket.io/broadcast.go

168 lines
4.6 KiB
Go

package socketio
import "sync"
// EachFunc typed for each callback function
type EachFunc func(Conn)
// Broadcast is the adaptor to handle broadcasts & rooms for socket.io server API
type Broadcast interface {
Join(room string, connection Conn) // Join causes the connection to join a room
Leave(room string, connection Conn) // Leave causes the connection to leave a room
LeaveAll(connection Conn) // LeaveAll causes given connection to leave all rooms
Clear(room string) // Clear causes removal of all connections from the room
Send(room, event string, args ...interface{}) // Send will send an event with args to the room
SendAll(event string, args ...interface{}) // SendAll will send an event with args to all the rooms
ForEach(room string, f EachFunc) // ForEach sends data by DataFunc, if room does not exits sends nothing
Len(room string) int // Len gives number of connections in the room
Rooms(connection Conn) []string // Gives list of all the rooms if no connection given, else list of all the rooms the connection joined
AllRooms() []string // Gives list of all the rooms the connection joined
}
// broadcast gives Join, Leave & BroadcastTO server API support to socket.io along with room management
// map of rooms where each room contains a map of connection id to connections in that room
type broadcast struct {
rooms map[string]map[string]Conn
lock sync.RWMutex
}
// newBroadcast creates a new broadcast adapter
func newBroadcast() *broadcast {
return &broadcast{
rooms: make(map[string]map[string]Conn),
}
}
// Join joins the given connection to the broadcast room
func (bc *broadcast) Join(room string, connection Conn) {
bc.lock.Lock()
defer bc.lock.Unlock()
if _, ok := bc.rooms[room]; !ok {
bc.rooms[room] = make(map[string]Conn)
}
bc.rooms[room][connection.ID()] = connection
}
// Leave leaves the given connection from given room (if exist)
func (bc *broadcast) Leave(room string, connection Conn) {
bc.lock.Lock()
defer bc.lock.Unlock()
if connections, ok := bc.rooms[room]; ok {
delete(connections, connection.ID())
if len(connections) == 0 {
delete(bc.rooms, room)
}
}
}
// LeaveAll leaves the given connection from all rooms
func (bc *broadcast) LeaveAll(connection Conn) {
bc.lock.Lock()
defer bc.lock.Unlock()
for room, connections := range bc.rooms {
delete(connections, connection.ID())
if len(connections) == 0 {
delete(bc.rooms, room)
}
}
}
// Clear clears the room
func (bc *broadcast) Clear(room string) {
bc.lock.Lock()
defer bc.lock.Unlock()
delete(bc.rooms, room)
}
// Send sends given event & args to all the connections in the specified room
func (bc *broadcast) Send(room, event string, args ...interface{}) {
bc.lock.RLock()
defer bc.lock.RUnlock()
for _, connection := range bc.rooms[room] {
connection.Emit(event, args...)
}
}
// SendAll sends given event & args to all the connections to all the rooms
func (bc *broadcast) SendAll(event string, args ...interface{}) {
bc.lock.RLock()
defer bc.lock.RUnlock()
for _, connections := range bc.rooms {
for _, connection := range connections {
connection.Emit(event, args...)
}
}
}
// ForEach sends data returned by DataFunc, if room does not exits sends nothing
func (bc *broadcast) ForEach(room string, f EachFunc) {
bc.lock.RLock()
defer bc.lock.RUnlock()
occupants, ok := bc.rooms[room]
if !ok {
return
}
for _, connection := range occupants {
f(connection)
}
}
// Len gives number of connections in the room
func (bc *broadcast) Len(room string) int {
bc.lock.RLock()
defer bc.lock.RUnlock()
return len(bc.rooms[room])
}
// Rooms gives the list of all the rooms available for broadcast in case of
// no connection is given, in case of a connection is given, it gives
// list of all the rooms the connection is joined to
func (bc *broadcast) Rooms(connection Conn) []string {
if connection == nil {
return bc.AllRooms()
}
bc.lock.RLock()
defer bc.lock.RUnlock()
return bc.getRoomsByConn(connection)
}
// AllRooms gives list of all rooms available for broadcast
func (bc *broadcast) AllRooms() []string {
bc.lock.RLock()
defer bc.lock.RUnlock()
rooms := make([]string, 0, len(bc.rooms))
for room := range bc.rooms {
rooms = append(rooms, room)
}
return rooms
}
func (bc *broadcast) getRoomsByConn(connection Conn) []string {
var rooms []string
for room, connections := range bc.rooms {
if _, ok := connections[connection.ID()]; ok {
rooms = append(rooms, room)
}
}
return rooms
}