为什么我不能通过功能从Discord.py发送消息?

时间:2017-09-12 16:03:05

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

我创建了一个脚本,它接收格式化为!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:coroutine' func'从未等待过

坦率地说,我在这里已经超出了我的深度。这有什么理由不起作用吗?

我在网上看到asyncio不是线程安全的。但是,除非我有误解,否则我的第一个例子并没有在函数中使用该库。可能还会造成问题吗?

2 个答案:

答案 0 :(得分:2)

discord.py discord.Client.send_message是一个协程,必须是awaited,就像您在第二个代码段中所做的那样。但是,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

答案 1 :(得分:2)

万一有人需要帮助,只需从flask函数内部将消息发送到服务器即可。在经历了异步和线程的麻烦之后,我自己花了几个小时解决这个问题。原来比我想象的要容易得多。与常规的Discord机器人不同,Webhooks是完全同步的,这意味着它们可以在flask功能中运行。

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

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