IRC сообщения случайно не отправляются от бота - PullRequest
0 голосов
/ 19 января 2019

Я написал очень простого бота на Python, чтобы получить webhook, проанализировать данные, а затем отправить сообщения в IRC. Все работает, как и ожидалось, за исключением случайного времени, когда сообщения не будут отправлены. Я не получаю никаких сообщений об ошибках от IRC-сервера, но они просто не отображаются в IRC. Я создаю массив сообщений для отправки, а затем перебираю их для отправки. Я аутентифицируюсь в IRC через SASL. Я подтвердил, что все сообщения в списке, которые должны быть отправлены. Иногда все они отправляют нормально, иногда только некоторые, а иногда ни один из них не отправляет. Я пытаюсь вернуть сообщения с сервера, но, похоже, их нет.

Когда я печатаю массив сообщений, он выглядит так:

['[\x0313repo\x0f] \x0315user-name\x0f force pushed \x021\x0f commit(s) to \x036master\x0f: \x032\x1fhttps://github.com/owner/repo/compare/e1a06c001733...387b204c4303\x0f\r\n', '\x0313repo\x0f/\x036master\x0f \x0314387b204\x0f \x0315user-name\x0f: commit message here\r\n']

Моя команда отправки:

self.irc.send(bytes("PRIVMSG {} :{}\r\n".format(channel, message), "UTF-8"))

Полный код:

import base64
import json
import re
import socket
import ssl
from time import sleep


class IRC(object):

    def __init__(self, sslConfig):
        if sslConfig is True:
            self.irc = ssl.wrap_socket(
                socket.socket(socket.AF_INET, socket.SOCK_STREAM),
                ssl_version=ssl.PROTOCOL_TLSv1_2
            )
        else:
            self.irc = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

    def getText(self):
        text=self.irc.recv(2040)
        return text.decode("UTF-8")

    def waitAndSee(self, search):
        tries = 0
        while True:
            text = self.getText()
            if tries > 20:
                raise ConnectionError("Unable to connect to IRC: %s" % text) 
            ack = re.search(search, text, re.MULTILINE)
            if ack:
                return
            sleep(0.25)
            tries += 1

    def authenticate(self, nick, password):
        self.irc.send(bytes("CAP REQ :sasl\r\n", "UTF-8"))
        self.waitAndSee(r'(.*)CAP(.*)ACK(.*)')
        self.irc.send(bytes("AUTHENTICATE PLAIN\r\n", "UTF-8"))
        self.waitAndSee(r'(.*)AUTHENTICATE \+(.*)')
        auth = (
            "{nick}\0{nick}\0{password}"
        ).format(
            nick=nick,
            password=password
        )
        auth = base64.encodestring(auth.encode("UTF-8"))
        auth = auth.decode("UTF-8").rstrip("\n")
        self.irc.send(bytes("AUTHENTICATE "+auth+"\r\n", "UTF-8"))
        self.waitAndSee(r'(.*)903(.*):SASL authentication successful(.*)')
        self.irc.send(bytes("CAP END\r\n", "UTF-8"))

    def sendMessage(self, channel, message):
        self.irc.send(bytes("PRIVMSG {} :{}\r\n".format(channel, message), "UTF-8"))

    def sendPong(self, text):
        self.irc.send(bytes(text.replace('PING', 'PONG'), "UTF-8"))

    def connect(self, host, port, channels, nick, password):
        print("Connecting to {}:{} with nick {} and channels: {}".format(host, port, nick, ','.join(channels)))
        self.irc.connect((host, port))
        if password != None:
            self.authenticate(nick, password)                                             
        self.irc.send(bytes("USER {nick} {nick} {nick} {nick}\r\n".format(nick=nick), "UTF-8"))
        self.irc.send(bytes("NICK {}\r\n".format(nick), "UTF-8"))
        for channel in channels:          
            self.irc.send(bytes("JOIN {}\r\n".format(channel), "UTF-8"))

    def disconnect(self, channels):
        for channel in channels:               
            self.irc.send(bytes("PART {}\r\n".format(channel), "UTF-8"))
        self.irc.send(bytes("QUIT\r\n", "UTF-8"))
        self.irc.close()



try:
    irc = IRC(pool.ssl)
    irc.connect(pool.host, pool.port, pool.channels, pool.nick, pool.password)

    # Wait until connection is established
    while True:    
        text = irc.getText()
        if re.search(r'(.*)End of /NAMES list.(.*)', text, re.MULTILINE):
            break
        elif re.search(r'(.*)PING(.*)', text, re.MULTILINE):
            irc.sendPong(text)
        elif re.search(r'(.*)433(.*)Nickname is already in use(.*)', text, re.MULTILINE):
            raise ConnectionError("Nickname is already in use")
        elif re.search(r'(.*)ERROR :(.*)', text, re.MULTILINE):
            raise ConnectionError(text)
        sleep(0.25)
    for channel in pool.channels:
        for message in messages:
            irc.sendMessage(channel, message)

    irc.disconnect(pool.channels)

    return 'success'

except Exception as e:
    print(e)
    return 'error'

EDIT

Пока я исследую это, похоже, что содержание сообщения - это проблема. В примере массива первое сообщение имеет два двоеточия. Это сообщение, которое обычно не работает. Если я делаю message.replace(":",""), кажется, отправлять нормально. Но у меня есть еще одно сообщение с двумя двоеточиями, которые, кажется, работают нормально, поэтому я не уверен, что это красная сельдь.

РЕДАКТИРОВАТЬ 2

Содержание сообщения определенно было красной сельдью. Смотрите решение ниже.

1 Ответ

0 голосов
/ 21 января 2019

TL; DR

Изменение if re.search(r'(.*)End of /NAMES list.(.*)', text, re.MULTILINE) на if re.search(r'(.*)00[1-4] '+pool.nick+'(.*)', text, re.MULTILINE) исправило проблему.Это отправляет сообщения раньше после подключения.

См. Описание ниже.


После многих испытаний я обнаружил проблему, и это не то, что я ожидал.Проблема в том, что эта строка: if re.search(r'(.*)End of /NAMES list.(.*)', text, re.MULTILINE): в цикле while True:.

После того, как я подключился к IRC и присоединился к каналу, я перебираю сообщения, возвращенные IRC, чтобы убедиться, что я успешно подключился перед отправкойсообщение.Ну, сообщение, которое содержит «Конец / NAMES список.»это одно из последних сообщений, отправленных с IRC-сервера.(после MOTD и все такое).Иногда это занимало слишком много времени, и у меня кончалась связьЗатем отправка сообщения разбудила соединение, но фактически не отправила сообщение.Вот почему это произойдет наугад.Иногда получение сообщения было бы быстрым, а иногда - медленным (возможно, из-за загрузки IRC-сервера).

Поэтому я переключил строку, которую я ищу, на if re.search(r'(.*)00[1-4] '+pool.nick+'(.*)', text, re.MULTILINE), потому что это одно из первых сообщений, отправленных после успешного подключения к IRC.Это происходит до MOTD и тому подобного, но все равно означает, что я на связи.Теперь, когда я отправляю свое сообщение сразу после подключения, все они проходят последовательно.

...