def account_lines(self, req: Dict) -> None:
        '''
        https://xrpl.org/websocket-api-tool.html#account_lines

        Retrieves information about an account's trust lines, including balances for all non-XRP currencies and assets.

        Example:
            >>> self.account_lines({address : 'rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn'})

            See `self.__account_lines_response` for example response
            

        '''
        if not 'account' in req:
            raise KeyError('`account` field required')

        payload = dict(command='account_lines', ledger_index='validated')
        if not 'id' in req:
            _id = utils.generate_uuid()
            payload['id'] = _id

        payload.update(req)
        self.send_json(payload)

        payload["handler"] = self.__account_lines_response
        self._response_queue.update({payload["id"]: payload})
        return
    def account_info(self, req: Dict) -> None:
        '''
        https://xrpl.org/websocket-api-tool.html#account_info
        
        Retrieves information about an account, its activity, and its XRP balance.
        Takes a dict and requires an address: str. You can also pass it optional parameters found in the docs

        >>> self.account_info({account : 'rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn'})
        
        See `self.__account_info_response` for example response
        

        '''

        payload = dict(command='account_info',
                       ledger_index='current',
                       queue=True,
                       strict=True)

        if not 'account' in req:
            raise KeyError('`account` field required')

        if not 'id' in req:
            _id = utils.generate_uuid('account_info')
            payload['id'] = _id

        payload.update(req)
        self.send_json(payload)

        payload["handler"] = self.__account_info_response
        self._response_queue.update({payload["id"]: payload})
        return
    def random(self, _id=None) -> None:
        '''
        Random Number Request
        https://xrpl.org/websocket-api-tool.html#random

        You can give it an id if you want or let it generate one for you

        Example:
            >>> self.random()

            see self.__random_response() for sample response
            
        '''

        payload = dict()
        if not _id:
            _id = utils.generate_uuid('random')

        payload.update(id=_id, command='random')

        self.send_json(payload)

        payload["handler"] = self.__random_response
        self._response_queue.update({payload["id"]: payload})
        return
    def ping(self, _id=None) -> None:
        '''
        Basic Ping Request
        https://xrpl.org/websocket-api-tool.html#ping

        You can give it an id if you want or let it generate one for you
        
        Example:
            >>> self.ping()

            see self.__ping_response() for example response
            

        '''
        payload = dict()
        if not _id:
            _id = utils.generate_uuid('ping')

        payload.update(id=_id, command='ping')

        self.send_json(payload)

        payload["handler"] = self.__ping_response
        self._response_queue.update({payload["id"]: payload})
        return
    def subscribe(self, sub: Dict):
        '''
        Docs: 
            https://xrpl.org/subscribe.html

        Description: 
            Subscribe to a stream
            There are 3 types of subscriptions as defined in the docs
                accounts, order book, and ledger
            
            This method will generate the id and command fields for you
                but follow the docs to see how each subscription payload is formatted

            After subscribing, the client will add it to its local list of subscriptions (self._subscriptions)
            The response handler in this case, `self.__subscription_response`, only handles the confirmation message
            All other subscription messages are handled by their `type` field in the response message

            # Subscribe to an account and valid transactions for it
            >>> self.subscribe(
                    { 
                        'accounts' : ['rrpNnNLKrartuEqfJGpqyDwPj1AFPg9vn1']
                    }
                )   

            # You can subscribe to multiple streams at once
            # Subscribes to LedgerClosed and a particular account's stream
            >>> self.subscribe(
                    { 
                        'streams' : ['ledger'], 
                        'accounts' : ['rfs2EXpCMVJ6S8PX872AUuGbhxPW4e4fYu']
                    }
                )

        '''

        try:
            if not sub.get('id'):
                _id = utils.generate_uuid()

            payload = dict(id=_id, command='subscribe')
            payload.update(sub)

            self.send_json(payload)
            payload["handler"] = self.__subscription_response
            self._response_queue.update({payload["id"]: payload})

            # Add to Running list of Subscriptions
            if sub.get('streams'):
                for s in sub['streams']:
                    self._subscriptions.append(dict(type='streams', stream=s))
            if sub.get('books'):
                for b in sub['books']:
                    self._subscriptions.append(dict(type='books', stream=b))
            if sub.get('accounts'):
                for a in sub['accounts']:
                    self._subscriptions.append(dict(type='accounts', stream=a))
        except Exception as e:
            logger.error(f'{repr(e)}')
 def response_queue_add(self, payload):
     '''
     Helper function that adds an On-Demand message to the queue
     in order to handle responses from the server
     '''
     if not payload.get('id'):
         payload['id'] = utils.generate_uuid()
     payload.update(sent_time=time.time())
     self._response_queue[payload['id']] = payload
    def book_offers(self, book: Dict) -> None:
        '''
        https://xrpl.org/websocket-api-tool.html#book_offers
        Description: On Demand Message to get a Pair's Direct (non-synthetic) Offer Book 
        If the `both` flag is set, it will try to fetch the other side of the Offer if it exists

        Usage: Takes a list of all pairs you want to get the offer book for

        Params:
            Required: taker_gets: Dict
            Required: taker_pays: Dict
            Optional: taker: str
            Optional: id: Any
            Optional: limit: int

        Example Payload
            book = 
                {
                    "id": 4, # optional
                    "taker": "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn", # optional
                    "taker_gets": {
                        "currency": "XRP"
                    },
                    "taker_pays": {
                        "currency": "USD",
                        "issuer": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B"
                    },
                    "limit": 10 # defaults to 10
                }


        >>> self.book_offers(book)

        see self.__book_offers_response() for example response
       

        '''
        if not 'taker_gets' in book:
            raise KeyError('taker_gets required')
        if not 'taker_pays' in book:
            raise KeyError('taker_pays required')

        payload = dict(limit=10)

        # Construct which pair you want
        if not 'id' in book:
            _id = utils.generate_uuid(_id)
            book.update(id=_id)

        payload.update(book, command='book_offers')
        self.send_json(payload)

        payload["handler"] = self.__book_offers_response
        self._response_queue.update({payload["id"]: payload})
        return
    def unsubscribe_all(self) -> None:
        '''
        https://xrpl.org/unsubscribe.html
        Unsubscribes to all current subscriptions in your local list
        '''

        payload = dict(command='unsubscribe', id=utils.generate_uuid())
        for sub in self._subscriptions:
            payload.update({sub['type']: [sub['stream']]})

        self.send_json(payload)
        payload["handler"] = self.__unsubscribe_response
        self._response_queue.update({payload["id"]: payload})

        # Remove the subscriptions from your local list
        for sub in self._subscriptions:
            while sub in self._subscriptions:
                self._subscriptions.remove(sub)