def quit(self): self.serverthread_object.control_channel.send((controlmessage_types.quit,)) self.serverthread_object.logging_channel.send((logmessage_types.internal, internal_submessage_types.quit)) cron.quit(self.cron)
def run(self): while True: # Connect to given server address = (self.server.host, self.server.port) try: self.server_socket = socket.create_connection(address) except (ConnectionRefusedError, socket.gaierror): # Tell controller we failed self.logging_channel.send((logmessage_types.internal, internal_submessage_types.error, "Can't connect to %s:%s" % address)) # Try reconnecting in a minute cron.reschedule(self.cron_control_channel, 60, self.control_channel, (controlmessage_types.reconnect,)) # Handle messages reconnect = True while True: command_type, *arguments = self.control_channel.recv() if command_type == controlmessage_types.reconnect: break elif command_type == controlmessage_types.quit: reconnect = False break else: error_message = 'Control message not supported when not connected: %s' % repr((command_type, *arguments)) self.logging_channel.send((logmessage_types.internal, internal_submessage_types.error, error_message)) # Remove the reconnect message in case we were told to reconnnect manually cron.delete(self.cron_control_channel, self.control_channel, (controlmessage_types.reconnect,)) if reconnect: continue else: break # Create an API object to give to outside line handler self.api = API(self) try: # Run initialization self.send_line_raw(b'USER %s a a :%s' % (self.server.username.encode('utf-8'), self.server.realname.encode('utf-8'))) # Set up nick self.api.nick(self.server.nick.encode('utf-8')) # Run the on_connect hook, to allow further setup botcmd.on_connect(irc = self.api) # Join channels for channel in self.server.channels: self.api.join(channel.encode('utf-8')) # Schedule a ping to be sent in 3 minutes of no activity cron.reschedule(self.cron_control_channel, 3 * 60, self.control_channel, (controlmessage_types.ping,)) # Run mainloop reconnecting = self.mainloop() if not reconnecting: # Run bot cleanup code botcmd.on_quit(irc = self.api) # Tell the server we're quiting self.send_line_raw(b'QUIT :%s exiting normally' % self.server.username.encode('utf-8')) self.server_socket.close() break else: # Tell server we're reconnecting self.send_line_raw(b'QUIT :Reconnecting') self.server_socket.close() except (BrokenPipeError, TimeoutError) as err: # Connection broke, log it and try to reconnect self.logging_channel.send((logmessage_types.internal, internal_submessage_types.error, 'Broken socket/pipe or timeout')) self.server_socket.close() # Tell controller we're quiting self.logging_channel.send((logmessage_types.internal, internal_submessage_types.quit)) # Tell cron we're quiting cron.quit(cron_control_channel)
if __name__ == '__main__': config, server = read_config() botcmd.initialize(config = config) cron_control_channel = cron.start() logging_channel, dead_notify_channel = spawn_loggerthread() control_channel = spawn_serverthread(server, cron_control_channel, logging_channel) while True: message = dead_notify_channel.recv(blocking = False) if message is not None: if message[0] == controlmessage_types.quit: break cmd = input('') if cmd == 'q': print('Keyboard quit') control_channel.send((controlmessage_types.quit,)) logging_channel.send((logmessage_types.internal, internal_submessage_types.quit)) cron.quit(cron_control_channel) break elif cmd == 'r': print('Keyboard reconnect') control_channel.send((controlmessage_types.reconnect,)) elif len(cmd) > 0 and cmd[0] == '/': control_channel.send((controlmessage_types.send_line, cmd[1:]))