def websocket(self): """ Websocket main server """ set_thread_name('WebsocketServer') async def register_websocket(websocket, path): address = websocket.remote_address if websocket.remote_address \ else '<unknown client>' self.logger.info('New websocket connection from {} on path {}'.format(address, path)) self.active_websockets.add(websocket) try: await websocket.recv() except ConnectionClosed: self.logger.info('Websocket client {} closed connection'.format(address)) self.active_websockets.remove(websocket) if address in self._websocket_locks: del self._websocket_locks[address] websocket_args = {} if self.ssl_context: websocket_args['ssl'] = self.ssl_context self._websocket_loop = get_or_create_event_loop() self._websocket_loop.run_until_complete( websocket_serve(register_websocket, self.bind_address, self.websocket_port, **websocket_args)) self._websocket_loop.run_forever()
def notify_web_clients(self, event): """ Notify all the connected web clients (over websocket) of a new event """ import websockets async def send_event(ws): try: self._acquire_websocket_lock(ws) await ws.send(str(event)) except Exception as e: self.logger.warning( 'Error on websocket send_event: {}'.format(e)) finally: self._release_websocket_lock(ws) loop = get_or_create_event_loop() wss = self.active_websockets.copy() for _ws in wss: try: loop.run_until_complete(send_event(_ws)) except websockets.exceptions.ConnectionClosed: self.logger.warning( 'Websocket client {} connection lost'.format( _ws.remote_address)) self.active_websockets.remove(_ws) if _ws.remote_address in self._websocket_locks: del self._websocket_locks[_ws.remote_address]
def run(self): super().run() self.register_service(port=self.port, name='ws') # noinspection PyUnusedLocal async def serve_client(websocket, path): self.active_websockets.add(websocket) self.logger.debug('New websocket connection from {}'.format( websocket.remote_address[0])) try: while True: if self.client_timeout: msg = await asyncio.wait_for( websocket.recv(), timeout=self.client_timeout) else: msg = await websocket.recv() msg = Message.build(msg) self.logger.info('Received message from {}: {}'.format( websocket.remote_address[0], msg)) self.on_message(msg) if isinstance(msg, Request): response = self.get_message_response(msg) or Response() self.logger.info( 'Processing response on the websocket backend: {}'. format(response)) await websocket.send(str(response)) except websockets.exceptions.ConnectionClosed as e: self.active_websockets.remove(websocket) self.logger.debug( 'Websocket client {} closed connection'.format( websocket.remote_address[0])) except asyncio.TimeoutError as e: self.active_websockets.remove(websocket) self.logger.debug( 'Websocket connection to {} timed out'.format( websocket.remote_address[0])) except Exception as e: self.logger.exception(e) self.logger.info( 'Initialized websocket backend on port {}, bind address: {}'. format(self.port, self.bind_address)) websocket_args = {} if self.ssl_context: websocket_args['ssl'] = self.ssl_context loop = get_or_create_event_loop() server = websockets.serve(serve_client, self.bind_address, self.port, **websocket_args) loop.run_until_complete(server) loop.run_forever()
def send(self, url, msg, ssl_cert=None, ssl_key=None, ssl_cafile=None, ssl_capath=None, *args, **kwargs): """ Sends a message to a websocket. :param url: Websocket URL, e.g. ws://localhost:8765 or wss://localhost:8765 :type topic: str :param msg: Message to be sent. It can be a list, a dict, or a Message object :param ssl_cert: Path to the SSL certificate to be used, if the SSL connection requires client authentication as well (default: None) :type ssl_cert: str :param ssl_key: Path to the SSL key to be used, if the SSL connection requires client authentication as well (default: None) :type ssl_key: str :param ssl_cafile: Path to the certificate authority file if required by the SSL configuration (default: None) :type ssl_cafile: str :param ssl_capath: Path to the certificate authority directory if required by the SSL configuration (default: None) :type ssl_capath: str """ async def send(): websocket_args = {} if ssl_cert: websocket_args['ssl'] = get_ssl_client_context( ssl_cert=ssl_cert, ssl_key=ssl_key, ssl_cafile=ssl_cafile, ssl_capath=ssl_capath) async with websockets.connect(url, **websocket_args) as websocket: try: await websocket.send(str(msg)) except websockets.exceptions.ConnectionClosed: self.logger.warning('Error on websocket {}: {}'.format( url, e)) try: msg = json.dumps(msg) except: pass try: msg = Message.build(json.loads(msg)) except: pass loop = get_or_create_event_loop() loop.run_until_complete(send())
def notify_web_clients(self, event): """ Notify all the connected web clients (over websocket) of a new event """ async def send_event(websocket): try: await websocket.send(str(event)) except Exception as e: self.logger.warning( 'Error on websocket send_event: {}'.format(e)) loop = get_or_create_event_loop() active_websockets = self.active_websockets.copy() for websocket in active_websockets: try: loop.run_until_complete(send_event(websocket)) except websockets.exceptions.ConnectionClosed: self.logger.info('Client connection lost') self.active_websockets.remove(websocket)