Advertisement
Guest User

Untitled

a guest
Jun 15th, 2019
85
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 2.17 KB | None | 0 0
  1. """
  2. Contains decorators for the functions in utils.py
  3. """
  4.  
  5. from functools import wraps
  6.  
  7. from django.core.cache import cache
  8. from time import time, sleep
  9.  
  10. from redlock import RedLockFactory
  11.  
  12. from .logging import logger
  13.  
  14. from . import settings as app_settings
  15.  
  16. rlf = RedLockFactory(connection_details=[{
  17. 'url': app_settings.REDIS_LOCATION
  18. }])
  19.  
  20. def _ratelimit_wait(route):
  21. """
  22. If ratelimited by route or globally, sleeps until it should be safe.
  23. """
  24.  
  25. if cache.get('discord_api:global:limit'):
  26. cur_time = time()
  27. retry = cache.get('discord_api:global:retry'.format(route))
  28. diff = retry - cur_time
  29. if diff > 0:
  30. logger.debug('Waiting for GLOBAL ratelimit reset')
  31. sleep(diff)
  32. cache.set('discord_api:global:limit', False)
  33.  
  34. remaining = cache.get('discord_api:{}:rl:remaining'.format(route))
  35. if remaining and remaining <= 0:
  36. cur_time = time()
  37. reset = cache.get('discord_api:{}:rl:reset'.format(route))
  38. diff = reset - cur_time
  39. if diff > 0:
  40. logger.debug('Waiting for {} ratelimit reset.'.format(route))
  41. sleep(diff)
  42.  
  43. def _ratelimit_update(route, headers):
  44. """
  45. Given a route and a dict of response headers, updates the cache values for them.
  46. """
  47.  
  48. if 'X-RateLimit-Global' in headers:
  49. cache.set('discord_api:global:limit', True)
  50. cache.set('discord_api:global:retry', time() + int(headers['Retry-After']))
  51. if 'X-RateLimit-Remaining' in headers:
  52. cache.set('discord_api:{}:rl:remaining'.format(route), int(headers['X-RateLimit-Remaining']))
  53. if 'X-RateLimit-Reset' in headers:
  54. cache.set('discord_api:{}:rl:reset'.format(route), int(headers['X-RateLimit-Reset']))
  55.  
  56. def ratelimited(route):
  57. """
  58. Applies ratelimiting logic to the decorated function.
  59.  
  60. Decorated function must return a tuple, with a dict of response headers as the last value in the tuple.
  61.  
  62. Returns the rest of the tuple, and if the tuple only contains one object, return that object directly.
  63. """
  64.  
  65. def decorator(func):
  66. @wraps(func)
  67. def wrapper(*args, **kwargs):
  68. with rlf.create_lock('discord_api:lock'):
  69. _ratelimit_wait(route)
  70. *result, headers = func(*args, **kwargs)
  71. _ratelimit_update(route, headers)
  72. if len(result) == 1:
  73. return result[0]
  74. return result
  75. return wrapper
  76. return decorator
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement