@NeoLight3

Как сделать авто-отправку сообщений в дискорд боте?

У меня есть интернет сокет, я хочу чтобы сокет проверялся в цикле while True:
при наличии нового сообщения на него, и чтобы при получении он сразу отправлял его в нужный мне дискорд канал по id.
Каким образом я могу это сделать?
def CheckForNewMsgs:
    channel = client.get_channel(755448398584479824)
    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    server_address = ('127.0.0.1', 6000)
    sock.bind(server_address)
    sock.listen(10)
    while True:
        connection, client_address = sock.accept()
        data = connection.recv(16)
        serial = data.decode('utf-8')
        datas = serial.split('|')
        playername = datas[0]
        await channel.send(playername + "connected!")


И при старте я запускаю эту функцию в новом потоке:
nthread = threading.Thread(target=CheckForNewMsgs)
nthread.start()


Однако код не работает, проблема в функции await channel.send(), я не могу её вызвать из моей функции.

Подскажите пожалуйста, что делать?
Я облазил весь Интернет в поисках решения, и не нашёл.
  • Вопрос задан
  • 497 просмотров
Решения вопроса 1
Для таких (и не совсем) целей, в asyncio существуют task'и: https://docs.python.org/3/library/asyncio-task.html
Для контекста дискорда, в discord.py также существует расширение-"обёртка" для этих самых task'ов, с обработкой дискордовских исключений: discord.ext.tasks.

Для запуска блокирующей функции в отдельном потоке существует loop.run_in_executor.

В asyncio всё что выполняется дольше 100ms считается блокирующим. (Developing with asyncio)

Скорее всего вы хотите что-то в таком духе:
import concurrent
...

async def CheckForNewMsgs():
    channel = client.get_channel(755448398584479824)
    sock = socket.socket()  # нужно ли указывать данные аргументы, если они являются стандартными значениями? https://docs.python.org/3/library/socket.html?highlight=socket#socket.socket
    server_address = ('127.0.0.1', 6000)
    sock.bind(server_address)
    sock.listen(10)
    while True:
        with concurrent.futures.ThreadPoolExecutor() as pool:
            connection, client_address = await loop.run_in_executor(pool, sock.accept)  # не уверен что из этого блокирует, что нет, в сокеты особо не углублялся
        data = connection.recv(16)
        serial = data.decode('utf-8')
        datas = serial.split('|')
        playername = datas[0]
        await channel.send(playername + "connected!")

msgs_check_task = asyncio.create_task(CheckForNewMsgs())
# msgs_check_task.cancel() для остановки, подробнее: https://docs.python.org/3/library/asyncio-task.html#asyncio.Task


Заметьте, что данный код никоим образом не отслеживает ошибки дискорда. Именно для этого и может пригодиться discord.ext.tasks:

import concurrent
from discord.ext import tasks
...

@tasks.loop()  # будет работать как while True
async def CheckForNewMsgs():
    channel = client.get_channel(755448398584479824)
    sock = socket.socket()  # нужно ли указывать данные аргументы, если они являются стандартными значениями? https://docs.python.org/3/library/socket.html?highlight=socket#socket.socket
    server_address = ('127.0.0.1', 6000)
    sock.bind(server_address)
    sock.listen(10)
    with concurrent.futures.ThreadPoolExecutor() as pool:
        connection, client_address = await loop.run_in_executor(pool, sock.accept)  # не уверен что из этого блокирует, что нет, в сокеты особо не углублялся
    data = connection.recv(16)
    serial = data.decode('utf-8')
    datas = serial.split('|')
    playername = datas[0]
    await channel.send(playername + "connected!")

CheckForNewMsgs.start()
# CheckForNewMsgs.stop() - остановит после окончания выполнения текущего "прохода", подробнее: https://discordpy.readthedocs.io/en/v1.4.1/ext/tasks/index.html#discord.ext.tasks.Loop.stop
Ответ написан
Комментировать
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы