async def _process_websocket_messages(self, websocket_assistant: WSAssistant, queue: asyncio.Queue): async for ws_response in websocket_assistant.iter_messages(): data: Dict[str, Any] = ws_response.data decompressed_data = utils.decompress_ws_message(data) try: if type(decompressed_data) == str: json_data = json.loads(decompressed_data) else: json_data = decompressed_data except asyncio.CancelledError: raise except Exception: self.logger().warning( f"Invalid event message received through the order book data source " f"connection ({decompressed_data})") continue if "errorCode" in json_data or "errorMessage" in json_data: raise ValueError( f"Error message received in the order book data source: {json_data}" ) await self._process_event_message(event_message=json_data, queue=queue)
async def _inner_messages( self, ws: websockets.WebSocketClientProtocol) -> AsyncIterable[str]: try: while True: try: msg: str = await asyncio.wait_for( ws.recv(), timeout=self.MESSAGE_TIMEOUT) msg = bitmart_utils.decompress_ws_message(msg) yield msg except asyncio.TimeoutError: pong_waiter = await ws.ping() await asyncio.wait_for(pong_waiter, timeout=self.PING_TIMEOUT) except asyncio.TimeoutError: self.logger().warning( "WebSocket ping timed out. Going to reconnect...") return except websockets.exceptions.ConnectionClosed: return finally: await ws.close()
async def listen_for_order_book_diffs(self, ev_loop: asyncio.BaseEventLoop, output: asyncio.Queue): """ Listen for orderbook diffs using websocket book channel(all messages are snapshots) """ while True: try: ws: WSAssistant = await self._api_factory.get_ws_assistant() await ws.connect(ws_url=CONSTANTS.WSS_URL, message_timeout=self.MESSAGE_TIMEOUT, ping_timeout=self.PING_TIMEOUT) for trading_pair in self._trading_pairs: ws_message: WSRequest = WSRequest({ "op": "subscribe", "args": [f"spot/depth400:{convert_to_exchange_trading_pair(trading_pair)}"] }) await ws.send(ws_message) while True: try: async for raw_msg in ws.iter_messages(): messages = decompress_ws_message(raw_msg.data) if messages is None: continue messages = ujson.loads(messages) if "errorCode" in messages.keys() or \ "data" not in messages.keys() or \ "table" not in messages.keys(): continue if messages["table"] != "spot/depth5": # Not an order book message continue for msg in messages["data"]: # data is a list msg_timestamp: float = float(msg["ms_t"]) t_pair = convert_from_exchange_trading_pair(msg["symbol"]) snapshot_msg: OrderBookMessage = BitmartOrderBook.snapshot_message_from_exchange( msg=msg, timestamp=msg_timestamp, metadata={"trading_pair": t_pair} ) output.put_nowait(snapshot_msg) break except asyncio.exceptions.TimeoutError: # Check whether connection is really dead await ws.ping() except asyncio.CancelledError: raise except asyncio.exceptions.TimeoutError: self.logger().warning("WebSocket ping timed out. Going to reconnect...") await ws.disconnect() await asyncio.sleep(30.0) except Exception: self.logger().network( "Unexpected error with WebSocket connection.", exc_info=True, app_warning_msg="Unexpected error with WebSocket connection. Retrying in 30 seconds. " "Check network connection." ) await ws.disconnect() await self._sleep(30.0) finally: await ws.disconnect()