【问题标题】:Why can I not send a message via Discord.py from a function?为什么我不能通过 Discord.py 从函数发送消息?
【发布时间】:2017-09-12 16:03:04
【问题描述】:

我创建了一个脚本,它接收格式为!notice [MM/DD/YY HH:mm], message, target 的消息,然后使用threading.Timer 调用一个函数,以便在消息中给出的UTC 时间调用它。

我遇到的问题是从此函数发送消息,无论消息的输入如何,我似乎都无法从该函数发送消息。

见下文:

import discord
import asyncio
from datetime import *
import threading

client = discord.Client()

@client.event
async def on_message(message):
    if message.content[:7].lower() == "!notice".lower():
        try:
            notice = [datetime.strptime(message.content[message.content.find("[")+1:message.content.find("]")], "%m/%d/%y %H:%M"), message.content.split(", ")[1], message.content.split(", ")[2]]
            await client.send_message(message.channel, 'Created notice "'+notice[1]+'" to be sent to '+notice[2]+' at '+str(notice[0])+' UTC.')
            threading.Timer((notice[0] - datetime.utcnow()).total_seconds(), lambda a=notice[1], b=notice[2]: func(a, b)).start()
            print(str((notice[0] - datetime.utcnow()).total_seconds())+" seconds until message is sent")
        except (ValueError, IndexError):
            await client.send_message(message.channel, 'Incorrect Notice Format.\nMust be "!notice [MM/DD/YY HH:mm], Notice contents, Target".\nEG: "!notice [01/01/2017 12:00], This is a notice, Siren Raid Team".')

def func(message, target):
    print("Func called")
    for i in client.servers:
        for c in i.channels:
            client.send_message(c, target+message)

client.run(MY_SESSION_KEY)

这会返回"Func called",所以我知道该函数正在被调用,但没有引发异常,也没有在我的聊天中发布消息。

我还尝试将func 替换为:

async def func(message, target):
    print("Func called")
    for i in client.servers:
        for c in i.channels:
            await client.send_message(c, target+message)

但是这会引发异常:

RuntimeWarning:从未等待协程“func”

坦率地说,我在这里超出了我的深度。这有什么不可行的原因吗?

我在网上看到asyncio 不是线程安全的。但是,除非我有误解,否则我的第一个示例没有在函数中使用该库。是否仍然会导致问题?

【问题讨论】:

  • 现在,您的func() 将尝试向每个服务器中的每个通道发送消息,直到遇到无法发送到的通道并崩溃。您可能应该考虑使用discord.utils.get 来找到您要发送的实际目标。
  • @squaswin 这是出于故障排除的目的,以检查我是否能够在任何频道上收到消息,在此之前我将 message 对象传递给函数并尝试将通知发送到 @ 987654332@。此外,如果我设置 logging 以获取有关问题的更多信息,我不会收到任何错误,如果我尝试发送到语音频道或我无权访问的频道,我通常会这样做。

标签: python-3.x python-multithreading python-asyncio discord.py


【解决方案1】:

discord.py 的 discord.Client.send_message 是一个协程,必须是 awaited,就像你在第二个代码 sn-p 中所做的那样。但是,threading.Timer 不支持协程。 您正在寻找的是create_task,它使您能够在事件循环上运行协程。由于您的协程所做的大部分工作都是休眠(模仿threading.Timer),因此您的on_message 将继续运行,因为您使用asyncio.sleep 而不是time.sleep - 后者会阻塞事件循环。这是一个示例,包括将参数传递给函数:

import asyncio

loop = asyncio.get_event_loop()

async def sleep_and_add(a, b):
    await asyncio.sleep(3)
    print(a, '+', b, 'is', a + b)

async def on_message():
    # prepare arguments to your function
    loop.create_task(sleep_and_add(2, 3))
    # continue doing other things

【讨论】:

    【解决方案2】:

    如果有人需要帮助,只需从烧瓶函数内部向服务器发送消息。在陷入异步和线程的兔子洞之后,我自己花了几个小时来解决这个问题。结果比我想象的要容易得多。与常规的 Discord 机器人不同,Webhooks 是完全同步的,这意味着它们可以毫无问题地在烧瓶函数中运行。

    如果您的目标只是简单地从烧瓶端点向通道发送消息而不使用任何其他功能,请尝试使用 webhook。

    from discord import Webhook, RequestsWebhookAdapter
    webhook = Webhook.partial(WEB_HOOK_ID, 'WEB_HOOK_TOKEN', adapter=RequestsWebhookAdapter())
    

    然后发布消息

     webhook.send('MESSAGE', username='WEBHOOK_BOT')
    

    Creating Webhook tutorial

    Discord.py Webhook Info

    【讨论】:

    • 我知道我们不应该发布感谢 cmets,但这正是我正在寻找的场景,这对我有很大帮助。谢谢!
    猜你喜欢
    • 2021-03-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-11-10
    • 2021-04-21
    • 2022-01-11
    • 2021-08-31
    相关资源
    最近更新 更多