async def send(self, msg: dict) -> Any: """Send a request to Binance stream and handle the asynchronous socket response Request:: { "method": "SUBSCRIBE", "params": [ "btcusdt@aggTrade", "btcusdt@depth" ], "id": 1 } Response:: { "result": null, "id": 1 } Then the result of `self.send()` is `None` (null) """ socket = self._socket if not socket: if self._open_future: socket = await self._open_future else: raise StreamDisconnectedException(self._uri) future = create_future() message_id = self._message_id self._message_id += 1 msg[STREAM_KEY_ID] = message_id self._message_futures[message_id] = future await socket.send(json_stringify(msg)) return await future
async def close(self, code: int = DEFAULT_STREAM_CLOSE_CODE) -> None: """Close the current socket connection Args: code (:obj:`int`, optional): socket close code, defaults to 4999 """ if not self._conn_task: raise StreamDisconnectedException(self._uri) # A lot of incomming messages might prevent # the socket from gracefully shutting down, # which leads `websockets` to fail connection # and result in a 1006 close code (ConnectionClosedError). # In that situation, we can not properly figure out whether the socket # is closed by socket.close() or network connection error. # So just set up a flag to do the trick self._closing = True tasks = [self._conn_task] if self._socket: tasks.append( # make socket.close run in background self._socket.close(code)) self._conn_task.cancel() # Make sure: # - conn_task is cancelled # - socket is closed for coro in asyncio.as_completed(tasks): try: await coro except Exception as e: logger.error(format_msg('close tasks error: %s', e)) self._socket = None self._closing = False