codekingpro/portable-devtools
114k
1import logging2 3from engineio import packet as eio_packet4from . import base_manager5from . import packet6 7default_logger = logging.getLogger('socketio')8 9 10class Manager(base_manager.BaseManager):11 """Manage client connections.12 13 This class keeps track of all the clients and the rooms they are in, to14 support the broadcasting of messages. The data used by this class is15 stored in a memory structure, making it appropriate only for single process16 services. More sophisticated storage backends can be implemented by17 subclasses.18 """19 def can_disconnect(self, sid, namespace):20 return self.is_connected(sid, namespace)21 22 def emit(self, event, data, namespace, room=None, skip_sid=None,23 callback=None, **kwargs):24 """Emit a message to a single client, a room, or all the clients25 connected to the namespace."""26 if namespace not in self.rooms:27 return28 if isinstance(data, tuple):29 # tuples are expanded to multiple arguments, everything else is30 # sent as a single argument31 data = list(data)32 elif data is not None:33 data = [data]34 else:35 data = []36 if not isinstance(skip_sid, list):37 skip_sid = [skip_sid]38 if not callback:39 # when callbacks aren't used the packets sent to each recipient are40 # identical, so they can be generated once and reused41 pkt = self.server.packet_class(42 packet.EVENT, namespace=namespace, data=[event] + data)43 encoded_packet = pkt.encode()44 if not isinstance(encoded_packet, list):45 encoded_packet = [encoded_packet]46 eio_pkt = [eio_packet.Packet(eio_packet.MESSAGE, p)47 for p in encoded_packet]48 for sid, eio_sid in self.get_participants(namespace, room):49 if sid not in skip_sid:50 for p in eio_pkt:51 self.server._send_eio_packet(eio_sid, p)52 else:53 # callbacks are used, so each recipient must be sent a packet that54 # contains a unique callback id55 # note that callbacks when addressing a group of people are56 # implemented but not tested or supported57 for sid, eio_sid in self.get_participants(namespace, room):58 if sid not in skip_sid: # pragma: no branch59 id = self._generate_ack_id(sid, callback)60 pkt = self.server.packet_class(61 packet.EVENT, namespace=namespace, data=[event] + data,62 id=id)63 self.server._send_packet(eio_sid, pkt)64 65 def disconnect(self, sid, namespace, **kwargs):66 """Register a client disconnect from a namespace."""67 return self.basic_disconnect(sid, namespace)68 69 def enter_room(self, sid, namespace, room, eio_sid=None):70 """Add a client to a room."""71 return self.basic_enter_room(sid, namespace, room, eio_sid=eio_sid)72 73 def leave_room(self, sid, namespace, room):74 """Remove a client from a room."""75 return self.basic_leave_room(sid, namespace, room)76 77 def close_room(self, room, namespace):78 """Remove all participants from a room."""79 return self.basic_close_room(room, namespace)80 81 def trigger_callback(self, sid, id, data):82 """Invoke an application callback."""83 callback = None84 try:85 callback = self.callbacks[sid][id]86 except KeyError:87 # if we get an unknown callback we just ignore it88 self._get_logger().warning('Unknown callback received, ignoring.')89 else:90 del self.callbacks[sid][id]91 if callback is not None:92 callback(*data)93 