From 294adf270fa92c0594c4f335943916a4458e4b15 Mon Sep 17 00:00:00 2001 From: Twentysix Date: Thu, 27 Apr 2017 16:26:21 +0200 Subject: [PATCH] [Core] Save package status and restore it on boot Also better error handling on package loading --- cogs/audio/audio.py | 30 +++++++++++++++--------------- core/__init__.py | 3 ++- core/bot.py | 7 +++++++ core/events.py | 39 +++++++++++++++++++++++++++++---------- core/owner.py | 44 +++++++++++++++++++++++++++++++------------- main.py | 2 +- 6 files changed, 85 insertions(+), 40 deletions(-) diff --git a/cogs/audio/audio.py b/cogs/audio/audio.py index bdd984bbc..cf05f6b68 100644 --- a/cogs/audio/audio.py +++ b/cogs/audio/audio.py @@ -21,9 +21,9 @@ class Audio: await ctx.send("Join a voice channel first!") return - if ctx.guild.voice_client: - if ctx.guild.voice_client.channel != ctx.author.voice.channel: - await ctx.guild.voice_client.disconnect() + if ctx.voice_client: + if ctx.voice_client.channel != ctx.author.voice.channel: + await ctx.voice_client.disconnect() path = os.path.join("cogs", "audio", "songs", filename + ".mp3") if not os.path.isfile(path): await ctx.send("Let's play a file that exists pls") @@ -44,9 +44,9 @@ class Audio: await ctx.send("Youtube links pls") return - if ctx.guild.voice_client: - if ctx.guild.voice_client.channel != ctx.author.voice.channel: - await ctx.guild.voice_client.disconnect() + if ctx.voice_client: + if ctx.voice_client.channel != ctx.author.voice.channel: + await ctx.voice_client.disconnect() yt = YoutubeSource(url) player = PCMVolumeTransformer(yt, volume=1) voice = await ctx.author.voice.channel.connect() @@ -56,9 +56,9 @@ class Audio: @commands.command() async def stop(self, ctx): """Stops the music and disconnects""" - if ctx.guild.voice_client: - ctx.guild.voice_client.source.cleanup() - await ctx.guild.voice_client.disconnect() + if ctx.voice_client: + ctx.voice_client.source.cleanup() + await ctx.voice_client.disconnect() else: await ctx.send("I'm not even connected to a voice channel!", delete_after=2) await ctx.message.delete() @@ -66,8 +66,8 @@ class Audio: @commands.command() async def pause(self, ctx): """Pauses the music""" - if ctx.guild.voice_client: - ctx.guild.voice_client.pause() + if ctx.voice_client: + ctx.voice_client.pause() await ctx.send("👌", delete_after=2) else: await ctx.send("I'm not even connected to a voice channel!", delete_after=2) @@ -76,8 +76,8 @@ class Audio: @commands.command() async def resume(self, ctx): """Resumes the music""" - if ctx.guild.voice_client: - ctx.guild.voice_client.resume() + if ctx.voice_client: + ctx.voice_client.resume() await ctx.send("👌", delete_after=2) else: await ctx.send("I'm not even connected to a voice channel!", delete_after=2) @@ -86,8 +86,8 @@ class Audio: @commands.command(hidden=True) async def volume(self, ctx, n: float): """Sets the volume""" - if ctx.guild.voice_client: - ctx.guild.voice_client.source.volume = n + if ctx.voice_client: + ctx.voice_client.source.volume = n await ctx.send("Volume set.", delete_after=2) else: await ctx.send("I'm not even connected to a voice channel!", delete_after=2) diff --git a/core/__init__.py b/core/__init__.py index 849681040..f3b61d575 100644 --- a/core/__init__.py +++ b/core/__init__.py @@ -1,4 +1,5 @@ from .owner import Owner + def setup(bot): - bot.add_cog(Owner(bot)) \ No newline at end of file + bot.add_cog(Owner()) \ No newline at end of file diff --git a/core/bot.py b/core/bot.py index 05ef984c5..a37421d46 100644 --- a/core/bot.py +++ b/core/bot.py @@ -65,6 +65,13 @@ class Red(commands.Bot): """Lists packages present in the cogs the folder""" return os.listdir("cogs") + def save_packages_status(self): + loaded = [] + for package in self.extensions: + if package.startswith("cogs."): + loaded.append(package) + self.db.set_global("packages", loaded) + class ExitCodes(Enum): CRITICAL = 1 diff --git a/core/events.py b/core/events.py index 1bc224f41..ca806791b 100644 --- a/core/events.py +++ b/core/events.py @@ -8,7 +8,7 @@ from core.utils.chat_formatting import inline log = logging.getLogger("red") -def init_events(bot): +def init_events(bot, cli_flags): @bot.event async def on_connect(): @@ -17,14 +17,33 @@ def init_events(bot): @bot.event async def on_ready(): - if bot.uptime is None: - bot.uptime = datetime.datetime.utcnow() - print("Loading cogs...") - # load the packages at this point - total_channels = len([c for c in bot.get_all_channels()]) - total_users = len(set([m for m in bot.get_all_members()])) - print("Ready and operational on {} servers.\n" - "".format(len(bot.guilds))) + if bot.uptime is not None: + return + + bot.uptime = datetime.datetime.utcnow() + + if cli_flags.no_cogs is False: + print("Loading packages...") + failed = [] + packages = bot.db.get_global("packages", []) + + for package in packages: + try: + bot.load_extension(package) + except Exception as e: + log.exception("Failed to load package {}".format(package), + exc_info=e) + failed.append(package) + + if failed: + bot.save_packages_status() + if packages: + print("Loaded packages: " + ", ".join(packages)) + + # total_channels = len([c for c in bot.get_all_channels()]) + # total_users = len(set([m for m in bot.get_all_members()])) + + print("Ready and operational on {} servers.".format(len(bot.guilds))) @bot.event async def on_command_error(error, ctx): @@ -61,7 +80,7 @@ def init_events(bot): elif isinstance(error, commands.CommandNotFound): pass elif isinstance(error, commands.CheckFailure): - await ctx.send("⛔") + await ctx.send("⛔ You are not authorized to issue that command.") elif isinstance(error, commands.NoPrivateMessage): await ctx.send("That command is not available in DMs.") elif isinstance(error, commands.CommandOnCooldown): diff --git a/core/owner.py b/core/owner.py index 3f34ddc65..f040aa471 100644 --- a/core/owner.py +++ b/core/owner.py @@ -1,26 +1,34 @@ from discord.ext import commands from core import checks from core.utils.chat_formatting import box +import logging import asyncio import importlib import os import discord +log = logging.getLogger("red") + class Owner: """All owner-only commands that relate to debug bot operations.""" - def __init__(self, bot): - self.bot = bot - @commands.command() @checks.is_owner() async def load(self, ctx, *, cog_name: str): """Loads a package""" if not cog_name.startswith("cogs."): cog_name = "cogs." + cog_name - self.bot.load_extension(cog_name) - await ctx.send("Done.") + + try: + ctx.bot.load_extension(cog_name) + except Exception as e: + log.exception("Package loading failed", exc_info=e) + await ctx.send("Failed to load package. Check your console or " + "logs for details.") + else: + ctx.bot.save_packages_status() + await ctx.send("Done.") @commands.group() @checks.is_owner() @@ -28,8 +36,10 @@ class Owner: """Unloads a package""" if not cog_name.startswith("cogs."): cog_name = "cogs." + cog_name - if cog_name in self.bot.extensions: - self.bot.unload_extension(cog_name) + + if cog_name in ctx.bot.extensions: + ctx.bot.unload_extension(cog_name) + ctx.bot.save_packages_status() await ctx.send("Done.") else: await ctx.send("That extension is not loaded.") @@ -40,10 +50,18 @@ class Owner: """Reloads a package""" if not cog_name.startswith("cogs."): cog_name = "cogs." + cog_name - self.refresh_modules(cog_name) - self.bot.unload_extension(cog_name) - self.bot.load_extension(cog_name) - await ctx.send("Done.") + + try: + self.refresh_modules(cog_name) + ctx.bot.unload_extension(cog_name) + ctx.bot.load_extension(cog_name) + except Exception as e: + log.exception("Package reloading failed", exc_info=e) + await ctx.send("Failed to reload package. Check your console or " + "logs for details.") + else: + ctx.bot.save_packages_status() + await ctx.send("Done.") def refresh_modules(self, module): """Interally reloads modules so that changes are detected""" @@ -69,7 +87,7 @@ class Owner: result = None global_vars = globals().copy() - global_vars['bot'] = self.bot + global_vars['bot'] = ctx.bot global_vars['ctx'] = ctx global_vars['message'] = ctx.message global_vars['author'] = ctx.message.author @@ -109,7 +127,7 @@ class Owner: ctx.message.author = user ctx.message.content = ctx.prefix + command - await self.bot.process_commands(ctx.message) + await ctx.bot.process_commands(ctx.message) ctx.message.author = old_author ctx.message.content = old_content diff --git a/main.py b/main.py index fafadb482..d251ecc7b 100644 --- a/main.py +++ b/main.py @@ -57,7 +57,7 @@ if __name__ == '__main__': description = "Red v3 - Alpha" red = Red(cli_flags, description=description, pm_help=None) init_global_checks(red) - init_events(red) + init_events(red, cli_flags) red.load_extension('core') if cli_flags.dev: pass # load dev cog here?