import json import sys import time import garth from datetime import datetime def main(): try: # Load configuration with open('config.json') as f: config = json.load(f) garmin_config = config.get('garmin', {}) username = garmin_config.get('username') password = garmin_config.get('password') is_china = garmin_config.get('is_china', False) session_file = garmin_config.get('session_data_file', 'garmin_session.json') if not username or not password: print("❌ Missing Garmin credentials in config.json") return 1 # Set domain based on region domain = "garmin.cn" if is_china else "garmin.com" garth.configure(domain=domain) try: # Authentication attempt start_time = time.time() garth.login(username, password) end_time = time.time() print("✅ Authentication successful!") print(f"⏱️ Authentication time: {end_time - start_time:.2f} seconds") garth.save(session_file) return 0 except garth.exc.GarthHTTPError as e: end_time = time.time() # Capture time when error occurred # Extract information from the exception message error_msg = str(e) print(f"\n⚠️ Garth HTTP Error: {error_msg}") # Check if it's a 429 error by parsing the message if "429" in error_msg: print("=" * 50) print("Rate Limit Exceeded (429)") print(f"Response Time: {end_time - start_time:.2f} seconds") # Try to extract URL from error message url_start = error_msg.find("url: ") if url_start != -1: url = error_msg[url_start + 5:] print(f"URL: {url}") # Try to access response headers if available if hasattr(e, 'response') and e.response is not None: headers = e.response.headers retry_after = headers.get('Retry-After') reset_timestamp = headers.get('X-RateLimit-Reset') remaining = headers.get('X-RateLimit-Remaining') limit = headers.get('X-RateLimit-Limit') print("\n📊 Rate Limit Headers Found:") if retry_after: print(f"⏳ Retry-After: {retry_after} seconds") wait_time = int(retry_after) reset_time = datetime.utcfromtimestamp(time.time() + wait_time) print(f"⏰ Estimated reset time: {reset_time} UTC") if reset_timestamp: try: reset_time = datetime.utcfromtimestamp(float(reset_timestamp)) print(f"⏰ Rate limit resets at: {reset_time} UTC") except ValueError: print(f"⚠️ Invalid reset timestamp: {reset_timestamp}") if remaining: print(f"🔄 Requests remaining: {remaining}") if limit: print(f"📈 Rate limit: {limit} requests per window") if not any([retry_after, reset_timestamp, remaining, limit]): print("ℹ️ No rate limit headers found in response") else: print("\n⚠️ Response headers not accessible directly from GarthHTTPError") print("Common rate limit headers to look for:") print(" - Retry-After: Seconds to wait before retrying") print(" - X-RateLimit-Limit: Maximum requests per time window") print(" - X-RateLimit-Remaining: Remaining requests in current window") print(" - X-RateLimit-Reset: Time when rate limit resets") print(f"\nRecommend waiting at least 60 seconds before retrying.") return 429 # Handle other HTTP errors print(f"❌ HTTP Error detected: {error_msg}") return 1 except Exception as e: print(f"❌ Authentication failed: {str(e)}") return 1 except FileNotFoundError: print("❌ config.json file not found") return 1 except json.JSONDecodeError: print("❌ Error parsing config.json") return 1 if __name__ == "__main__": sys.exit(main())