2016-05-08 7 views
1

Wie der Titel sagt, obwohl dies auch das erste Mal ist, dass ich mit Python wirklich etwas Großes gemacht habe. Ich bin noch nicht so sehr an die Sprache gewöhnt, also ist das wahrscheinlich meine fehlende Sache. Der Code ist ziemlich kurz und wird wie folgt mit Benutzername und privaten Pass entfernt:Ich erstelle einen Twitch-fokussierten IRC-Bot in Python, aber er bekommt die Antworten langsam. Was mache ich falsch?

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+!\[email protected]\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) 

Eine Sache zu erwähnen ist, dass ich eine grundlegende Vorlage Stil folgend, aber es hat nicht für flüstert in den Bot Umsetzung - so Ich muss raten, indem ich recherchiere, wie man das macht, und es scheint, dass der am meisten empfohlene Weg zwei Verbindungen sind, eine für die Öffentlichkeit, eine für die private.

Antwort

1

Da Sie Ihren Code strukturiert haben, können Sie nichts aus dem private Sockel bekommen, bis Sie etwas aus dem public Sockel bekommen haben. Wenn IRC gelegentlich keine PING Nachrichten gesendet hat, würde dies noch schlimmer funktionieren.

Der Weg, um dies zu handhaben ist, select zu verwenden, und geben Sie es Ihre zwei Sockets. Sobald man Daten hat, die gelesen werden können, gibt select zurück und zeigt an, welcher Socket über Bytes zum Lesen verfügt.

This answer hat einige allgemeine code. Vielleicht haben Sie es ändern wollen, wie etwas aussehen:

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 

Es gibt ein paar andere Dinge, die Sie beachten sollten:

  1. Das Netzwerk verfügt nicht über gesamte IRC-Nachrichten mit der gleichen liefern Zeit, noch muss es einzeln zu einer Zeit liefern. Sie können "PI", "NG: t", "mi.twitch.tv", "\ r \ n" als separate Nachrichten erhalten. Sie sollten also Bytes in einem Puffer akkumulieren und dann, wenn Sie mindestens eine ganze Nachricht haben, diese verarbeiten und aus dem Puffer entfernen.
  2. UTF-8-Zeichen können sich über mehrere Bytes erstrecken und möglicherweise vom Netzwerk getrennt werden. Entschlüsseln Sie UTF-8 erst dann, wenn Sie sicher sind, dass Sie eine vollständige Nachricht haben.
+0

Okay, ich habe diesen Teil eingerichtet, aber ich bin mir nicht sicher, wie man die Arrays für öffentliche/private Kanalantworten in Python überprüft - in einer while-Schleife. Was ist der beste Weg? – Merlin

+0

Arrays? Du meinst die 'privateResponse' und' channelResponse' Puffer, die Strings sind? Du hast viele Optionen. meistens drehen sie sich um die Tatsache, dass Nachrichten im IRC bequem durch Zeilenumbrüche beendet werden. Wenn es im Puffer keine neue Zeile gibt, sind keine vollständigen Nachrichten vorhanden. Die einfachste Sache ist wahrscheinlich zu sehen, ob es eine neue Zeile gibt, und falls ja, verarbeiten Sie alles als Nachricht und ersetzen Sie dann den Puffer durch alles nach dem Zeilenumbruch. –

+0

Das hat es getan. Es gibt jetzt eine erste Pause, aber dann verhalten sich beide Verbindungen richtig - und erhalten sofort Antworten. – Merlin