我正在 Python 中创建一个 Twitch-focused IRC 机器人,但它的响应速度很慢。我究竟做错了什么?
I am creating a Twitch-focused IRC bot in Python, however it is getting the responses slowly. What am I doing wrong?
正如标题所说,虽然这也是我第一次用Python真正干出大事。我还不太习惯这种语言,所以这可能是我遗漏的东西。代码很短,如下所示,删除了用户名和私人通行证:
import re
import socket
import sys
import time
import string
HOST = "irc.twitch.tv"
PORT = 6667
NICK = ""
PASS = ""
CHAN = ""
RATE = (20/30) # messages per second
CHAT_MSG=re.compile(r"^:\w+!\w+@\w+\.tmi\.twitch\.tv PRIVMSG #\w+ :")
def chat(sock, msg):
sock.send("PRIVMSG #{} :{}".format(cfg.CHAN, msg))
public = socket.socket()
public.connect((HOST, PORT))
public.send("PASS {}\r\n".format(PASS).encode("utf-8"))
public.send("NICK {}\r\n".format(NICK).encode("utf-8"))
public.send("JOIN {}\r\n".format(CHAN).encode("utf-8"))
private = socket.socket()
private.connect((HOST, PORT))
private.send("PASS {}\r\n".format(PASS).encode("utf-8"))
private.send("NICK {}\r\n".format(NICK).encode("utf-8"))
private.send("CAP REQ :twitch.tv/tags twitch.tv/commands {}\r\n".format(CHAN).encode("utf-8"))
while True:
channelResponse = public.recv(1024).decode("utf-8")
privateResponse = private.recv(1024).decode("utf-8")
if privateResponse == "PING :tmi.twitch.tv\r\n":
private.send("PONG :tmi.twitch.tv\r\n".encode("utf-8"))
else:
privateResponseUsername = re.search(r"\w+", privateResponse).group(0) # return the entire match
privateResponseMessage = CHAT_MSG.sub("", privateResponse)
print(privateResponseUsername + ": " + privateResponseMessage)
if channelResponse == "PING :tmi.twitch.tv\r\n":
public.send("PONG :tmi.twitch.tv\r\n".encode("utf-8"))
else:
username = re.search(r"\w+", channelResponse).group(0) # return the entire match
message = CHAT_MSG.sub("", channelResponse)
print(username + ": " + message)
time.sleep(1 / RATE)
要提的一件事是我遵循了基本的模板样式,但是它没有涵盖在机器人中实施耳语 - 所以我不得不通过研究如何做到这一点来猜测,而且它似乎是最推荐的方式是两个连接,一个用于public,一个用于private.
在构建代码时,在从 public
套接字获取某些内容之前,您无法从 private
套接字获取任何内容。如果 IRC 不偶尔发送 PING
消息,这会更糟。
处理这个问题的方法是使用 select
,并给它你的两个插座。一旦有了可以读取的内容,select
就会 return 并指出哪个套接字有字节可供读取。
This answer 有一些通用代码。您可能希望将其修改为如下所示:
while True:
# this will block until at least one socket is ready
ready_socks,_,_ = select.select([private, public], [], [])
if private in ready_socks:
privateResponse += private.recv()
if public in ready_socks:
channelResponse += public.recv()
# check privateResponse buffer, do stuff
# check channelResponse buffer, do stuff
您还应记住一些其他事项:
- 网络不必同时传递整个 IRC 消息,也不必一次传递一条消息。您可以获得 "PI"、"NG :t"、"mi.twitch.tv"、“\r\n”作为单独的消息。所以你应该在缓冲区中累积字节,然后当你至少有一个完整的消息时,处理它,并将它从缓冲区中删除。
- UTF-8 字符可以跨越多个字节,并且可能会被网络拆分。在确定可以使用整条消息之前,不要解码 UTF-8。
正如标题所说,虽然这也是我第一次用Python真正干出大事。我还不太习惯这种语言,所以这可能是我遗漏的东西。代码很短,如下所示,删除了用户名和私人通行证:
import re
import socket
import sys
import time
import string
HOST = "irc.twitch.tv"
PORT = 6667
NICK = ""
PASS = ""
CHAN = ""
RATE = (20/30) # messages per second
CHAT_MSG=re.compile(r"^:\w+!\w+@\w+\.tmi\.twitch\.tv PRIVMSG #\w+ :")
def chat(sock, msg):
sock.send("PRIVMSG #{} :{}".format(cfg.CHAN, msg))
public = socket.socket()
public.connect((HOST, PORT))
public.send("PASS {}\r\n".format(PASS).encode("utf-8"))
public.send("NICK {}\r\n".format(NICK).encode("utf-8"))
public.send("JOIN {}\r\n".format(CHAN).encode("utf-8"))
private = socket.socket()
private.connect((HOST, PORT))
private.send("PASS {}\r\n".format(PASS).encode("utf-8"))
private.send("NICK {}\r\n".format(NICK).encode("utf-8"))
private.send("CAP REQ :twitch.tv/tags twitch.tv/commands {}\r\n".format(CHAN).encode("utf-8"))
while True:
channelResponse = public.recv(1024).decode("utf-8")
privateResponse = private.recv(1024).decode("utf-8")
if privateResponse == "PING :tmi.twitch.tv\r\n":
private.send("PONG :tmi.twitch.tv\r\n".encode("utf-8"))
else:
privateResponseUsername = re.search(r"\w+", privateResponse).group(0) # return the entire match
privateResponseMessage = CHAT_MSG.sub("", privateResponse)
print(privateResponseUsername + ": " + privateResponseMessage)
if channelResponse == "PING :tmi.twitch.tv\r\n":
public.send("PONG :tmi.twitch.tv\r\n".encode("utf-8"))
else:
username = re.search(r"\w+", channelResponse).group(0) # return the entire match
message = CHAT_MSG.sub("", channelResponse)
print(username + ": " + message)
time.sleep(1 / RATE)
要提的一件事是我遵循了基本的模板样式,但是它没有涵盖在机器人中实施耳语 - 所以我不得不通过研究如何做到这一点来猜测,而且它似乎是最推荐的方式是两个连接,一个用于public,一个用于private.
在构建代码时,在从 public
套接字获取某些内容之前,您无法从 private
套接字获取任何内容。如果 IRC 不偶尔发送 PING
消息,这会更糟。
处理这个问题的方法是使用 select
,并给它你的两个插座。一旦有了可以读取的内容,select
就会 return 并指出哪个套接字有字节可供读取。
This answer 有一些通用代码。您可能希望将其修改为如下所示:
while True:
# this will block until at least one socket is ready
ready_socks,_,_ = select.select([private, public], [], [])
if private in ready_socks:
privateResponse += private.recv()
if public in ready_socks:
channelResponse += public.recv()
# check privateResponse buffer, do stuff
# check channelResponse buffer, do stuff
您还应记住一些其他事项:
- 网络不必同时传递整个 IRC 消息,也不必一次传递一条消息。您可以获得 "PI"、"NG :t"、"mi.twitch.tv"、“\r\n”作为单独的消息。所以你应该在缓冲区中累积字节,然后当你至少有一个完整的消息时,处理它,并将它从缓冲区中删除。
- UTF-8 字符可以跨越多个字节,并且可能会被网络拆分。在确定可以使用整条消息之前,不要解码 UTF-8。