IRC 消息随机不从 bot 发送
IRC messages randomly not sending from bot
我在 Python 中编写了一个非常简单的机器人来接收 webhook,解析数据,然后将消息发送到 IRC。一切都按预期工作,除了在完全随机的时间消息将无法发送。我没有从 IRC 服务器收到任何错误消息,但它们根本不会出现在 IRC 中。我构建了一个要发送的消息数组,然后循环发送它们。我通过 SASL 向 IRC 进行身份验证。我确认所有消息都在应该发送的列表中。有时他们都发送正常,有时只有一些发送,有时 none 发送。我尝试从服务器取回消息,但似乎 none.
当我打印消息数组时,它看起来像:
['[\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}[=12=]{nick}[=12=]{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
邮件内容绝对是在转移注意力。请参阅下面的解决方案。
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 和所有其他东西之前,但仍然意味着我已连接。现在,当我在连接后立即发送消息时,它们都会始终如一地通过。
我在 Python 中编写了一个非常简单的机器人来接收 webhook,解析数据,然后将消息发送到 IRC。一切都按预期工作,除了在完全随机的时间消息将无法发送。我没有从 IRC 服务器收到任何错误消息,但它们根本不会出现在 IRC 中。我构建了一个要发送的消息数组,然后循环发送它们。我通过 SASL 向 IRC 进行身份验证。我确认所有消息都在应该发送的列表中。有时他们都发送正常,有时只有一些发送,有时 none 发送。我尝试从服务器取回消息,但似乎 none.
当我打印消息数组时,它看起来像:
['[\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}[=12=]{nick}[=12=]{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
邮件内容绝对是在转移注意力。请参阅下面的解决方案。
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 和所有其他东西之前,但仍然意味着我已连接。现在,当我在连接后立即发送消息时,它们都会始终如一地通过。