Skip to content

Instantly share code, notes, and snippets.

@crrapi
Last active December 7, 2023 16:47
Show Gist options
  • Save crrapi/c8465f9ce8b579a8ca3e78845309b832 to your computer and use it in GitHub Desktop.
Save crrapi/c8465f9ce8b579a8ca3e78845309b832 to your computer and use it in GitHub Desktop.
(Don't use if you can) Run a Flask app and a discord.py bot in one program using threads.
# Note: You really should not use this.
# You can easily convert your app
# to use Quart by using async+await
# and then use loop.create_task(bot.start(...))
# before using app.run.
from threading import Thread
from flask import Flask
from functools import partial
from discord.ext import commands
# Initialize our app and the bot itself
app = Flask(__name__)
bot = commands.Bot(command_prefix="!")
# Set up the 'index' route
@app.route("/")
def hello():
return "Hello from {}".format(bot.user.name)
# Make a partial app.run to pass args/kwargs to it
partial_run = partial(app.run, host="0.0.0.0", port=80, debug=True, use_reloader=False)
# Run the Flask app in another thread.
# Unfortunately this means we can't have hot reload
# (We turned it off above)
# Because there's no signal support.
t = Thread(target=partial_run)
t.start()
# Run the bot
bot.run("Your token")
# Now, you can visit your localhost or your VPS' IP in your browser and you should see a message!
@Digbigpig
Copy link

If I wanted flask to trigger the bot to send a message how would I do that?
Without making the hello function async and awaiting bot.send_message, it wont send the message. I tried switching to Quart since it supports async but then I kept getting "thread has no event loop" error which I couldn't troubleshoot. I've tried about 10 other things as well but im completely stuck right now. Any help is appreciated.

@CraigRobertWhite
Copy link

Did you get this to work?

@crrapi
Copy link
Author

crrapi commented Oct 5, 2019

Hey @Digbigpig,
Sorry for the late response, but you can use bot.loop.create_task(coro) to run a coroutine (e.g. bot.loop.create_task(channel.send("Hello")))

@antsankov
Copy link

antsankov commented May 11, 2020

In case anyone needs help with just sending messages to a server inside of a flask function. I spent hours with this problem myself after going down the rabbit hole of asyncio and threading. Turned out to be way easier than I thought. Webhooks, unlike a regular Discord bot, are entirely synchronous, which means they can run in a flask function no problem.

If your goal is to just simply send a message to a channel from a flask endpoint and not use any other functionality, try webhooks.

from discord import Webhook, RequestsWebhookAdapter
webhook = Webhook.partial(WEB_HOOK_ID, 'WEB_HOOK_TOKEN', adapter=RequestsWebhookAdapter())

and then post the message

 webhook.send('MESSAGE', username='WEBHOOK_BOT')

Creating Webhook tutorial

Discord.py Webhook Info

@anshulxyz
Copy link

anshulxyz commented Aug 26, 2020

Had a discussion with Alex here. His solution works if you want to send text (or embeds), since that is the limitation of the discord websockets.

But if you want a full bot approach, you can tryusing aiohttp to listen to HTTP requests.

The Flask based solution as suggested by OP doesn't seem to work for me. It might have to do with asynchronously running Flask.

The code below is a Cog based solution from https://stackoverflow.com/questions/52336409/discord-py-rewrite-basic-aiohttp-webserver-in-a-cog

I have fixed indentation and a TypeError. And added a route to listen to POST request.

from aiohttp import web
import asyncio
import discord 
from discord.ext import commands

class Youtube(commands.Cog):

    def __init__(self, bot):
        self.bot = bot

    async def webserver(self):
        async def handler(request):
            return web.Response(text="Hello, world")

        async def post_handler(request):
            # prints the payload received in POST request
            print(await request.json())
            return web.Response(text="post request")

        app = web.Application()
        app.router.add_get('/', handler)
        app.router.add_post('/', post_handler)
        runner = web.AppRunner(app)
        await runner.setup()
        self.site = web.TCPSite(runner, '127.0.0.1', 8080)
        await self.bot.wait_until_ready()
        await self.site.start()

    def __unload(self):
        asyncio.ensure_future(self.site.stop())

def setup(bot):
    yt = Youtube(bot)
    bot.add_cog(yt)
    bot.loop.create_task(yt.webserver())```

This is a bare-bones example, you can build on top of it.

For any help, feel free to DM me at https://twitter.com/anshulxyz

@perymerdeka
Copy link

Had a discussion with Alex here. His solution works if you want to send text (or embeds), since that is the limitation of the discord websockets.

But if you want a full bot approach, you can tryusing aiohttp to listen to HTTP requests.

The Flask based solution as suggested by OP doesn't seem to work for me. It might have to do with asynchronously running Flask.

The code below is a Cog based solution from https://stackoverflow.com/questions/52336409/discord-py-rewrite-basic-aiohttp-webserver-in-a-cog

I have fixed indentation and a TypeError. And added a route to listen to POST request.

from aiohttp import web
import asyncio
import discord 
from discord.ext import commands

class Youtube(commands.Cog):

    def __init__(self, bot):
        self.bot = bot

    async def webserver(self):
        async def handler(request):
            return web.Response(text="Hello, world")

        async def post_handler(request):
            # prints the payload received in POST request
            print(await request.json())
            return web.Response(text="post request")

        app = web.Application()
        app.router.add_get('/', handler)
        app.router.add_post('/', post_handler)
        runner = web.AppRunner(app)
        await runner.setup()
        self.site = web.TCPSite(runner, '127.0.0.1', 8080)
        await self.bot.wait_until_ready()
        await self.site.start()

    def __unload(self):
        asyncio.ensure_future(self.site.stop())

def setup(bot):
    yt = Youtube(bot)
    bot.add_cog(yt)
    bot.loop.create_task(yt.webserver())```

This is a bare-bones example, you can build on top of it.

For any help, feel free to DM me at https://twitter.com/anshulxyz

How do I run and manage the discord bot using the web, I'm creating a panel in flask but I haven't found a way to connect so that I can interact with each other?

@TheRedstoneRadiant
Copy link

Hey @Digbigpig,
Sorry for the late response, but you can use bot.loop.create_task(coro) to run a coroutine (e.g. bot.loop.create_task(channel.send("Hello")))

Awesome!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment