在同一应用中运行Flask与Discord Bot的技术实现问询
Hey there! I’ve worked on similar setups before, so let’s walk through how to run your discord.py bot and Flask web server side-by-side to handle Twitch webhooks. Here’s a practical, step-by-step solution:
The problem here is that both discord.py and Flask run their own event loops—if you start one after the other, the second one will never run because the first blocks the thread. The simplest fix is to run Flask in a separate daemon thread, so it runs in the background while your Discord bot handles its own events.
First, make sure you have all the required packages installed:
pip install discord.py flask requests
Here’s a complete, working script that ties everything together. I’ll break down the key parts below:
import discord from discord.ext import commands from flask import Flask, request, abort import threading import hmac import hashlib # ---------------------- # Discord Bot Configuration # ---------------------- intents = discord.Intents.default() intents.message_content = True # Required to send messages in channels bot = commands.Bot(command_prefix="!", intents=intents) # ---------------------- # Flask Webhook Configuration # ---------------------- app = Flask(__name__) TWITCH_WEBHOOK_SECRET = "your_twitch_webhook_secret" # From Twitch Dev Console TARGET_DISCORD_CHANNEL_ID = 123456789012345678 # Replace with your channel ID # ---------------------- # Discord Bot Events # ---------------------- @bot.event async def on_ready(): print(f"Logged in as {bot.user} (ID: {bot.user.id})") print("Bot is ready to handle Twitch events!") print("----------------------------------------") # ---------------------- # Twitch Webhook Endpoints # ---------------------- # Handle Twitch's webhook verification (GET request) @app.route("/twitch-webhook", methods=["GET"]) def verify_webhook(): challenge = request.args.get("hub.challenge") if challenge: return challenge, 200 abort(400) # Bad request if no challenge provided # Handle Twitch event notifications (POST request) @app.route("/twitch-webhook", methods=["POST"]) def handle_twitch_event(): # Optional: Verify Twitch's request signature to prevent spam signature_header = request.headers.get("X-Hub-Signature") if not signature_header: abort(403) # Forbidden if no signature # Validate the signature using your webhook secret sha1_hash = hmac.new( TWITCH_WEBHOOK_SECRET.encode(), request.data, hashlib.sha1 ).hexdigest() if not signature_header == f"sha1={sha1_hash}": abort(403) # Invalid signature # Parse the event data event_data = request.json event_type = event_data["event"]["type"] # Handle stream online event if event_type == "stream.online": streamer_name = event_data["event"]["broadcaster_user_name"] streamer_login = event_data["event"]["broadcaster_user_login"] # Send message to Discord using the bot's event loop channel = bot.get_channel(TARGET_DISCORD_CHANNEL_ID) if channel: # Use bot.loop.create_task to run async code in Flask's sync thread bot.loop.create_task( channel.send(f"🎉 {streamer_name} just went live on Twitch!\nWatch here: https://twitch.tv/{streamer_login}") ) return "", 200 # Twitch expects a 200 OK response # ---------------------- # Run Both Services # ---------------------- def run_flask_server(): # Use host='0.0.0.0' to make the server accessible externally # Disable debug in production! app.run(host="0.0.0.0", port=5000, debug=False) if __name__ == "__main__": # Start Flask in a daemon thread (dies when main thread exits) flask_thread = threading.Thread(target=run_flask_server) flask_thread.daemon = True flask_thread.start() # Start the Discord Bot bot.run("your_discord_bot_token") # Replace with your bot token
- Twitch Signature Verification: I added optional (but highly recommended) signature validation to ensure only Twitch can send requests to your webhook. You’ll get the secret when you set up the webhook in the Twitch Developer Console.
- Async Compatibility: Flask runs in a synchronous thread, so we can’t use
awaitdirectly. Instead, we usebot.loop.create_task()to schedule the Discord message send in the bot’s async event loop—this avoids blocking Flask and keeps everything working smoothly. - Local Development: To test locally, you’ll need a tool like ngrok to expose your Flask server to the internet. Run
ngrok http 5000and use the provided HTTPS URL as your Twitch webhook callback. - Discord Intents: Don’t forget to enable the
message_contentintent in the Discord Developer Portal for your bot—otherwise, it won’t be able to send messages. - Production Deployment: For production, use a proper WSGI server like Gunicorn instead of Flask’s built-in server, and store secrets (bot token, Twitch secret) as environment variables instead of hardcoding them.
内容的提问来源于stack exchange,提问作者Haxo201

