Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- """
- Contains decorators for the functions in utils.py
- """
- from functools import wraps
- from django.core.cache import cache
- from time import time, sleep
- from redlock import RedLockFactory
- from .logging import logger
- from . import settings as app_settings
- rlf = RedLockFactory(connection_details=[{
- 'url': app_settings.REDIS_LOCATION
- }])
- def _ratelimit_wait(route):
- """
- If ratelimited by route or globally, sleeps until it should be safe.
- """
- if cache.get('discord_api:global:limit'):
- cur_time = time()
- retry = cache.get('discord_api:global:retry'.format(route))
- diff = retry - cur_time
- if diff > 0:
- logger.debug('Waiting for GLOBAL ratelimit reset')
- sleep(diff)
- cache.set('discord_api:global:limit', False)
- remaining = cache.get('discord_api:{}:rl:remaining'.format(route))
- if remaining and remaining <= 0:
- cur_time = time()
- reset = cache.get('discord_api:{}:rl:reset'.format(route))
- diff = reset - cur_time
- if diff > 0:
- logger.debug('Waiting for {} ratelimit reset.'.format(route))
- sleep(diff)
- def _ratelimit_update(route, headers):
- """
- Given a route and a dict of response headers, updates the cache values for them.
- """
- if 'X-RateLimit-Global' in headers:
- cache.set('discord_api:global:limit', True)
- cache.set('discord_api:global:retry', time() + int(headers['Retry-After']))
- if 'X-RateLimit-Remaining' in headers:
- cache.set('discord_api:{}:rl:remaining'.format(route), int(headers['X-RateLimit-Remaining']))
- if 'X-RateLimit-Reset' in headers:
- cache.set('discord_api:{}:rl:reset'.format(route), int(headers['X-RateLimit-Reset']))
- def ratelimited(route):
- """
- Applies ratelimiting logic to the decorated function.
- Decorated function must return a tuple, with a dict of response headers as the last value in the tuple.
- Returns the rest of the tuple, and if the tuple only contains one object, return that object directly.
- """
- def decorator(func):
- @wraps(func)
- def wrapper(*args, **kwargs):
- with rlf.create_lock('discord_api:lock'):
- _ratelimit_wait(route)
- *result, headers = func(*args, **kwargs)
- _ratelimit_update(route, headers)
- if len(result) == 1:
- return result[0]
- return result
- return wrapper
- return decorator
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement