问题描述
我有一个 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())