Add token refresher task

kivy_mainline_and_py3.8
Tyler Goodlet 2018-01-25 21:53:55 -05:00
parent 4e1c64a7fb
commit 9e8ed392d4
1 changed files with 19 additions and 7 deletions

View File

@ -1,6 +1,7 @@
""" """
Questrade API backend. Questrade API backend.
""" """
import trio
from . import config from . import config
from ..log import get_logger from ..log import get_logger
from pprint import pformat from pprint import pformat
@ -105,12 +106,14 @@ class Client:
) )
return resp return resp
async def enable_access(self, force_refresh: bool = False) -> dict: async def ensure_access(self, force_refresh: bool = False) -> dict:
"""Acquire new ``refresh_token`` and/or ``access_token`` if necessary. """Acquire new ``access_token`` and/or ``refresh_token`` if necessary.
Only needs to be called if the locally stored ``refresh_token`` has Checks if the locally cached (file system) ``access_token`` has expired
(based on a ``expires_at`` time stamp stored in the brokers.ini config)
expired (normally has a lifetime of 3 days). If ``false is set then expired (normally has a lifetime of 3 days). If ``false is set then
refresh the access token instead of using the locally cached version. and refreshs token if necessary using the ``refresh_token``. If the
``refresh_token`` has expired a new one needs to be provided by the user.
""" """
access_token = self.access_data.get('access_token') access_token = self.access_data.get('access_token')
expires = float(self.access_data.get('expires_at', 0)) expires = float(self.access_data.get('expires_at', 0))
@ -146,6 +149,14 @@ def get_config() -> "configparser.ConfigParser":
return conf return conf
async def token_refresher(client):
"""Coninually refresh the ``access_token`` near its expiry time.
"""
while True:
await trio.sleep(float(client.access_data['expires_at']) - time.time() - .1)
await client.ensure_access()
@asynccontextmanager @asynccontextmanager
async def get_client() -> Client: async def get_client() -> Client:
"""Spawn a broker client. """Spawn a broker client.
@ -153,7 +164,7 @@ async def get_client() -> Client:
conf = get_config() conf = get_config()
log.debug(f"Loaded config:\n{pformat(dict(conf['questrade']))}\n") log.debug(f"Loaded config:\n{pformat(dict(conf['questrade']))}\n")
client = Client(dict(conf['questrade'])) client = Client(dict(conf['questrade']))
await client.enable_access() await client.ensure_access()
try: try:
log.debug("Check time to ensure access token is valid") log.debug("Check time to ensure access token is valid")
@ -163,7 +174,7 @@ async def get_client() -> Client:
# access token is likely no good # access token is likely no good
log.warn(f"Access token {client.access_data['access_token']} seems" log.warn(f"Access token {client.access_data['access_token']} seems"
f" expired, forcing refresh") f" expired, forcing refresh")
await client.enable_access(force_refresh=True) await client.ensure_access(force_refresh=True)
await client.api.time() await client.api.time()
accounts = await client.api.accounts() accounts = await client.api.accounts()
@ -181,4 +192,5 @@ async def serve_forever() -> None:
async with get_client() as client: async with get_client() as client:
# pretty sure this doesn't work # pretty sure this doesn't work
# await client._revoke_auth_token() # await client._revoke_auth_token()
return client async with trio.open_nursery() as nursery:
nursery.start_soon(token_refresher, client)