# -*- coding: utf-8 -*- import socket import threading class BrokenSocketException(Exception): """A socket has broken, because it is not sending data. Raised by Connection.get().""" pass class Connection(object): """A class to interface with IRC.""" def __init__(self, host=None, port=None, nick=None, ident=None, realname=None, logger=None): self.host = host self.port = port self.nick = nick self.ident = ident self.realname = realname self.logger = logger # A lock to prevent us from sending two messages at once: self.lock = threading.Lock() def connect(self): """Connect to our IRC server.""" self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) try: self.sock.connect((self.host, self.port)) except socket.error: self.logger.critical("Couldn't connect to IRC server", exc_info=1) exit(1) self.send("NICK %s" % self.nick) self.send("USER %s %s * :%s" % (self.ident, self.host, self.realname)) def close(self): """Close our connection with the IRC server.""" try: self.sock.shutdown(socket.SHUT_RDWR) # shut down connection first except socket.error: pass # ignore if the socket is already down self.sock.close() def get(self, size=4096): """Receive (i.e. get) data from the server.""" data = self.sock.recv(4096) if not data: # Socket isn't giving us any data, so it is dead or broken: raise BrokenSocketException() return data def send(self, msg): """Send data to the server.""" # Ensure that we only send one message at a time with a blocking lock: with self.lock: self.sock.sendall(msg + "\r\n") self.logger.debug(msg) def say(self, target, msg): """Send a private message to a target on the server.""" message = "".join(("PRIVMSG ", target, " :", msg)) self.send(message) def reply(self, data, msg): """Send a private message as a reply to a user on the server.""" message = "".join((chr(2), data.nick, chr(0x0f), ": ", msg)) self.say(data.chan, message) def action(self, target, msg): """Send a private message to a target on the server as an action.""" message = "".join((chr(1), "ACTION ", msg, chr(1))) self.say(target, message) def notice(self, target, msg): """Send a notice to a target on the server.""" message = "".join(("NOTICE ", target, " :", msg)) self.send(message) def join(self, chan): """Join a channel on the server.""" message = " ".join(("JOIN", chan)) self.send(message) def part(self, chan): """Part from a channel on the server.""" message = " ".join(("PART", chan)) self.send(message) def mode(self, chan, level, msg): """Send a mode message to the server.""" message = " ".join(("MODE", chan, level, msg)) self.send(message)