class Writer(object): def __init__(self): self.lock = threading.RLock() # (use "with"-block to lock writer) self.event = Events() self.messagetokens = TokenBucket(6, 16) # 5 Messages per 16 seconds self.event.add("line", self.onwriteline) def onwriteline(self, line): with self.lock: self.event.notify("data", line + b"\r\n") def command(self, command, args): if(len(args) != 0): args[-1] = b":" + args[-1] argstr = b" ".join(args) else: argstr = b"" command = command.encode("iso-8859-1") line = command + b" " + argstr self.event.notify("line", line) def join(self, chan): chan = chan.encode("iso-8859-1") self.command("JOIN", [chan]) def part(self, chan): self.command("PART", [chan]) def quit(self, msg): self._quit = True self.command("QUIT", [msg]) def nick(self, nick): nick = nick.encode("iso-8859-1") self.command("NICK", [nick]) def user(self, username, hostname, servername, realname): username = username.encode("iso-8859-1") hostname = hostname.encode("iso-8859-1") servername = servername.encode("iso-8859-1") realname = realname.encode("utf-8") self.command("USER", [username, hostname, servername, realname]) def pong(self, msg): self.command("PONG", [msg]) def msgline(self, recipient, msg, blocking=True): return self.msglines(recipient, [msg], blocking) def msglines(self, recipient, lines, blocking=True): recipient = recipient.encode("iso-8859-1") if self.messagetokens.consume(len(lines), blocking): for line in lines: line = line.encode("utf-8") self.command("PRIVMSG", [recipient, line]) return True return False
class Connection(object): def __init__(self): self.socket = socket.socket() self.event = Events() self.event.add("send", self.onsend) def connect(self, server, port): self.socket.connect((server, port)) def recvloop(self): while True: data = self.socket.recv(4096) if data == "": self.event.notify("disconnect") return self.event.notify("recv", data) def onsend(self, data): self.socket.sendall(data)
class Parser(object): def __init__(self): self.buf = b"" self.event = Events() self.event.add("data", self.ondata) self.event.add("line", self.onrecvline) self.event.add("msg", self.onmsg) def reset(self): self.buf = b"" def ondata(self, data): self.buf += data lines = self.buf.split(b"\r\n") self.buf = lines.pop() for line in lines: self.event.notify("line", line) def onrecvline(self, line): match = message_matcher.match(line) if match == None: return servername = match.group(3) nick = match.group(5) user = match.group(6) host = match.group(7) command = match.group(8) params = match.group(12).split(b" ")[1:] trailparam = match.group(15) servername = servername and servername.decode("iso-8859-1", "ignore") nick = nick and nick.decode("iso-8859-1", "ignore") user = user and user.decode("iso-8859-1", "ignore") host = host and host.decode("iso-8859-1", "ignore") command = command and command.decode("iso-8859-1", "ignore") if trailparam != None: params += [trailparam] self.event.notify("msg", servername, nick, user, host, command, params) def onmsg(self, servername, nick, user, host, command, args): if(command == "332"): self.event.notify("topic", nick, user, host, args[0], args[1], args[2]) elif(command == "PING"): self.event.notify("ping", args[0]) elif(command == "NICK"): nick, = args nick = nick.decode("iso-8859-1", "ignore") self.event.notify("nick", nick, user, host, args[0]) elif(command == "NOTICE"): mask, message = args mask = mask.decode("iso-8859-1", "ignore") message = message.decode("utf-8", "ignore") self.event.notify("notice", nick, user, host, mask, message) elif(command == "PRIVMSG"): mask, message = args mask = mask.decode("iso-8859-1", "ignore") message = message.decode("utf-8", "ignore") self.event.notify("privmsg", nick, user, host, mask, message) elif(command == "376"): self.event.notify("endofmotd", nick, user, host, args[0])