【问题标题】:IRC messages randomly not sending from botIRC 消息随机不从机器人发送
【发布时间】:2019-06-13 17:36:35
【问题描述】:

我用 Python 编写了一个非常简单的机器人来接收 webhook,解析数据,然后向 IRC 发送消息。一切都按预期工作,除了在完全随机的时间消息将无法发送。我没有从 IRC 服务器收到任何错误消息,但它们根本不会出现在 IRC 中。我构造了一个要发送的消息数组,然后遍历它们进行发送。我通过 SASL 向 IRC 进行身份验证。我确认所有消息都在应该发送的列表中。有时他们都发送很好,有时只发送一些,有时他们都不发送。我尝试从服务器取回消息,但似乎没有消息。

当我打印消息数组时,它看起来像:

['[\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'

编辑

在我对此进行研究时,消息的内容似乎是问题所在。在示例数组中,第一条消息有两个冒号。这是通常不起作用的信息。如果我这样做message.replace(":",""),它似乎发送得很好。但我有另一条消息,其中有两个冒号,似乎可以正常工作,所以不确定这是否是一条红鲱鱼。

编辑 2

消息内容绝对是红鲱鱼。请参阅下面的解决方案。

【问题讨论】:

  • FWIW,我只尝试向 freenode 发送消息,但这可能是我要发送的唯一 IRC。
  • 我也认为每次没有显示消息时它都是数组中的第一个

标签: python python-3.x sockets bots irc


【解决方案1】:

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) 解决了这个问题。这会在连接后更快地发送消息。

请参阅下面的说明。


经过大量测试,我发现了问题,这不是我所期望的。问题是这一行:while True: 循环中的if re.search(r'(.*)End of /NAMES list.(.*)', text, re.MULTILINE):

连接到 IRC 并加入频道后,我会循环浏览从 IRC 返回的消息,以确保在发送消息之前已成功连接。那么包含“End of /NAMES list”的消息。是从 IRC 服务器发送的最后一条消息之一。 (在 MOTD 和所有这些之后)。有时这花费了太长时间,就像我的连接空闲或什么的。然后发送消息唤醒连接,但实际上并没有发送消息。这就是为什么它会随机发生。有时接收消息会很快,有时会很慢(可能基于 IRC 服务器的负载)。

所以我将要搜索的行切换到 if re.search(r'(.*)00[1-4] '+pool.nick+'(.*)', text, re.MULTILINE),因为这是成功连接到 IRC 后发送的第一批消息之一。这发生在 MOTD 和所有这些东西之前,但仍然意味着我已经连接。现在,当我在连接后立即发送消息时,它们都会始终如一地通过。

【讨论】:

    猜你喜欢
    • 2014-09-18
    • 2012-09-21
    • 2021-08-19
    • 2022-01-03
    • 2021-08-27
    • 2012-07-28
    • 2020-08-25
    • 2019-06-27
    • 2017-03-19
    相关资源
    最近更新 更多