codekingpro/portable-devtools
114k
1import logging2import signal3import threading4import time5import urllib6from . import packet7 8default_logger = logging.getLogger('engineio.client')9connected_clients = []10 11 12def signal_handler(sig, frame):13 """SIGINT handler.14 15 Disconnect all active clients and then invoke the original signal handler.16 """17 for client in connected_clients[:]:18 if not client.is_asyncio_based():19 client.disconnect()20 if callable(original_signal_handler):21 return original_signal_handler(sig, frame)22 else: # pragma: no cover23 # Handle case where no original SIGINT handler was present.24 return signal.default_int_handler(sig, frame)25 26 27original_signal_handler = None28 29 30class BaseClient:31 event_names = ['connect', 'disconnect', 'message']32 33 def __init__(self, logger=False, json=None, request_timeout=5,34 http_session=None, ssl_verify=True, handle_sigint=True,35 websocket_extra_options=None):36 global original_signal_handler37 if handle_sigint and original_signal_handler is None and \38 threading.current_thread() == threading.main_thread():39 original_signal_handler = signal.signal(signal.SIGINT,40 signal_handler)41 self.handlers = {}42 self.base_url = None43 self.transports = None44 self.current_transport = None45 self.sid = None46 self.upgrades = None47 self.ping_interval = None48 self.ping_timeout = None49 self.http = http_session50 self.external_http = http_session is not None51 self.handle_sigint = handle_sigint52 self.ws = None53 self.read_loop_task = None54 self.write_loop_task = None55 self.queue = None56 self.state = 'disconnected'57 self.ssl_verify = ssl_verify58 self.websocket_extra_options = websocket_extra_options or {}59 60 if json is not None:61 packet.Packet.json = json62 if not isinstance(logger, bool):63 self.logger = logger64 else:65 self.logger = default_logger66 if self.logger.level == logging.NOTSET:67 if logger:68 self.logger.setLevel(logging.INFO)69 else:70 self.logger.setLevel(logging.ERROR)71 self.logger.addHandler(logging.StreamHandler())72 73 self.request_timeout = request_timeout74 75 def is_asyncio_based(self):76 return False77 78 def on(self, event, handler=None):79 """Register an event handler.80 81 :param event: The event name. Can be ``'connect'``, ``'message'`` or82 ``'disconnect'``.83 :param handler: The function that should be invoked to handle the84 event. When this parameter is not given, the method85 acts as a decorator for the handler function.86 87 Example usage::88 89 # as a decorator:90 @eio.on('connect')91 def connect_handler():92 print('Connection request')93 94 # as a method:95 def message_handler(msg):96 print('Received message: ', msg)97 eio.send('response')98 eio.on('message', message_handler)99 """100 if event not in self.event_names:101 raise ValueError('Invalid event')102 103 def set_handler(handler):104 self.handlers[event] = handler105 return handler106 107 if handler is None:108 return set_handler109 set_handler(handler)110 111 def transport(self):112 """Return the name of the transport currently in use.113 114 The possible values returned by this function are ``'polling'`` and115 ``'websocket'``.116 """117 return self.current_transport118 119 def _reset(self):120 self.state = 'disconnected'121 self.sid = None122 123 def _get_engineio_url(self, url, engineio_path, transport):124 """Generate the Engine.IO connection URL."""125 engineio_path = engineio_path.strip('/')126 parsed_url = urllib.parse.urlparse(url)127 128 if transport == 'polling':129 scheme = 'http'130 elif transport == 'websocket':131 scheme = 'ws'132 else: # pragma: no cover133 raise ValueError('invalid transport')134 if parsed_url.scheme in ['https', 'wss']:135 scheme += 's'136 137 return ('{scheme}://{netloc}/{path}/?{query}'138 '{sep}transport={transport}&EIO=4').format(139 scheme=scheme, netloc=parsed_url.netloc,140 path=engineio_path, query=parsed_url.query,141 sep='&' if parsed_url.query else '',142 transport=transport)143 144 def _get_url_timestamp(self):145 """Generate the Engine.IO query string timestamp."""146 return '&t=' + str(time.time())147 