""" HTTP client for Microsoft Graph API. """ import aiohttp import asyncio import orjson # Define a global semaphore for throttling semaphore = asyncio.Semaphore(4) async def fetch_with_aiohttp(url, headers): """ Fetch data from Microsoft Graph API. Args: url (str): The URL to fetch data from. headers (dict): Headers including authentication. Returns: dict: JSON response data. Raises: Exception: If the request fails. """ async with semaphore: async with aiohttp.ClientSession() as session: async with session.get(url, headers=headers) as response: if response.status != 200: raise Exception(f"Failed to fetch {url}: {response.status} {await response.text()}") raw_bytes = await response.read() content_length = response.headers.get('Content-Length') if content_length and len(raw_bytes) != int(content_length): print("Warning: Incomplete response received!") return None return orjson.loads(raw_bytes) async def post_with_aiohttp(url, headers, json_data): """ Post data to Microsoft Graph API. Args: url (str): The URL to post data to. headers (dict): Headers including authentication. json_data (dict): JSON data to post. Returns: int: HTTP status code. """ async with semaphore: async with aiohttp.ClientSession() as session: async with session.post(url, headers=headers, json=json_data) as response: return response.status async def patch_with_aiohttp(url, headers, json_data): """ Patch data to Microsoft Graph API. Args: url (str): The URL to patch data to. headers (dict): Headers including authentication. json_data (dict): JSON data to patch. Returns: int: HTTP status code. """ async with semaphore: async with aiohttp.ClientSession() as session: async with session.patch(url, headers=headers, json=json_data) as response: return response.status async def delete_with_aiohttp(url, headers): """ Delete data from Microsoft Graph API. Args: url (str): The URL to delete data from. headers (dict): Headers including authentication. Returns: int: HTTP status code. """ async with semaphore: async with aiohttp.ClientSession() as session: async with session.delete(url, headers=headers) as response: return response.status