从循环函数发送 Discord 消息

时间:2021-01-03 22:51:43

标签: python-3.x discord.py

所以我在试图让这段代码工作时遇到了障碍。

我正在编写一个相当简单的 Discord 机器人,它可以做两件事。

机器人的主要部分是在机器人初始化时运行 API 请求以获取返回的基本值。然后我有一个函数,我想每 X 秒运行一次,再次检查该值,如果它发生变化,则向 Discord 通道发送一条消息,然后将变量更新为新值,以便循环可以报告它何时发生又改了。

第二部分不是那么重要,但我仍然想包括它,是用户可以发送机器人命令来报告返回的当前值。

问题#1:当我在没有代码的情况下启动循环以通过不和谐消息发送结果时出现。如果我不包括在循环代码中发送不和谐消息的行,循环将运行并将结果打印到控制台(用于测试目的)。但是,当循环运行时,我无法再让机器人响应命令。

问题#2:如果我包含发送不和谐消息的代码,整个事情立即失败并给我以下错误:


  File "bot.py", line 67, in <module>

    asyncio.run(update_status())

  File "/usr/lib/python3.7/asyncio/runners.py", line 43, in run

    return loop.run_until_complete(main)

  File "/usr/lib/python3.7/asyncio/base_events.py", line 584, in run_until_complete

    return future.result()

  File "bot.py", line 63, in update_status

    await channel.send(f'Server status is still: {updatestatus}.')

  File "/usr/local/lib/python3.7/dist-packages/discord/abc.py", line 905, in send

    nonce=nonce, allowed_mentions=allowed_mentions)

  File "/usr/local/lib/python3.7/dist-packages/discord/http.py", line 185, in request

    async with self.__session.request(method, url, **kwargs) as r:

  File "/usr/local/lib/python3.7/dist-packages/aiohttp/client.py", line 1012, in __aenter__

    self._resp = await self._coro

  File "/usr/local/lib/python3.7/dist-packages/aiohttp/client.py", line 357, in _request

    raise RuntimeError('Session is closed')

RuntimeError: Session is closed

问题 #3:更多的小麻烦,但如果我设置我的代码使其在问题 #1 中工作,循环不会自动启动,但只有在我按下 Ctrl+C 之后(注意:我正在编写通过 PuTTY 在 Raspi 4 上的代码。

有什么想法吗?

完整代码:

# bot.py
import os
import requests
import discord
import json
import asyncio

from dotenv import load_dotenv
from discord.ext import commands
from discord.ext import tasks
from discord.utils import get

load_dotenv()
TOKEN = os.getenv('DISCORD_TOKEN')
CLIENTID = os.getenv('CLIENT_ID')
CLIENTSECRET = os.getenv('CLIENT_SECRET')

bot = commands.Bot(command_prefix='+')

@bot.event
async def on_ready():
        print(f'{bot.user.name} has connected to Discord!')
        channel = bot.get_channel(795162312112865280)
        await channel.send('MurkyBot has connected')

def create_access_token(client_id, client_secret, region = 'us'):
        data = { 'grant_type': 'client_credentials' }
        response = requests.post('https://%s.battle.net/oauth/token' % region, data=data, auth=(client_id, client_secret))
        return response.json()

tokenresponse = create_access_token(CLIENTID, CLIENTSECRET)
accesstoken = tokenresponse["access_token"]
print(accesstoken)

initialrequest = requests.get(f'https://us.api.blizzard.com/data/wow/connected-realm/154?namespace=dynamic-us&locale=en_US&access_token={accesstoken}')
initialrequest = initialrequest.json()
initialstatus = initialrequest['status']['type']
print(f'Initial status: {initialstatus}')

@bot.command(name='status', help='Gets the current server status')
async def manual_status(ctx):
       manualrequest = requests.get(f'https://us.api.blizzard.com/data/wow/connected-realm/154?namespace=dynamic-us&locale=en_US&access_token={accesstoken}')
       manualrequest = manualrequest.json()
       manualstatus = manualrequest['status']['type']
       channel = bot.get_channel(795162312112865280)
       await ctx.send(f'Current world server status is: {manualstatus}')

bot.run(TOKEN)

async def update_status():
        while True:
                global initialstatus
                channel = bot.get_channel(795162312112865280)
                updaterequest = requests.get(f'https://us.api.blizzard.com/data/wow/connected-realm/154?namespace=dynamic-us&locale=en_US&access_token={accesstoken}')
                updaterequest = updaterequest.json()
                updatestatus = updaterequest['status']['type']
                if updatestatus != initialstatus:
                        await channel.send(f'Server status has changed to: {updatestatus}!')
                        initialstatus = updatestatus
                        print('Status Change')
                        await asyncio.sleep(5)
                else:
                        await channel.send(f'Server status is still: {updatestatus}.')
                        print('No Change')
                        await asyncio.sleep(5)

asyncio.run(update_status())

1 个答案:

答案 0 :(得分:0)

.run 是一个阻塞调用,意味着一切都停止并等待它完成。因此,第二部分只能在 ctrl+c 后运行,但脚本结束。

您可能想查看 discord.ext.tasks,它将具有预期的功能。

对于您要执行的操作,以下是使用 discord.ext.tasks 的更新代码:

from dotenv import load_dotenv
from discord.ext import commands
from discord.ext import tasks
from discord.utils import get

load_dotenv()
TOKEN = os.getenv('DISCORD_TOKEN')
CLIENTID = os.getenv('CLIENT_ID')
CLIENTSECRET = os.getenv('CLIENT_SECRET')

bot = commands.Bot(command_prefix='+')

@tasks.loop(seconds=60.0)
async def update_status():
        while True:
                global initialstatus
                channel = bot.get_channel(795162312112865280)
                updaterequest = requests.get(f'https://us.api.blizzard.com/data/wow/connected-realm/154?namespace=dynamic-us&locale=en_US&access_token={accesstoken}')
                updaterequest = updaterequest.json()
                updatestatus = updaterequest['status']['type']
                if updatestatus != initialstatus:
                        await channel.send(f'Server status has changed to: {updatestatus}!')
                        initialstatus = updatestatus
                        print('Status Change')
                        await asyncio.sleep(5)
                else:
                        await channel.send(f'Server status is still: {updatestatus}.')
                        print('No Change')
                        await asyncio.sleep(5)


@bot.event
async def on_ready():
        update_status.start()
        print(f'{bot.user.name} has connected to Discord!')
        channel = bot.get_channel(795162312112865280)
        await channel.send('MurkyBot has connected')

def create_access_token(client_id, client_secret, region = 'us'):
        data = { 'grant_type': 'client_credentials' }
        response = requests.post('https://%s.battle.net/oauth/token' % region, data=data, auth=(client_id, client_secret))
        return response.json()

tokenresponse = create_access_token(CLIENTID, CLIENTSECRET)
accesstoken = tokenresponse["access_token"]
print(accesstoken)

initialrequest = requests.get(f'https://us.api.blizzard.com/data/wow/connected-realm/154?namespace=dynamic-us&locale=en_US&access_token={accesstoken}')
initialrequest = initialrequest.json()
initialstatus = initialrequest['status']['type']
print(f'Initial status: {initialstatus}')

@bot.command(name='status', help='Gets the current server status')
async def manual_status(ctx):
       manualrequest = requests.get(f'https://us.api.blizzard.com/data/wow/connected-realm/154?namespace=dynamic-us&locale=en_US&access_token={accesstoken}')
       manualrequest = manualrequest.json()
       manualstatus = manualrequest['status']['type']
       channel = bot.get_channel(795162312112865280)
       await ctx.send(f'Current world server status is: {manualstatus}')



bot.run(TOKEN)