Created
January 31, 2018 19:55
-
-
Save williamjacksn/60718d30138ed501bf72f30043313932 to your computer and use it in GitHub Desktop.
Class-based IRC bot
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import socket | |
# change these | |
HOST = 'irc.undernet.org' | |
PORT = 6667 | |
NICK = 'rex' | |
CHAN = '#dashin' | |
ADMIN = 'Humphrey' | |
class IRCBot: | |
def __init__(self, host: str, port: int, nick: str, chan: str, admin: str): | |
self.socket = socket.socket() | |
self.host = host | |
self.port = port | |
self.nick = nick | |
self.chan = chan | |
self.admin = admin | |
self.buff = b'' | |
# this is where I do my work | |
def run(self): | |
self.socket.connect((self.host, self.port)) | |
print(f'** connected to {self.host}') | |
# identify myself to the IRC server | |
self.send_line(f'NICK {self.nick}') | |
self.send_line(f'USER {self.nick} {self.host} x :{self.nick}') | |
while True: | |
# receive what the server has sent me | |
self.buff = self.buff + self.socket.recv(4096) | |
# split it into lines | |
lines = self.buff.split(b'\n') | |
# the last line might be incomplete, put it back in the buffer | |
self.buff = lines.pop() | |
# handle each of the lines that the server sent me | |
for line in lines: | |
self.handle_line(line) | |
# this is the function I will use when I want to send a message to the IRC server | |
def send_line(self, line: str): | |
print(f'=> {line}') | |
# add \r\n to the end of the line and convert it from string to bytes, then send | |
self.socket.send(f'{line}\r\n'.encode()) | |
# this is the function I will use when I want to process a message I received from the IRC server | |
def handle_line(self, line: bytes): | |
# convert line from bytes to string, and remove leading and trailing whitespace | |
line = line.decode().strip() | |
print(f'<= {line}') | |
# split the line on whitespace into a list of tokens | |
tokens = line.split() | |
if tokens[0] == 'PING': | |
self.handle_ping(tokens[1]) | |
elif tokens[1] in ('376', '422'): | |
# 376 means the server has finished sending the message of the day | |
# 422 means there is no message of the day to send | |
self.handle_server_connect_done() | |
elif tokens[1] == 'PRIVMSG' and tokens[2] == self.nick: | |
self.handle_private_message(tokens) | |
elif tokens[1] == 'PRIVMSG' and tokens[2] == self.chan: | |
self.handle_public_message(tokens) | |
def handle_ping(self, message): | |
# when the server sends PING, I automatically reply with PONG | |
self.send_line(f'PONG {message}') | |
def handle_server_connect_done(self): | |
# when the server connection and introduction is complete, join my channel | |
self.send_line(f'JOIN {self.chan}') | |
def handle_private_message(self, tokens): | |
# when I get a message sent directly to me, not the channel | |
sender = self.get_nick(tokens[0]) | |
command = tokens[3] | |
if command == ':!changename' and sender == self.admin: | |
self.nick = tokens[4] | |
print(f'COMMAND: Change nickname to {self.nick}') | |
self.send_line(f'NICK {self.nick}') | |
def handle_public_message(self, tokens): | |
# when I get a message sent to the channel | |
sender = self.get_nick(tokens[0]) | |
command = tokens[3] | |
if command == ':!jump': | |
print('COMMAND: Jump') | |
self.send_line(f'PRIVMSG {self.chan} :\x01ACTION does jumping jacks!') | |
@staticmethod | |
def get_nick(prefix: str): | |
# ':nick!user@host' => 'nick' | |
prefix = prefix.lstrip(':') | |
nick = prefix.split('!')[0] | |
return nick | |
def main(): | |
irc = IRCBot(HOST, PORT, NICK, CHAN, ADMIN) | |
irc.run() | |
if __name__ == '__main__': | |
main() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment