import datetime import select import threading import channel commchan = None commchan_lock = threading.Lock() class Clock(threading.Thread): def __init__(self, irc, commchan): self.irc = irc self.commchan = commchan threading.Thread.__init__(self) def send_time(self, hour, half_past): # Convert to 12h clock hour = hour % 12 # Deal with the fact that unicode has 1…12 if hour == 0: hour = 12 clockface = chr(0x1F550 - 1 + hour + (12 if half_past else 0)) for chan in self.irc.get_channels(): self.irc.bot_response(chan, clockface) def run(self): poll = select.poll() poll.register(self.commchan, select.POLLIN) last_hour = None last_half_past = None quit = False while not quit: now = datetime.datetime.now() half_past = now.minute >= 30 if last_hour != now.hour or last_half_past != half_past: self.send_time(now.hour, half_past) last_hour = now.hour last_half_past = half_past # Set poll timeout to when we next need to wake up timeout = ((30 - now.minute % 30) * 60 - now.second) * 1000 - now.microsecond // 1000 for fd, event in poll.poll(timeout): if fd == self.commchan.fileno(): comm = self.commchan.recv() if comm == 'quit': quit = True self.commchan.close() def stop_clock(): global commchan, commchan_lock with commchan_lock: if commchan is None: return else: commchan.send('quit') commchan = None def start_clock(irc): global commchan, commchan_lock with commchan_lock: if commchan is not None: return else: commchan = channel.Channel() Clock(irc, commchan).start() # initialize(*, config) # Called to initialize the IRC bot # Runs before even logger is brought up, and blocks further bringup until it's done # config is a configpatser.ConfigParser object containig contents of bot.conf def initialize(*, config): ... # on_connect(*, irc) # Called after IRC bot has connected and sent the USER/NICk commands but not yet attempted anything else # Called for every reconnect # Blocks the bot until it's done, including PING/PONG handling # irc is the IRC API object def on_connect(*, irc): stop_clock() start_clock(irc) # on_quit(*, irc) # Called just before IRC bot sends QUIT # Blocks the bot until it's done, including PING/PONG handling # irc is the IRC API object def on_quit(*, irc): stop_clock() # handle_message(*, prefix, message, nick, channel, irc) # Called for PRIVMSGs. # prefix is the prefix at the start of the message, without the leading ':' # message is the contents of the message # nick is who sent the message # channel is where you should send the response (note: in queries nick == channel) # irc is the IRC API object # All strings are bytestrings def handle_message(*, prefix, message, nick, channel, irc): ... # handle_nonmessage(*, prefix, command, arguments, irc) # Called for all other commands than PINGs and PRIVMSGs. # prefix is the prefix at the start of the message, without the leading ':' # command is the command or number code # arguments is rest of the arguments of the command, represented as a list. ':'-arguments are handled automatically # irc is the IRC API object # All strings are bytestrings def handle_nonmessage(*, prefix, command, arguments, irc): ...