我正在 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

您还应记住一些其他事项:

  1. 网络不必同时传递整个 IRC 消息,也不必一次传递一条消息。您可以获得 "PI"、"NG :t"、"mi.twitch.tv"、“\r\n”作为单独的消息。所以你应该在缓冲区中累积字节,然后当你至少有一个完整的消息时,处理它,并将它从缓冲区中删除。
  2. UTF-8 字符可以跨越多个字节,并且可能会被网络拆分。在确定可以使用整条消息之前,不要解码 UTF-8。