从线程内部发送消息时出现discord.py错误

问题描述

我有一个 discord.py 机器人来访问 Politics & 的 API战争,我有一个线程每 20 分钟检查一次以检查新活动.我已经尝试将这部分放在 on_ready 中,但这似乎会停止执行任何命令,所以我不得不创建一个线程.但是,当我尝试运行此代码并且有新活动要发送消息时,它会引发 RuntimeError:

I have a discord.py bot to access the API for Politics & War, and I have a thread to check every 20 minutes to check for new activity. I have tried putting this part in on_ready, but this seems to stop the execution of any commands, so I had to create a thread. However, when I try to run this code, and there is new activity to send a message about, it raises a RuntimeError:

Exception in thread Thread-1:
Traceback (most recent call last):
  File "C:Users
aturAppDataLocalProgramsPythonPython38lib	hreading.py", line 932, in _bootstrap_inner
    self.run()
  File "C:Users
aturAppDataLocalProgramsPythonPython38lib	hreading.py", line 870, in run
    self._target(*self._args, **self._kwargs)
  File "C:/Users/natur/Desktop/Trans-Atlantic-Bot/BOT/main.py", line 100, in update
    asyncio.run(update_war())
  File "C:Users
aturAppDataLocalProgramsPythonPython38libasynciounners.py", line 44, in run
    return loop.run_until_complete(main)
  File "C:Users
aturAppDataLocalProgramsPythonPython38libasyncioase_events.py", line 616, in run_until_complete
    return future.result()
  File "C:/Users/natur/Desktop/Trans-Atlantic-Bot/BOT/main.py", line 61, in update_war
    defense_channel = await client.fetch_channel(CHANNEL_1)
  File "C:Users
aturAppDataLocalProgramsPythonPython38libsite-packagesdiscordclient.py", line 1447, in fetch_channel
    data = await self.http.get_channel(channel_id)
  File "C:Users
aturAppDataLocalProgramsPythonPython38libsite-packagesdiscordhttp.py", line 185, in request
    async with self.__session.request(method, url, **kwargs) as r:
  File "C:Users
aturAppDataLocalProgramsPythonPython38libsite-packagesaiohttpclient.py", line 1012, in __aenter__
    self._resp = await self._coro
  File "C:Users
aturAppDataLocalProgramsPythonPython38libsite-packagesaiohttpclient.py", line 426, in _request
    with timer:
  File "C:Users
aturAppDataLocalProgramsPythonPython38libsite-packagesaiohttphelpers.py", line 579, in __enter__
    raise RuntimeError('Timeout context manager should be used '
RuntimeError: Timeout context manager should be used inside a task


import os
import time
import json
import difflib
import datetime
import asyncio
import threading
import requests
import discord
from discord.ext import commands

TOKEN = os.environ.get("TRANSATLANTICBOT")
KEY = os.environ.get("PNWKEY")

command_dict = {
    "help": "Lists the commands and their descriptions",
    "help_commands": "ALIAS: help",
    "city": "Gets information about the specified city. URL and ID are both accepted.",
}


def req(loc, key_provider=None):
    if key_provider is not None:
        return requests.get(f"https://politicsandwar.com/api/{loc}{key_provider}key={KEY}").json()
    if "=" in loc:
        return requests.get(f"https://politicsandwar.com/api/{loc}&key={KEY}").json()
    else:
        return requests.get(f"https://politicsandwar.com/api/{loc}/?key={KEY}").json()


def dict_to_string(d):
    newline = "
"
    return f'```yml
{newline.join((f"{key}: {value}" for key, value in d.items()))}
```'


async def get_nation(ctx, n_id):
    if not n_id.isdigit():
        if n_id.startswith("http"):
            n_id = n_id[n_id.find("=") + 1].rstrip("/")
        else:
            pass
    return n_id


# update
async def update_war():
    start_time = time.time()
    print("
WAR")
    print(f"Update Started - 0 secs")
    new = req("wars?alliance_id=7536")
    print(f"Recieved Data - {time.time() - start_time} secs")
    if "success" in new.keys():
        lastcheck = datetime.datetime.utcnow() - datetime.timedelta(hours=0, minutes=21)
        wars = new["wars"]
        war_time = datetime.datetime.strptime(wars[0]["date"][:19], "%Y-%m-%dT%X")
        war = 0
        while war_time >= lastcheck:
            current_war = wars[war]
            war_time = datetime.datetime.strptime(wars[war + 1]["date"][:19], "%Y-%m-%dT%X")
            if current_war["attackerAA"] in ("Atlantian Council", "Atlantian Council Applicant"):
                defense_channel = await client.fetch_channel(CHANNEL_1)
            else:
                defense_channel = await client.fetch_channel(CHANNEL_2)

            spec_war = req(f"war/{current_war['warID']}", "/&")

            emb = discord.Embed(
                title="WAR REPORT",
                description=dict_to_string(spec_war),
                color=discord.Color(0x00ff00)
            )
            emb.set_footer(text=f"P&W bot for ANYONE, unlike SOME OTHER BOT  -  Requested by The Atlantian Council")

            await defense_channel.send(embed=emb)
            war += 1
        print(f"Update Success - {time.time() - start_time} secs")
    else:
        print(f"Upate Failure - {time.time() - start_time} secs")
    print(f"Waiting for next update - {time.time() - start_time} secs")


async def update_nations():
    start_time = time.time()
    print("
NATION")
    print(f"Update Started - 0 secs")
    with open("all_nations.json", "w") as nations:
        new = req("nations")
        print(f"Recieved Data - {time.time() - start_time} secs")
        if "success" in new.keys():
            json.dump(new, nations)
            print(f"Update Success - {time.time() - start_time} secs")
        else:
            print(f"Upate Failure - {time.time() - start_time} secs")
    print(f"Waiting for next update - {time.time() - start_time} secs")


def update():
    while True:
        try:
            asyncio.run(update_war())
            asyncio.run(update_nations())
        except Exception as e:
            print("

ERROR HAPPENED
")
            print(e)

        time.sleep(60 * 20)


updater = threading.Thread(target=update, daemon=True)

# run bot
client = commands.Bot(command_prefix=("^", "!", "also,
", "also, ", "tst!"))
client.remove_command("help")


@client.event
async def on_ready():
    await client.change_presence(
        status=discord.Status.online,
        activity=discord.Game(name="P&W")
    )
    print("BOT READY")

    updater.start()


解决方案

async def start():
    await bot.wait_until_ready()
    # Whatever function you want

bot.loop.create_task(start())

相关文章