async def start_websockets(self) -> None: if len(self.subscription_sets): done, pending = await asyncio.wait( [ asyncio.create_task( self._get_websocket_mgr(subscriptions, self.ssl_context).run()) for subscriptions in self.subscription_sets ], return_when=asyncio.FIRST_EXCEPTION) for task in done: try: task.result() except Exception as e: LOG.exception( f"Unrecoverable exception occurred while processing messages: {e}" ) LOG.info("All websockets scheduled for shutdown") for task in pending: if not task.cancelled(): task.cancel() if len(pending) > 0: await asyncio.wait(pending, return_when=asyncio.ALL_COMPLETED) LOG.info("All websockets closed.") raise else: raise CryptoXLibException( "ERROR: There are no subscriptions to be started.")
async def start_websockets(self, websocket_start_time_interval_ms: int = 0) -> None: if len(self.subscription_sets) < 1: raise CryptoXLibException("ERROR: There are no subscriptions to be started.") tasks = [] startup_delay_ms = 0 for id, subscription_set in self.subscription_sets.items(): subscription_set.websocket_mgr = self._get_websocket_mgr(subscription_set.subscriptions, startup_delay_ms, self.ssl_context) tasks.append(async_create_task( subscription_set.websocket_mgr.run()) ) startup_delay_ms += websocket_start_time_interval_ms done, pending = await asyncio.wait(tasks, return_when = asyncio.FIRST_EXCEPTION) for task in done: try: task.result() except Exception as e: LOG.error(f"Unrecoverable exception occurred while processing messages: {e}") LOG.info(f"Remaining websocket managers scheduled for shutdown.") await self.shutdown_websockets() if len(pending) > 0: await asyncio.wait(pending, return_when = asyncio.ALL_COMPLETED) LOG.info("All websocket managers shut down.") raise
async def close(self): if self.ws is None: raise CryptoXLibException("Websocket attempted to close connection while connection not open.") await self.ws.close() await self.session.close() self.ws = None self.session = None
async def connect(self): if self.ws is not None: raise CryptoXLibException("Websocket reattempted to make connection while previous one is still active.") LOG.debug(f"Connecting to websocket {self.websocket_uri}") self.ws = await websockets.connect(self.websocket_uri, ping_interval = self.builtin_ping_interval, max_size = self.max_message_size, ssl = self.ssl_context)
async def connect(self): if self.ws is not None: raise CryptoXLibException("Websocket reattempted to make connection while previous one is still active.") self.session = aiohttp.ClientSession() self.ws = await self.session.ws_connect(url = self.websocket_uri, max_msg_size = self.max_message_size, autoping = True, heartbeat = self.builtin_ping_interval, ssl_context = self.ssl_context)
async def unsubscribe_subscriptions(self, subscriptions: List[Subscription]) -> None: for subscription in subscriptions: subscription_found = False for id, subscription_set in self.subscription_sets.items(): if subscription_set.find_subscription(subscription) is not None: subscription_found = True await subscription_set.websocket_mgr.unsubscribe(subscriptions) if not subscription_found: raise CryptoXLibException(f"No active subscription {subscription.subscription_id} found.")
async def send(self, message: Union[str, dict, WebsocketOutboundMessage]): if isinstance(message, str): pass elif isinstance(message, dict): message = json.dumps(message) elif isinstance(message, WebsocketOutboundMessage): message = json.dumps(message.to_json()) else: raise CryptoXLibException( "Only string or JSON serializable objects can be sent over the websocket." ) LOG.debug(f"> {message}") return await self.websocket.send(message)
async def receive(self): if self.ws is None: raise CryptoXLibException("Websocket attempted to read data while connection not open.") message = await self.ws.receive() if message.type == aiohttp.WSMsgType.TEXT: if message.data == 'close cmd': raise WebsocketClosed(f'Websocket was closed: {message.data}') else: return message.data elif message.type == aiohttp.WSMsgType.CLOSED: raise WebsocketClosed(f'Websocket was closed: {message.data}') elif message.type == aiohttp.WSMsgType.ERROR: raise WebsocketError(f'Websocket error: {message.data}')
async def receive(self): if self.ws is None: raise CryptoXLibException("Websocket attempted to read data while connection not open.") return await self.ws.recv()
async def send(self, message: str): if self.ws is None: raise CryptoXLibException("Websocket attempted to send data while connection not open.") return await self.ws.send_str(message)
async def send_unsubscription_message(self, subscriptions: List[Subscription]): raise CryptoXLibException( "The client does not support unsubscription messages.")