slazarov / python-bittrex-websocket-aio

Python websocket for Bittrex (async).
http://python-bittrex-websocket-docs.readthedocs.io/en/latest/index.html#
MIT License
36 stars 13 forks source link

multiple 'query_summary_state' not working #12

Open markoaurelije opened 6 years ago

markoaurelije commented 6 years ago

Hi, Not more that one query_summary_state is succesfully made when previosuly "authentication" is performed. I did solve it by adding:

self.invokes.append({'invoke': invoke, 'ticker': None})

at _handle_subscribe function for the invoke == BittrexMethods.AUTHENTICATE case.

BR.

slazarov commented 6 years ago

Hi, I will look into it.

Note that your solution will result in an invalid AUTHENTICATE call in the case of a drop & reconnect event since authentication works like this:

  1. Call GET_AUTH_CONTENT
  2. Await for payload from Bittrex and create signature
  3. Call AUTHENTICATE with the signature as a payload
markoaurelije commented 6 years ago

No drop or disconnect, when I'm authenticated and try to call query_summary_state()

I get an exception "index out of bounds" on line 197 at websocket_client.py.

       async def _is_query_invoke(self, kwargs):
        if 'R' in kwargs and type(kwargs['R']) is not bool:
***         invoke = self.invokes[int(kwargs['I'])]['invoke']     ***
            if invoke == BittrexMethods.GET_AUTH_CONTENT:
                signature = await create_signature(self.credentials['api_secret'], kwargs['R'])
                event = SubscribeEvent(BittrexMethods.AUTHENTICATE, self.credentials['api_key'], signature)
                self.control_queue.put(event)
            else:
                msg = await process_message(kwargs['R'])
                if msg is not None:
                    msg['invoke_type'] = invoke
                    msg['ticker'] = self.invokes[int(kwargs['I'])].get('ticker')
                    await self.on_public(msg)

As it turns out value of int(kwargs['I']) exceeds the length of self.invokes array. So by adding:

       def _handle_subscribe(self, invoke, payload):
        if invoke in [BittrexMethods.SUBSCRIBE_TO_EXCHANGE_DELTAS, BittrexMethods.QUERY_EXCHANGE_STATE]:
            for ticker in payload[0]:
                self.invokes.append({'invoke': invoke, 'ticker': ticker})
                self.connection.corehub.server.invoke(invoke, ticker)
                logger.info('Successfully subscribed to [{}] for [{}].'.format(invoke, ticker))
        elif invoke == BittrexMethods.GET_AUTH_CONTENT:
            self.connection.corehub.server.invoke(invoke, payload[0])
            self.invokes.append({'invoke': invoke, 'ticker': payload[0]})
            logger.info('Retrieving authentication challenge.')
        elif invoke == BittrexMethods.AUTHENTICATE:
            self.connection.corehub.server.invoke(invoke, payload[0], payload[1])
            logger.info('Challenge retrieved. Sending authentication. Awaiting messages...')
            # No need to append invoke list, because AUTHENTICATE is called from successful GET_AUTH_CONTENT.
***         self.invokes.append({'invoke': invoke, 'ticker': None})    ***
        else:
            self.invokes.append({'invoke': invoke, 'ticker': None})
            self.connection.corehub.server.invoke(invoke)
            logger.info('Successfully invoked [{}].'.format(invoke))

Sorry for not having a traceback, I can reproduce if you wish ;)

BTW: great work, this lib helped me alot.