简体   繁体   English

在同一个应用程序中运行 Flask 和 Discord 机器人

[英]Running Flask & a Discord bot in the same application

I am building a Discord bot in Python and would like to receive HTTP requests from Twitch.tv's API (See Webhooks Guide & Webhooks Reference ) (To subscribe to events like; X streamer has gone live) and based on the content of the HTTP (POST or GET) request received from Twitch, do something on the Discord bot, eg: Output a message on a text channel.我正在用 Python 构建一个 Discord 机器人,并希望从 Twitch.tv 的 API 接收 HTTP 请求(请参阅Webhooks 指南Webhooks 参考)(订阅事件,例如 X 流媒体已上线)并基于 HTTP 的内容( POST 或 GET)从 Twitch 收到的请求,在 Discord 机器人上做一些事情,例如:在文本频道上输出一条消息。

I am using the discord.py Python Discord API/Library.我正在使用discord.py Python Discord API/Library。

I've looked into the matter and found that Flask seemed like a good minimalist choice for a webserver to receive these requests on.我调查了这个问题,发现Flask似乎是一个很好的极简主义选择,让网络服务器接收这些请求。

I should preface this by saying I'm very new to Python and I've never used Flask before.我应该先说我对 Python 非常陌生,而且我以前从未使用过 Flask。

Now.现在。 The problem is I can't seem to figure out a way to run the Flask server inside of my discord bot.问题是我似乎无法找到在我的不和谐机器人内部运行 Flask 服务器的方法。

I've tried adding this simple code into my discord.py script:我尝试将这个简单的代码添加到我的 discord.py 脚本中:

from flask import Flask, request
app = Flask(__name__)
@app.route('/posts', methods=['POST'])
def result():
    print(request.form['sched'])
    # Send a message to a discord text channel etc...
    return 'Received !'

When I run my discord.py script which looks something like this: (Stripped away some commands and features for the sake of keeping this shorter)当我运行我的 discord.py 脚本时,它看起来像这样:(为了保持简短,去掉了一些命令和功能)

import discord
import asyncio

from flask import Flask, request
app = Flask(__name__)
@app.route('/posts', methods=['POST'])
def result():
    print(request.form['sched'])
    # Send a message to a discord text channel etc...
    return 'Received !'

client = discord.Client()

@client.event
async def on_ready():
    print('Logged in as')
    print(client.user.name)
    print(client.user.id)
    print('------')

@client.event
async def on_message(message):

    if message.author == client.user:
        return

    content = message.content
    fullUser = message.author.name+'#'+message.author.discriminator
    print(str(message.timestamp)+" #"+message.channel.name+" "+fullUser+": "+str(content.encode('ascii', 'ignore').decode('ascii')))
    if content.startswith('!'):

        content = content[1:]
        if content.startswith('test'):
            counter = 0
            tmp = await client.send_message(message.channel, 'Calculating messages...')
            async for log in client.logs_from(message.channel, limit=100):
                if log.author == message.author:
                    counter += 1

            await client.edit_message(tmp, 'You have {} messages.'.format(counter))

client.run('MyTokenHere')

It seems like if I point flask to discord.py (the above) and run it, it'll start the code, get to the "client.run('MyTokenHere')" part for discord, and just stop at that and run the discord bot.似乎如果我将flask指向discord.py(上面的)并运行它,它将启动代码,进入discord的“client.run('MyTokenHere')”部分,然后停止并运行不和谐机器人。 It's not until I exit out of the bot by doing Ctrl+C that the actual Flask server starts, but now the discord bot is disconnected and no longer does any processing.直到我通过执行 Ctrl+C 退出机器人,实际的 Flask 服务器才启动,但现在不和谐机器人已断开连接,不再进行任何处理。

The same problem persists if I were to for example add "app.run()" somewhere in my code (before calling "client.run()" which starts the Discord bot part) to launch the Flask server;例如,如果我要在代码中的某处添加“app.run()”(在调用启动 Discord bot 部分的“client.run()”之前)以启动 Flask 服务器,同样的问题仍然存在; It'll just run the flask, get stuck on that until I Ctrl+C out of the Flask server, then it'll proceed to start the Discord bot.它只会运行 Flask,在我 Ctrl+C 退出 Flask 服务器之前一直卡在它上面,然后它会继续启动 Discord 机器人。 Ultimately, I need to use the Discord API and I need to be connected to the Discord API gateway and all that good jazz to actually send messages to a channel with the bot, so I don't really know what to do here.最终,我需要使用 Discord API,我需要连接到 Discord API 网关和所有优秀的爵士乐才能使用机器人将消息实际发送到通道,所以我真的不知道在这里做什么。

So.所以。 I think I've tried my best to explain what I'm ultimately trying to achieve here, and hopefully someone can help me find a way to either make this work with Flask, or if there's a better and easier way, provide a different solution.我想我已经尽力解释了我最终要在这里实现的目标,希望有人能帮助我找到一种方法来使用 Flask 进行这项工作,或者如果有更好更简单的方法,请提供不同的解决方案.

This is cog example in discord.py这是 discord.py 中的 cog 示例

I made this thing for dbl (Discord Bot Lists) you can implement, the thing you need.我为 dbl(Discord Bot Lists)制作了这个东西,你可以实现,你需要的东西。

Note: run your heroku app with webprocess注意:使用 webprocess 运行你的 heroku 应用程序

example :例子:
web: python main.py网络:python main.py

Then go on https://uptimerobot.com/ and setup to ping your web app after every 5 minutes然后访问https://uptimerobot.com/并设置为每 5 分钟 ping 您的 Web 应用程序

from aiohttp import web
from discord.ext import commands, tasks
import discord
import os
import aiohttp

app = web.Application()
routes = web.RouteTableDef()


def setup(bot):
    bot.add_cog(Webserver(bot))


class Webserver(commands.Cog):
    def __init__(self, bot):
        self.bot = bot
        self.web_server.start()

        @routes.get('/')
        async def welcome(request):
            return web.Response(text="Hello, world")

        @routes.post('/dbl')
        async def dblwebhook(request):
            if request.headers.get('authorization') == '3mErTJMYFt':
                data = await request.json()
                user = self.bot.get_user(data['user']) or await self.bot.fetch_user(data['user'])
                if user is None:
                    return
                _type = f'Tested!' if data['type'] == 'test' else f'Voted!'
                upvoted_bot = f'<@{data["bot"]}>'
                embed = discord.Embed(title=_type, colour=discord.Color.blurple())
                embed.description = f'**Upvoter :** {user.mention} Just {_type}' + f'\n**Upvoted Bot :** {upvoted_bot}'
                embed.set_thumbnail(url=user.avatar_url)
                channel = self.bot.get_channel(5645646545142312312)
                await channel.send(embed=embed)
            return 200

        self.webserver_port = os.environ.get('PORT', 5000)
        app.add_routes(routes)

    @tasks.loop()
    async def web_server(self):
        runner = web.AppRunner(app)
        await runner.setup()
        site = web.TCPSite(runner, host='0.0.0.0', port=self.webserver_port)
        await site.start()

    @web_server.before_loop
    async def web_server_before_loop(self):
        await self.bot.wait_until_ready()

As the kind commenters informed me;正如好心的评论者告诉我的那样; threading seems like the way to go. 线程似乎是要走的路。 Thanks guys!谢谢各位!

Another cool way if you aren't going to use flask extensions, use quart instead of flask, then it will super easy for you.如果您不打算使用烧瓶扩展,另一种很酷的方法是使用夸脱而不是烧瓶,那么这对您来说将非常容易。

Note: Run your heroku app with webprocess注意:使用 webprocess 运行您的 heroku 应用程序

example : web: python main.py示例:网络:python main.py

Then go on https://uptimerobot.com/ and setup to ping your web app after every 5 minutes然后访问https://uptimerobot.com/并设置为每 5 分钟 ping 您的 Web 应用程序

# Code Example
from discord.ext import commands
from quart import Quart
import os
app = Quart(__name__)

bot = commands.Bot('!')

@bot.command()
async def something(ctx):
    ...

"""
Note: On Heroku you cant bind your webserver with 5000 port as they aren't static.

To fix above problem you will have to get dynamic port from the environment variable and you are good to go.

"""

PORT = os.environ.get('PORT')

bot.loop.create_task(app.run_task('0.0.0.0', PORT))

bot.run('Token')

Or you can use the Terminal Multiplexer, tmux to run them independently!.或者您可以使用终端多路复用器tmux来独立运行它们!。 If you are running on a Linux platform, tmux python3 flaskapp.py would run the flask app, while you can independently run the discord bot.如果你在 Linux 平台上运行, tmux python3 flaskapp.py将运行flask应用程序,而你可以独立运行discord bot。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM