Как отправить сообщение с помощью discord.py вне цикла событий (т. Е. Из потока python-telegram-bot)? - PullRequest
0 голосов
/ 11 декабря 2018

Я хочу использовать make-бот, который обменивается данными между discord и telegram, используя библиотеки python-telegram-bot и discord.py (версия 1.0.0).Однако проблема в том, что discord.py использует асинхронные функции и потоки python-telegram-bot.С помощью приведенного ниже кода все прекрасно работает для сообщений, отправляемых в разногласиях (бот отправляет их правильно в telegram), однако, наоборот, не работает (бот получает сообщения из telegram и отправляет их в разбор).Ранее у меня были проблемы с синтаксисом / ошибками времени выполнения, когда я пытался запустить функцию discords channel.send в функции синхронизации (таким образом, либо возвращая только объект-генератор, либо жаловался, что я не могу использовать await в функции синхронизации).Тем не менее, в то же время MessageHandler python-telegram-bot нуждается в функции синхронизации, поэтому, давая ему асинхронную функцию, Python жалуется, что «await» никогда не вызывался для асинхронной функции.Теперь я попытался использовать метод async_to_sync из библиотеки asgiref для запуска моего асинхронного broadcastMsg из MessageHandler, однако код по-прежнему не отправляет сообщение на разногласия!Кажется, что функция вызывается правильно, но только до строки print('I get to here').Ошибка не отображается, и сообщение не появляется в разногласиях.Я предполагаю, что это как-то связано с тем фактом, что я должен зарегистрировать функцию как задачу в цикле событий discord.py, однако регистрация работает только тогда, когда это происходит до того, как botDiscord.run(TOKENDISCORD) выполнено, что, конечно, должно произойти раньше,Итак, сводим мою проблему к одному вопросу: как я могу взаимодействовать с циклом событий discord.py из другого потока (из телеграммы MessageHandler).Или, если это невозможно: как я могу отправить сообщение с discord.py, не будучи в цикле событий discord.py?

Спасибо за вашу помощь

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:\n%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)  

1 Ответ

0 голосов
/ 11 декабря 2018

Как я могу отправить сообщение с discord.py, не находясь в цикле событий discord.py?

Чтобы безопасно запланировать сопрограмму из-за пределов потока цикла событий, используйте asyncio.run_coroutine_threadsafe:

_loop = asyncio.get_event_loop()

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