From 89e241c132b86615bebc44d6c8eb1973e80a2f71 Mon Sep 17 00:00:00 2001 From: Nelson Torres Date: Fri, 15 Nov 2024 11:18:55 -0300 Subject: [PATCH] json_rpc_auth_wrapper --- piker/brokers/deribit/api.py | 109 +++++++++++++---------------------- 1 file changed, 40 insertions(+), 69 deletions(-) diff --git a/piker/brokers/deribit/api.py b/piker/brokers/deribit/api.py index 41b39eec..49664883 100644 --- a/piker/brokers/deribit/api.py +++ b/piker/brokers/deribit/api.py @@ -236,6 +236,39 @@ class Client: self.json_rpc = json_rpc + self._auth_ts = None + self._auth_renew_ts = 5 # seconds to renew auth + + async def _json_rpc_auth_wrapper(self, *args, **kwargs) -> JSONRPCResult: + + """Background task that adquires a first access token and then will + refresh the access token. + + https://docs.deribit.com/?python#authentication-2 + """ + access_scope = 'trade:read_write' + current_ts = time.time() + + if not self._auth_ts or current_ts - self._auth_ts < self._auth_renew_ts: + # if we are close to token expiry time + + params = { + 'grant_type': 'client_credentials', + 'client_id': self._key_id, + 'client_secret': self._key_secret, + 'scope': access_scope + } + + resp = await self.json_rpc('public/auth', params) + result = resp.result + + self._auth_ts = time.time() + result['expires_in'] + + return await self.json_rpc(*args, **kwargs) + + + + async def get_balances( self, kind: str = 'option' @@ -246,7 +279,7 @@ class Client: balances = {} for currency in self.currencies: - resp = await self.json_rpc( + resp = await self._json_rpc_auth_wrapper( 'private/get_positions', params={ 'currency': currency.upper(), 'kind': kind}) @@ -264,7 +297,7 @@ class Client: by symbol. """ assets = {} - resp = await self.json_rpc( + resp = await self._json_rpc_auth_wrapper( 'public/get_currencies', params={} ) @@ -311,7 +344,7 @@ class Client: 'type': 'limit', 'price': price, } - resp = await self.json_rpc( + resp = await self._json_rpc_auth_wrapper( f'private/{action}', params) return resp.result @@ -319,7 +352,7 @@ class Client: async def submit_cancel(self, oid: str): """Send cancel request for order id """ - resp = await self.json_rpc( + resp = await self._json_rpc_auth_wrapper( 'private/cancel', {'order_id': oid}) return resp.result @@ -367,7 +400,7 @@ class Client: 'expired': str(expired).lower() } - resp: JSONRPCResult = await self.json_rpc( + resp: JSONRPCResult = await self._json_rpc_auth_wrapper( 'public/get_instruments', params, ) @@ -449,7 +482,7 @@ class Client: end_time = deribit_timestamp(end_dt) # https://docs.deribit.com/#public-get_tradingview_chart_data - resp = await self.json_rpc( + resp = await self._json_rpc_auth_wrapper( 'public/get_tradingview_chart_data', params={ 'instrument_name': instrument.upper(), @@ -486,7 +519,7 @@ class Client: instrument: str, count: int = 10 ): - resp = await self.json_rpc( + resp = await self._json_rpc_auth_wrapper( 'public/get_last_trades_by_instrument', params={ 'instrument_name': instrument, @@ -508,68 +541,6 @@ async def get_client( ) as json_rpc ): client = Client(json_rpc) - _refresh_token: Optional[str] = None - _access_token: Optional[str] = None - - async def _auth_loop( - task_status: TaskStatus = trio.TASK_STATUS_IGNORED - ): - """Background task that adquires a first access token and then will - refresh the access token while the nursery isn't cancelled. - - https://docs.deribit.com/?python#authentication-2 - """ - renew_time = 10 - access_scope = 'trade:read_write' - _expiry_time = time.time() - got_access = False - nonlocal _refresh_token - nonlocal _access_token - - while True: - if time.time() - _expiry_time < renew_time: - # if we are close to token expiry time - - if _refresh_token != None: - # if we have a refresh token already dont need to send - # secret - params = { - 'grant_type': 'refresh_token', - 'refresh_token': _refresh_token, - 'scope': access_scope - } - - else: - # we don't have refresh token, send secret to initialize - params = { - 'grant_type': 'client_credentials', - 'client_id': client._key_id, - 'client_secret': client._key_secret, - 'scope': access_scope - } - - resp = await json_rpc('public/auth', params) - result = resp.result - - _expiry_time = time.time() + result['expires_in'] - _refresh_token = result['refresh_token'] - - if 'access_token' in result: - _access_token = result['access_token'] - - if not got_access: - # first time this loop runs we must indicate task is - # started, we have auth - got_access = True - task_status.started() - - else: - await trio.sleep(renew_time / 2) - - # if we have client creds launch auth loop - if client._key_id is not None: - await n.start(_auth_loop) - await client.cache_symbols() yield client n.cancel_scope.cancel()