如何从事件循环外部(即从 python-telegram-bot 线程)发送带有 discord.py 的消息? [英] How to send a message with discord.py from outside the event loop (i.e. from python-telegram-bot thread)?

查看:25
本文介绍了如何从事件循环外部(即从 python-telegram-bot 线程)发送带有 discord.py 的消息?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想使用库 python-telegram-bot 和 discord.py(版本 1.0.0)制作一个在 discord 和 telegram 之间进行通信的机器人.然而问题是 discord.py 使用异步函数和 python-telegram-bot 线程.使用下面的代码,在不和谐中发布的消息一切正常(机器人将它们正确地发送到电报),但是相反的方法不起作用(机器人从电报中获取消息并将其发送到不和谐).我以前在尝试在同步函数中运行 discords channel.send 函数时遇到语法/运行时错误问题(因此要么只返回一个生成器对象,要么抱怨我不能使用 await 在同步函数中).然而,与此同时,python-telegram-bot 的 MessageHandler 需要一个同步函数,因此当给他一个异步函数时,Python 抱怨说,异步函数从未调用过等待".我现在尝试使用 asgiref 库中的 async_to_sync 方法从 MessageHandler 运行我的异步 broadcastMsg,但是代码仍然没有将消息发送到不和谐!它似乎正确调用了该函数,但仅在 print('I get to here') 行之前.没有显示错误,也没有不和谐的消息弹出.我想这与我必须将函数注册为 discord.py 事件循环中的任务这一事实有关,但是注册仅在 botDiscord.run(TOKENDISCORD) 之前发生时才有效已经被执行,这当然必须在之前发生.所以把我的问题归结为一个问题:我如何能够与来自另一个线程(来自电报 MessageHandler)的 discord.py 事件循环进行交互.或者如果这是不可能的:如何在不进入 discord.py 事件循环的情况下使用 discord.py 发送消息?

I want to use make a bot that communicates between discord and telegram by using the libraries python-telegram-bot and discord.py (version 1.0.0). However the problem is that discord.py uses async functions and python-telegram-bot threading. With the code below, everything works fine for messages being posted in discord (the bot sends them correctly to telegram), however the other way around does not work (bot gets messages from telegram and sends it to discord). I previously had issues with syntax/runtime errors as I tried to run the discords channel.send function in a sync function (thus either returning only a generator object or complaining that I cannot use await in a sync function). However, at the same time the python-telegram-bot's MessageHandler needs a sync function so when giving him a async function Python complains that "await" was never called for the async function. I now tried to use the async_to_sync method from asgiref library to run my async broadcastMsg from the MessageHandler, however the code still does not send the message to discord! It seems to call the function correctly but only until line print('I get to here'). No error is displayed and no message is poping up in discord. I guess it has something to do with the fact that I have to register the function as a task in the discord.py event loop, however registering is only working when it happens before botDiscord.run(TOKENDISCORD) has been executed which of course has to happen before. So to boil my problem down to one question: How am I able to interact with the discord.py event loop from another thread (which is from the telegram MessageHandler). Or if this is not possible: How can I send a message with discord.py without being within the discord.py event loop?

感谢您的帮助

import asyncio
from asgiref.sync import async_to_sync
from telegram import Message as TMessage
from telegram.ext import (Updater,Filters,MessageHandler)
from discord.ext import commands
import discord

TChannelID = 'someTelegramChannelID'
DChannel = 'someDiscordChannelObject'

#%% define functions / commands
prefix = "?"
botDiscord = commands.Bot(command_prefix=prefix)
discordChannels = {}


async def broadcastMsg(medium,channel,message):
    ''' 
    Function to broadcast a message to all linked channels.
    '''
    if isinstance(message,TMessage):
        fromMedium = 'Telegram'
        author = message.from_user.username
        channel = message.chat.title
        content = message.text
    elif isinstance(message,discord.Message):
        fromMedium = 'Discord'
        author = message.author
        channel = message.channel.name
        content = message.content
    # check where message comes from        
    textToSend = '%s wrote on %s %s:
%s'%(author,fromMedium,channel,content)
    # go through channels and send the message
    if 'telegram' in medium:
        # transform channel to telegram chatID and send
        updaterTelegram.bot.send_message(channel,textToSend)

    elif 'discord' in medium:
        print('I get to here')
        await channel.send(textToSend)

    print("I do not get there")


@botDiscord.event
async def on_message(message):
    await broadcastMsg('telegram',TChannelID,message)

def on_TMessage(bot,update):
    # check if this chat is already known, else save it
    # get channels to send to and send message
    async_to_sync(broadcastMsg)('discord',DChannel,update.message)


#%% initialize telegram and discord bot and run them
messageHandler = MessageHandler(Filters.text, on_TMessage)
updaterTelegram = Updater(token = TOKENTELEGRAM, request_kwargs={'read_timeout': 10, 'connect_timeout': 10})
updaterTelegram.dispatcher.add_handler(messageHandler)
updaterTelegram.start_polling()
botDiscord.run(TOKENDISCORD)  

推荐答案

如何在不进入 discord.py 事件循环的情况下使用 discord.py 发送消息?

How can I send a message with discord.py without being within the discord.py event loop?

要从事件循环线程之外安全地安排协程,请使用 asyncio.run_coroutine_threadsafe:

To safely schedule a coroutine from outside the event loop thread, use asyncio.run_coroutine_threadsafe:

_loop = asyncio.get_event_loop()

def on_TMessage(bot, update):
    asyncio.run_coroutine_threadsafe(
        broadcastMsg('discord', DChannel, update.message), _loop)

这篇关于如何从事件循环外部(即从 python-telegram-bot 线程)发送带有 discord.py 的消息?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆