| @@ -27,8 +27,8 @@ from earwigbot import __version__ | |||||
| from earwigbot.commands import BaseCommand | from earwigbot.commands import BaseCommand | ||||
| class Command(BaseCommand): | class Command(BaseCommand): | ||||
| """Not an actual command, this module is used to respond to the CTCP | |||||
| commands PING, TIME, and VERSION.""" | |||||
| """Not an actual command; this module implements responses to the CTCP | |||||
| requests PING, TIME, and VERSION.""" | |||||
| name = "ctcp" | name = "ctcp" | ||||
| hooks = ["msg_private"] | hooks = ["msg_private"] | ||||
| @@ -23,11 +23,12 @@ | |||||
| from earwigbot.commands import BaseCommand | from earwigbot.commands import BaseCommand | ||||
| class Command(BaseCommand): | class Command(BaseCommand): | ||||
| """Restart the bot. Only the owner can do this.""" | |||||
| name = "restart" | |||||
| """Quit, restart, or reload components from the bot. Only the owners can | |||||
| run this command.""" | |||||
| name = "quit" | |||||
| def check(self, data): | def check(self, data): | ||||
| commands = ["restart", "reload"] | |||||
| commands = ["quit", "restart", "reload"] | |||||
| return data.is_command and data.command in commands | return data.is_command and data.command in commands | ||||
| def process(self, data): | def process(self, data): | ||||
| @@ -35,17 +36,34 @@ class Command(BaseCommand): | |||||
| msg = "you must be a bot owner to use this command." | msg = "you must be a bot owner to use this command." | ||||
| self.connection.reply(data, msg) | self.connection.reply(data, msg) | ||||
| return | return | ||||
| if data.command == "quit": | |||||
| self.do_quit(data) | |||||
| elif data.command == "restart": | |||||
| self.do_restart(data) | |||||
| else: | |||||
| self.do_reload(data) | |||||
| if data.command == "restart": | |||||
| self.logger.info("Restarting bot per owner request") | |||||
| if data.args: | |||||
| self.bot.restart(" ".join(data.args)) | |||||
| else: | |||||
| self.bot.restart() | |||||
| def do_quit(self, data): | |||||
| nick = self.config.irc.frontend["nick"] | |||||
| if not data.args or data.args[0].lower() != nick.lower(): | |||||
| self.connection.reply(data, "to confirm this action, the first argument must be my nickname.") | |||||
| return | |||||
| if data.args[1:]: | |||||
| msg = " ".join(data.args[1:]) | |||||
| self.bot.stop("Stopped by {0}: {1}".format(data.nick, msg)) | |||||
| else: | |||||
| self.bot.stop("Stopped by {0}".format(data.nick)) | |||||
| def do_restart(self, data): | |||||
| self.logger.info("Restarting bot per owner request") | |||||
| if data.args: | |||||
| msg = " ".join(data.args) | |||||
| self.bot.restart("Restarted by {0}: {1}".format(data.nick, msg)) | |||||
| else: | |||||
| self.bot.restart("Restarted by {0}".format(data.nick)) | |||||
| elif data.command == "reload": | |||||
| self.logger.info("Reloading IRC commands") | |||||
| self.bot.commands.load() | |||||
| self.logger.info("Reloading bot tasks") | |||||
| self.bot.tasks.load() | |||||
| self.connection.reply("IRC commands and bot tasks reloaded.") | |||||
| def do_reload(self, data): | |||||
| self.logger.info("Reloading IRC commands and bot tasks") | |||||
| self.bot.commands.load() | |||||
| self.bot.tasks.load() | |||||
| self.connection.reply(data, "IRC commands and bot tasks reloaded.") | |||||
| @@ -117,9 +117,9 @@ class Command(BaseCommand): | |||||
| t = "\x0302{0}\x0301 (\x02active\x0F as ids {1})" | t = "\x0302{0}\x0301 (\x02active\x0F as ids {1})" | ||||
| tasklist.append(t.format(task, ', '.join(ids))) | tasklist.append(t.format(task, ', '.join(ids))) | ||||
| tasklist = ", ".join(tasklist) | |||||
| tasks = ", ".join(tasklist) | |||||
| msg = "{0} tasks loaded: {1}.".format(len(all_tasks), tasklist) | |||||
| msg = "{0} tasks loaded: {1}.".format(len(tasklist), tasks) | |||||
| self.connection.reply(self.data, msg) | self.connection.reply(self.data, msg) | ||||
| def do_start(self): | def do_start(self): | ||||
| @@ -98,6 +98,7 @@ class BotConfig(object): | |||||
| """Configures the logging module so it works the way we want it to.""" | """Configures the logging module so it works the way we want it to.""" | ||||
| log_dir = self._log_dir | log_dir = self._log_dir | ||||
| logger = logging.getLogger("earwigbot") | logger = logging.getLogger("earwigbot") | ||||
| logger.handlers = [] # Remove any handlers already attached to us | |||||
| logger.setLevel(logging.DEBUG) | logger.setLevel(logging.DEBUG) | ||||
| if self.metadata.get("enableLogging"): | if self.metadata.get("enableLogging"): | ||||
| @@ -81,6 +81,13 @@ class IRCConnection(object): | |||||
| self._sock.sendall(msg + "\r\n") | self._sock.sendall(msg + "\r\n") | ||||
| self.logger.debug(msg) | self.logger.debug(msg) | ||||
| def _quit(self, msg=None): | |||||
| """Issue a quit message to the server.""" | |||||
| if msg: | |||||
| self._send("QUIT :{0}".format(msg)) | |||||
| else: | |||||
| self._send("QUIT") | |||||
| def say(self, target, msg): | def say(self, target, msg): | ||||
| """Send a private message to a target on the server.""" | """Send a private message to a target on the server.""" | ||||
| msg = "PRIVMSG {0} :{1}".format(target, msg) | msg = "PRIVMSG {0} :{1}".format(target, msg) | ||||
| @@ -121,13 +128,6 @@ class IRCConnection(object): | |||||
| msg = "PONG {0}".format(target) | msg = "PONG {0}".format(target) | ||||
| self._send(msg) | self._send(msg) | ||||
| def quit(self, msg=None): | |||||
| """Issue a quit message to the server.""" | |||||
| if msg: | |||||
| self._send("QUIT :{0}".format(msg)) | |||||
| else: | |||||
| self._send("QUIT") | |||||
| def loop(self): | def loop(self): | ||||
| """Main loop for the IRC connection.""" | """Main loop for the IRC connection.""" | ||||
| self._is_running = True | self._is_running = True | ||||
| @@ -150,7 +150,7 @@ class IRCConnection(object): | |||||
| def stop(self, msg=None): | def stop(self, msg=None): | ||||
| """Request the IRC connection to close at earliest convenience.""" | """Request the IRC connection to close at earliest convenience.""" | ||||
| if self._is_running: | if self._is_running: | ||||
| self.quit(msg) | |||||
| self._quit(msg) | |||||
| self._is_running = False | self._is_running = False | ||||
| def is_stopped(self): | def is_stopped(self): | ||||
| @@ -67,8 +67,11 @@ def main(): | |||||
| bot.tasks.start(args.task) | bot.tasks.start(args.task) | ||||
| else: | else: | ||||
| bot.run() | bot.run() | ||||
| except KeyboardInterrupt: | |||||
| pass | |||||
| finally: | finally: | ||||
| bot.stop() | |||||
| if not bot._keep_looping: # Indicates bot has already been stopped | |||||
| bot.stop() | |||||
| if __name__ == "__main__": | if __name__ == "__main__": | ||||
| main() | main() | ||||