From 3945c6ae459089245ea96b1ff8fbd17516598cca Mon Sep 17 00:00:00 2001 From: Joscha Date: Tue, 5 Sep 2017 19:37:14 +0000 Subject: [PATCH] Allow for bots to be restarted and fix botrulez commands --- TestBot.py | 17 ++++++++++++----- yaboli/bot.py | 45 +++++++++++++++++++++++++++++++++++++-------- yaboli/utils.py | 29 ++++++++++++++++++++++++++++- 3 files changed, 77 insertions(+), 14 deletions(-) diff --git a/TestBot.py b/TestBot.py index be41127..cfb902d 100644 --- a/TestBot.py +++ b/TestBot.py @@ -3,12 +3,12 @@ from yaboli.utils import * -#class TestBot(Bot): class TestBot(yaboli.Bot): def __init__(self, nick): super().__init__(nick=nick) self.register_callback("tree", self.command_tree, specific=False) + self.register_callback("stree", self.command_simple_tree, specific=False) #async def on_send(self, message): #if message.content == "!spawnevil": @@ -36,13 +36,20 @@ class TestBot(yaboli.Bot): messages = [message] newmessages = [] for i in range(2): - for m in messages: + for msg in messages: for j in range(2): - newm = await self.room.send(f"{message.content}.{j}", m.message_id) + newm = await self.room.send(f"{msg.content}.{j}", msg.message_id) newmessages.append(newm) messages = newmessages newmessages = [] + + async def command_simple_tree(self, message, args): + root = await self.room.send("root message", message.message_id) + branch1 = await self.room.send("branch 1", root.message_id) + branch2 = await self.room.send("branch 2", root.message_id) + await self.room.send("branch 1.1", branch1.message_id) + await self.room.send("branch 2.1", branch2.message_id) + await self.room.send("branch 1.2", branch1.message_id) if __name__ == "__main__": - bot = TestBot("TestSummoner") - run_controller(bot, "test") + run_bot(TestBot, "test", "TestSummoner") diff --git a/yaboli/bot.py b/yaboli/bot.py index a274d77..075e991 100644 --- a/yaboli/bot.py +++ b/yaboli/bot.py @@ -19,6 +19,7 @@ class Bot(Controller): def __init__(self, nick): super().__init__(nick) + self.restarting = False # whoever runs the bot can check if a restart is necessary self.start_time = time.time() self._callbacks = Callbacks() @@ -26,12 +27,26 @@ class Bot(Controller): # settings (modify in your bot's __init__) self.general_help = None # None -> does not respond to general help + self.specific_help = "No help available" self.killable = True self.kill_message = "/me *poof*" # how to respond to !kill, whether killable or not + self.restartable = True + self.restart_message = "/me temporary *poof*" # how to respond to !restart, whether restartable or not def register_callback(self, event, callback, specific=True): self._callbacks.add((event, specific), callback) + async def restart(self): + # After calling this, the bot is stopped, not yet restarted. + self.restarting = True + await self.stop() + + def noargs(func): + async def wrapper(self, message, args): + if not args: + return await func(self, message) + return wrapper + async def on_send(self, message): parsed = self.parse_message(message.content) if not parsed: @@ -138,7 +153,7 @@ class Bot(Controller): - # BOTRULEZ COMMANDS + # BOTRULEZ AND YABOLI-SPECIFIC COMMANDS def register_default_callbacks(self): self.register_callback("ping", self.command_ping) @@ -147,19 +162,24 @@ class Bot(Controller): self.register_callback("help", self.command_help_general, specific=False) self.register_callback("uptime", self.command_uptime) self.register_callback("kill", self.command_kill) - # TODO: maybe !restart command + self.register_callback("restart", self.command_restart) - async def command_ping(self, message, args): + @noargs + async def command_ping(self, message): await self.room.send("Pong!", message.message_id) - async def command_help(self, message, args): - await self.room.send("", message.message_id) + @noargs # TODO: specific command help (!help @bot ping) + async def command_help(self, message): + if self.specific_help: + await self.room.send(self.specific_help, message.message_id) - async def command_help_general(self, message, args): + @noargs + async def command_help_general(self, message): if self.general_help is not None: await self.room.send(self.general_help, message.message_id) - async def command_uptime(self, message, args): + @noargs + async def command_uptime(self, message): now = time.time() startformat = format_time(self.start_time) deltaformat = format_time_delta(now - self.start_time) @@ -167,10 +187,19 @@ class Bot(Controller): await self.room.send(text, message.message_id) async def command_kill(self, message, args): - logging.warn(f"Kill attempt in &{self.room.roomname}: {message.content!r}") + logging.warn(f"Kill attempt by @{mention(message.sender.nick)} in &{self.room.roomname}: {message.content!r}") if self.kill_message is not None: await self.room.send(self.kill_message, message.message_id) if self.killable: await self.stop() + + async def command_restart(self, message, args): + logging.warn(f"Restart attempt by @{mention(message.sender.nick)} in &{self.room.roomname}: {message.content!r}") + + if self.restart_message is not None: + await self.room.send(self.restart_message, message.message_id) + + if self.restartable: + await self.restart() diff --git a/yaboli/utils.py b/yaboli/utils.py index 0f619ed..f1ff82e 100644 --- a/yaboli/utils.py +++ b/yaboli/utils.py @@ -1,8 +1,10 @@ import asyncio +import logging import time +logger = logging.getLogger(__name__) __all__ = [ - "run_controller", + "run_controller", "run_bot", "mention", "mention_reduced", "similar", "format_time", "format_time_delta", "Session", "Listing", @@ -21,6 +23,31 @@ def run_controller(controller, room): task, reason = await controller.connect(room) if task: await task + else: + logger.warn(f"Could not connect to &{room}: {reason!r}") + + asyncio.get_event_loop().run_until_complete(run()) + +def run_bot(bot_class, room, *args, **kwargs): + """ + Helper function to run a bot. To run Multibots, use the MultibotKeeper. + This restarts the bot when it is explicitly restarted through Bot.restart(). + """ + + async def run(): + while True: + logger.info(f"Creating new instance and connecting to &{room}") + bot = bot_class(*args, **kwargs) + task, reason = await bot.connect(room) + if task: + await task + else: + logger.warn(f"Could not connect to &{room}: {reason!r}") + + if bot.restarting: + logger.info(f"Restarting in &{room}") + else: + break asyncio.get_event_loop().run_until_complete(run())