Advertisement
Shefeto

helpers.py

Apr 25th, 2024
501
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 3.62 KB | None | 0 0
  1. import requests
  2. import functools
  3. import time
  4. import json
  5. import os
  6. from datetime import datetime, timedelta
  7. import logging
  8.  
  9. # Constants
  10. API_TOKEN = # TODO
  11. HEADERS = {
  12.     "Authorization": f"Bearer {API_TOKEN}",
  13.     "Content-Type": "application/json",
  14. }
  15. GRAPHQL_ENDPOINT = "https://api.stratz.com/graphql"
  16.  
  17. # Configure logging
  18. logging.basicConfig(level=logging.INFO, format="%(asctime)s - %(message)s")
  19.  
  20. # Constants for API rate limits
  21. SECOND_LIMIT = 20 - 2  # timers aren't perfect
  22. LIMIT_BUFFER = 20  # larger buffer in case you used some up on the website "manually"
  23. MINUTE_LIMIT = 250 - LIMIT_BUFFER
  24. HOUR_LIMIT = 2000 - LIMIT_BUFFER
  25. DAY_LIMIT = 10000 - LIMIT_BUFFER
  26.  
  27. # File path for storing request counts
  28. REQUEST_COUNT_FILE = os.path.join(os.path.dirname(__file__), "api_call_counts.json")
  29.  
  30.  
  31. def update_call_counts():
  32.     """Update call counts for the current time unit, resetting counts where necessary."""
  33.     now = datetime.now()
  34.     time_keys = {
  35.         "second": now.strftime("%Y-%m-%d %H:%M:%S"),
  36.         "minute": now.strftime("%Y-%m-%d %H:%M"),
  37.         "hour": now.strftime("%Y-%m-%d %H"),
  38.         "day": now.strftime("%Y-%m-%d"),
  39.     }
  40.  
  41.     # Load or initialize request counts
  42.     if os.path.exists(REQUEST_COUNT_FILE):
  43.         with open(REQUEST_COUNT_FILE, "r") as f:
  44.             counts = json.load(f)
  45.     else:
  46.         counts = {k: {"time": "", "count": 0} for k in time_keys}
  47.  
  48.     # Update counts or reset if the time unit has changed
  49.     for unit, key in time_keys.items():
  50.         if counts[unit]["time"] == key:
  51.             counts[unit]["count"] += 1
  52.         else:
  53.             counts[unit] = {"time": key, "count": 1}
  54.  
  55.     # Save updated counts
  56.     with open(REQUEST_COUNT_FILE, "w") as f:
  57.         json.dump(counts, f)
  58.  
  59.  
  60. def check_rate_limits():
  61.     """Check if the call is within rate limits. If not, calculate wait time and pause."""
  62.     if not os.path.exists(REQUEST_COUNT_FILE):  # No need to check if file doesn't exist
  63.         return
  64.  
  65.     with open(REQUEST_COUNT_FILE, "r") as f:
  66.         counts = json.load(f)
  67.  
  68.     limits = {
  69.         "second": SECOND_LIMIT,
  70.         "minute": MINUTE_LIMIT,
  71.         "hour": HOUR_LIMIT,
  72.         "day": DAY_LIMIT,
  73.     }
  74.     for unit, limit in limits.items():
  75.         if counts[unit]["count"] >= limit:
  76.             now = datetime.now()
  77.             next_unit_start = now + timedelta(**{unit + "s": 1})
  78.             next_unit_start = next_unit_start.replace(microsecond=0)
  79.             if unit == "minute":
  80.                 next_unit_start = next_unit_start.replace(second=0)
  81.             elif unit == "hour":
  82.                 next_unit_start = next_unit_start.replace(minute=0, second=0)
  83.             elif unit == "day":
  84.                 next_unit_start = next_unit_start.replace(hour=0, minute=0, second=0)
  85.  
  86.             wait_seconds = (next_unit_start - now).total_seconds()
  87.             logging.info(
  88.                 f"Rate limit for {unit} exceeded. Waiting for {wait_seconds} seconds."
  89.             )
  90.             time.sleep(wait_seconds)
  91.             break  # Once the longest wait is identified, no need to check smaller units
  92.  
  93.  
  94. def rate_limited(func):
  95.     @functools.wraps(func)
  96.     def wrapper_rate_limited(*args, **kwargs):
  97.         check_rate_limits()
  98.         update_call_counts()
  99.         return func(*args, **kwargs)
  100.  
  101.     return wrapper_rate_limited
  102.  
  103.  
  104. @rate_limited
  105. def post_query(query):
  106.     response = requests.post(GRAPHQL_ENDPOINT, headers=HEADERS, json={"query": query})
  107.     if response.status_code == 200:
  108.         return response.json()
  109.     else:
  110.         raise Exception(f"Failed to fetch data: {response.status_code} {response.text}")
  111.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement