2020-03-22 16:58:53 +00:00
|
|
|
import { EventEmitter } from 'events'
|
2020-11-18 08:21:56 +00:00
|
|
|
import { Namespace } from './namespace'
|
|
|
|
import { Parser } from './parser'
|
|
|
|
import { Socket } from './socket'
|
|
|
|
|
|
|
|
export type SocketId = string
|
|
|
|
export type Room = string
|
|
|
|
|
|
|
|
export interface BroadcastFlags {
|
|
|
|
volatile?: boolean
|
|
|
|
compress?: boolean
|
|
|
|
local?: boolean
|
|
|
|
broadcast?: boolean
|
|
|
|
binary?: boolean
|
|
|
|
}
|
|
|
|
|
|
|
|
export interface BroadcastOptions {
|
|
|
|
rooms: Set<Room>
|
|
|
|
except?: Set<SocketId>
|
|
|
|
flags?: BroadcastFlags
|
|
|
|
}
|
|
|
|
|
|
|
|
export class Adapter extends EventEmitter implements Adapter {
|
|
|
|
rooms: Map<Room, Set<SocketId>>
|
|
|
|
sids: Map<SocketId, Set<Room>>
|
|
|
|
private readonly encoder: Parser
|
2020-03-22 16:58:53 +00:00
|
|
|
parser: Parser
|
2020-11-18 08:21:56 +00:00
|
|
|
|
|
|
|
constructor(readonly nsp: Namespace) {
|
2020-03-22 16:58:53 +00:00
|
|
|
super()
|
2020-11-18 08:21:56 +00:00
|
|
|
this.rooms = new Map()
|
|
|
|
this.sids = new Map()
|
|
|
|
this.parser = nsp.server._parser
|
|
|
|
this.encoder = this.parser
|
2020-03-22 16:58:53 +00:00
|
|
|
}
|
2020-11-18 08:21:56 +00:00
|
|
|
|
2020-03-22 16:58:53 +00:00
|
|
|
/**
|
|
|
|
* Adds a socket to a list of room.
|
|
|
|
*
|
|
|
|
* @param {String} socket id
|
|
|
|
* @param {String} rooms
|
|
|
|
* @param {Function} callback
|
|
|
|
* @api public
|
|
|
|
*/
|
2020-11-18 08:21:56 +00:00
|
|
|
addAll(id: SocketId, rooms: Set<Room>): Promise<void> | void {
|
|
|
|
for (const room of rooms) {
|
|
|
|
if (!this.sids.has(id)) {
|
|
|
|
this.sids.set(id, new Set())
|
|
|
|
}
|
|
|
|
this.sids.get(id).add(room)
|
|
|
|
|
|
|
|
if (!this.rooms.has(room)) {
|
|
|
|
this.rooms.set(room, new Set())
|
|
|
|
}
|
|
|
|
this.rooms.get(room).add(id)
|
2020-03-22 16:58:53 +00:00
|
|
|
}
|
2020-11-18 08:21:56 +00:00
|
|
|
}
|
2020-03-22 16:58:53 +00:00
|
|
|
del(id: string, room: string, callback?: (err?: any) => void): void {
|
2020-11-18 08:21:56 +00:00
|
|
|
if (this.sids.has(id)) {
|
|
|
|
this.sids.get(id).delete(room)
|
|
|
|
}
|
2020-03-22 16:58:53 +00:00
|
|
|
|
2020-11-18 08:21:56 +00:00
|
|
|
if (this.rooms.has(room)) {
|
|
|
|
this.rooms.get(room).delete(id)
|
|
|
|
if (this.rooms.get(room).size === 0) this.rooms.delete(room)
|
2020-03-22 16:58:53 +00:00
|
|
|
}
|
|
|
|
callback && callback.bind(null, null)
|
|
|
|
}
|
|
|
|
delAll(id: string): void {
|
2020-11-18 08:21:56 +00:00
|
|
|
if (!this.sids.has(id)) {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
for (const room of this.sids.get(id)) {
|
|
|
|
if (this.rooms.has(room)) {
|
|
|
|
this.rooms.get(room).delete(id)
|
|
|
|
if (this.rooms.get(room).size === 0) this.rooms.delete(room)
|
2020-03-22 16:58:53 +00:00
|
|
|
}
|
|
|
|
}
|
2020-11-18 08:21:56 +00:00
|
|
|
|
|
|
|
this.sids.delete(id)
|
2020-03-22 16:58:53 +00:00
|
|
|
}
|
2020-11-18 08:21:56 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Broadcasts a packet.
|
|
|
|
*
|
|
|
|
* Options:
|
|
|
|
* - `flags` {Object} flags for this packet
|
|
|
|
* - `except` {Array} sids that should be excluded
|
|
|
|
* - `rooms` {Array} list of rooms to broadcast to
|
|
|
|
*
|
|
|
|
* @param {Object} packet the packet object
|
|
|
|
* @param {Object} opts the options
|
|
|
|
* @public
|
|
|
|
*/
|
|
|
|
public broadcast(packet: any, opts: BroadcastOptions): void {
|
|
|
|
const rooms = opts.rooms
|
|
|
|
const except = opts.except || new Set()
|
|
|
|
const flags = opts.flags || {}
|
|
|
|
const packetOpts = {
|
2020-03-22 16:58:53 +00:00
|
|
|
preEncoded: true,
|
|
|
|
volatile: flags.volatile,
|
|
|
|
compress: flags.compress
|
2020-11-18 08:21:56 +00:00
|
|
|
}
|
|
|
|
const ids = new Set()
|
|
|
|
|
|
|
|
packet.nsp = this.nsp.name
|
|
|
|
const encodedPackets = this.encoder.encode(packet)
|
|
|
|
|
|
|
|
if (rooms.size) {
|
|
|
|
for (const room of rooms) {
|
|
|
|
if (!this.rooms.has(room)) continue
|
|
|
|
|
|
|
|
for (const id of this.rooms.get(room)) {
|
|
|
|
if (ids.has(id) || except.has(id)) continue
|
|
|
|
const socket = this.nsp.sockets.get(id)
|
|
|
|
if (socket) {
|
|
|
|
socket.packet(encodedPackets as any, packetOpts)
|
|
|
|
ids.add(id)
|
2020-03-22 16:58:53 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
2020-11-18 08:21:56 +00:00
|
|
|
for (const [id] of this.sids) {
|
|
|
|
if (except.has(id)) continue
|
|
|
|
const socket = this.nsp.sockets.get(id)
|
|
|
|
if (socket) socket.packet(encodedPackets as any, packetOpts)
|
2020-03-22 16:58:53 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-11-18 08:21:56 +00:00
|
|
|
/**
|
|
|
|
* Gets a list of sockets by sid.
|
|
|
|
*
|
|
|
|
* @param {Set<Room>} rooms the explicit set of rooms to check.
|
|
|
|
*/
|
|
|
|
public sockets(rooms: Set<Room>): Promise<Set<SocketId>> {
|
|
|
|
const sids = new Set<SocketId>()
|
|
|
|
if (rooms.size) {
|
|
|
|
for (const room of rooms) {
|
|
|
|
if (!this.rooms.has(room)) continue
|
|
|
|
for (const id of this.rooms.get(room)) {
|
|
|
|
if (this.nsp.sockets.has(id)) {
|
|
|
|
sids.add(id)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
for (const [id] of this.sids) {
|
|
|
|
if (this.nsp.sockets.has(id)) sids.add(id)
|
|
|
|
}
|
2020-03-22 16:58:53 +00:00
|
|
|
}
|
2020-11-18 08:21:56 +00:00
|
|
|
return Promise.resolve(sids)
|
2020-03-22 16:58:53 +00:00
|
|
|
}
|
2020-11-18 08:21:56 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Gets the list of rooms a given socket has joined.
|
|
|
|
*
|
|
|
|
* @param {SocketId} id the socket id
|
|
|
|
*/
|
|
|
|
public socketRooms(id: SocketId): Set<Room> | undefined {
|
|
|
|
return this.sids.get(id)
|
2020-03-22 16:58:53 +00:00
|
|
|
}
|
2020-11-18 08:21:56 +00:00
|
|
|
}
|