Discord机器人wait_for未按指定条件筛选消息问题排查
Discord Bot wait_for 校验失效问题排查与修复
问题描述
使用wait_for等待满足以下条件的消息时,机器人会响应任意消息并执行后续命令,无报错:
- 消息来自特定作者(ID: 282859044593598464)
- 提及指定用户(ID: 994347081294684240)
- 包含计算后的总金额(商品价格×数量+税费)
核心问题分析
缩进错误导致逻辑混乱
原代码中if type == "netflix":块未缩进在buy函数内部,导致该代码块在机器人启动时执行(而非命令调用时),且内部函数check无法被外部正确访问,引发wait_for执行时机错误。分支逻辑错误
elif type == "spotify" or "crunchyroll"写法不符合Python语法,"crunchyroll"会被视为布尔值True,导致所有非Netflix的请求都走Spotify逻辑分支;若type为其他值,check函数无返回值(默认返回None),wait_for会将None视为False,引发异常等待行为。字符串包含判断逻辑错误
int(nettax + netfprice) in message.content是无效判断:in操作符要求左右两侧同为字符串类型,整数与字符串的包含判断永远返回False,导致符合条件的消息无法通过校验。冗余计算与数据不一致风险
check函数内重复查询数据库计算金额,不仅冗余,还可能因数据库数据变化,导致与buy命令内计算的金额不一致,引发校验失败。
修复后的完整代码
import asyncio import discord import sqlite3 from discord.ext import commands from typing import Optional # 假设bot和tax函数已定义 bot = commands.Bot(command_prefix="!", intents=discord.Intents.all()) async def tax(args): # 替换为实际税费计算逻辑 return args * 0.1 @bot.slash_command() @commands.cooldown(1, 60, commands.BucketType.user) async def buy(message, type: str, amount: Optional[int] = 1): if amount < 0: await message.respond("You cannot buy negative amount of accounts") return member = message.author con = sqlite3.connect("db.sqlite") c = con.cursor() # 提前计算总金额,避免重复查询数据库 total_amount = None if type == "netflix": c.execute("SELECT price FROM netflix") netprice = c.fetchone()[0] newnet = netprice * amount withtax = await tax(args=newnet) total_amount = newnet + withtax elif type in ("spotify", "crunchyroll"): c.execute("SELECT price FROM spotify") spotprice = c.fetchone()[0] newspot = spotprice * amount spotytax = await tax(args=newspot) total_amount = newspot + spotytax else: await message.respond("Invalid service type") con.close() return # Netflix库存检查 if type == "netflix": c.execute('SELECT COUNT(*) FROM netflix') net_stock = c.fetchone()[0] if net_stock < amount: await message.respond(f"We do not have this amount of accounts in the stock") con.close() return # 发送转账提示Embed embed = discord.Embed(title="Transfer", description=f"Please transfer: {total_amount}") embed.add_field( name=f"c <@994347081294684240> {total_amount}", value="**Copy paste the message for no error**" ) embed.set_footer(text=f"Sidtho Host. | Requested by - {message.author}") print("Sent embed, Waiting for receiving the credits") await message.respond(embed=embed) # 定义校验函数,捕获外部计算好的总金额 async def check(msg): try: return (msg.author.id == 282859044593598464 and msg.mentions[0].id == 994347081294684240 and str(total_amount) in msg.content) except IndexError: # 未提及目标用户时返回False return False # 等待符合条件的消息,处理超时 try: await bot.wait_for('message', check=check, timeout=60) except asyncio.TimeoutError: await message.respond("Timeout: No valid payment message received.") con.close() return # 交付账号并更新数据库 if type == "netflix": c.execute("SELECT email, password FROM netflix") netres = c.fetchmany(size=amount) embed = discord.Embed(title=f"حساب {type}", description="") embed.add_field(name="Sidtho Host.", value=" ", inline=False) for email, password in netres: embed.add_field(name=f"Email: {email}", value=f"Password: {password}", inline=False) await member.send(embed=embed) # 批量删除已交付账号 for email, password in netres: c.execute("DELETE FROM netflix WHERE email=? AND password=?", (email, password)) con.commit() elif type in ("spotify", "crunchyroll"): c.execute(f"SELECT email, password FROM {type}") res = c.fetchmany(size=amount) embed = discord.Embed(title=f"حساب {type}", description="") embed.add_field(name="Sidtho Host.", value=" ", inline=False) for email, password in res: embed.add_field(name=f"Email: {email}", value=f"Password: {password}", inline=False) await member.send(embed=embed) for email, password in res: c.execute(f"DELETE FROM {type} WHERE email=? AND password=?", (email, password)) con.commit() con.close() # 运行机器人 bot.run("YOUR_BOT_TOKEN")
修复说明
- 修正缩进:将所有业务逻辑缩进在
buy函数内部,确保命令调用时才执行对应代码。 - 优化分支判断:使用
type in ("spotify", "crunchyroll")替代错误的or写法,增加无效类型的提示。 - 修复包含判断:将总金额转为字符串后再判断是否存在于消息内容中,保证校验逻辑正确。
- 消除冗余计算:提前计算总金额,
check函数直接捕获该变量,避免重复查询数据库,保证金额一致性。 - 完善错误处理:添加
return提前终止无效请求,捕获TimeoutError处理超时情况,避免程序异常。 - 规范数据库操作:库存检查改为直接统计数量,交付后批量删除账号并提交事务,使用后关闭数据库连接避免资源泄漏。
内容的提问来源于stack exchange,提问作者signalmute
相关产品推荐
相关产品推荐

