diff --git a/Pipfile b/Pipfile index 0c9b963..166e33d 100644 --- a/Pipfile +++ b/Pipfile @@ -12,11 +12,15 @@ aiohttp = "*" aiofiles = "*" lupa = "*" aiofile = "*" -pyyaml = "*" +toml = "*" "discord.py" = {version = "*", extras = ["voice",]} [dev-packages] + + [requires] python_version = "3.7" + + diff --git a/config/FileSystem.py b/config/FileSystem.py index a367b56..e08e0dd 100644 --- a/config/FileSystem.py +++ b/config/FileSystem.py @@ -1,6 +1,6 @@ import os -import yaml +import toml from config.Base import Config @@ -8,7 +8,7 @@ from config.Base import Config class FSConfig(Config): path: str - def __init__(self, path="config.json", *args, **kwargs): + def __init__(self, path="config.toml", *args, **kwargs): super().__init__(*args, **kwargs) self.path = path os.makedirs(os.path.dirname(path), exist_ok=True) @@ -17,13 +17,11 @@ class FSConfig(Config): def _load(self): with open(self.path, "r") as file: content = file.read() - self.config = yaml.load(content, Loader=yaml.BaseLoader) + self.config = toml.loads(content) if self.config is None: - self.parent.config[self.name] = {} self.config = {} def _save(self): - content = yaml.dump(self.config) - print(self.config) + content = toml.dumps(self.config) with open(self.path, "w") as file: file.write(content) diff --git a/main.py b/main.py index 4361e74..a9699bb 100644 --- a/main.py +++ b/main.py @@ -18,6 +18,7 @@ from packaging.version import Version from config.FileSystem import FSConfig from errors import IncompatibleModule +from modules.base import base_supported_type __version__ = "0.1.0" @@ -74,7 +75,6 @@ class Module: return False with open(os.path.join("modules", self.name, "version.json")) as file: versions = json.load(file) - print(versions) if "version" not in versions.keys(): return False if "dependencies" not in versions.keys(): @@ -83,6 +83,8 @@ class Module: return False if "type" not in versions.keys(): return False + if versions["type"] not in base_supported_type: + return False return True @property @@ -226,7 +228,7 @@ class LBI(discord.Client): def __init__(self, config=None, *args, **kwargs): super().__init__(*args, **kwargs) if config is None: - config = FSConfig(path="data/config.yml") + config = FSConfig(path="data/config.toml") self.reloading = False self.id = ClientById(self) self.ready = False diff --git a/modules/base/Base.py b/modules/base/Base.py index fd72e52..a2e10d2 100644 --- a/modules/base/Base.py +++ b/modules/base/Base.py @@ -30,13 +30,12 @@ class BaseClass: Initialize module class, always call it to set self.client when you override it. :param client: client instance - :type client: NikolaTesla""" + :type client: LBI""" self.client = client self.storage = FSStorage(path.join(self.client.base_path, self.name)) self.objects = FSObjects(self.storage) self.config = Config(parent=self.client.config, name="mod-"+self.name) - self.config["authorized_roles"] = self.config["authorized_roles"] or self.authorized_roles - self.config["authorized_users"] = self.config["authorized_users"] or self.authorized_users + self.config.init({"authorized_roles": self.authorized_roles, "authorized_users": self.authorized_users}) async def send_help(self, channel): embed = discord.Embed( @@ -61,9 +60,9 @@ class BaseClass: :type user: discord.User """ if role_list is None: - role_list = self.authorized_roles + role_list = self.config["authorized_roles"] if user_list is None: - user_list = self.authorized_users + user_list = self.config["authorized_users"] if len(role_list) == 0 and len(user_list) == 0: # Everyone can use this command return True diff --git a/modules/base/__init__.py b/modules/base/__init__.py index 3549db6..e5d1805 100644 --- a/modules/base/__init__.py +++ b/modules/base/__init__.py @@ -1,2 +1,3 @@ from .BasePython import BaseClassPython -from .BaseLua import BaseClassLua \ No newline at end of file +from .BaseLua import BaseClassLua +base_supported_type = ["python", "lua"] \ No newline at end of file diff --git a/modules/errors/__init__.py b/modules/errors/__init__.py index a1a8c51..364f4e7 100644 --- a/modules/errors/__init__.py +++ b/modules/errors/__init__.py @@ -1,11 +1,14 @@ import asyncio +import time + +import datetime import random import traceback import collections import discord +from discord import Message -from config.Base import Config from modules.base import BaseClassPython @@ -26,9 +29,7 @@ class MainClass(BaseClassPython): def __init__(self, client): super().__init__(client) - self.config["dev_chan"] = self.config["dev_chan"] or [] - self.config["meme"] = [""] - self.config["icon"] = "" + self.config.init({"dev_chan":[], "memes":[""], "icon":""}) self.errorsDeque = None async def on_ready(self): @@ -38,10 +39,10 @@ class MainClass(BaseClassPython): self.errorsDeque = collections.deque() for i in range(len(self.errorsDeque)): try: - messagelst = self.errorsDeque.popleft() - channel = self.client.get_channel(messagelst[0]) - delete_message = await channel.fetch_message(messagelst[1]) - await delete_message.delete() + msg_id = self.errorsDeque.popleft() + channel = self.client.get_channel(msg_id["channel_id"]) + to_delete = await channel.fetch_message(msg_id["msg_id"]) + await to_delete.delete() except: raise self.objects.save_object('errorsDeque', self.errorsDeque) @@ -50,39 +51,59 @@ class MainClass(BaseClassPython): raise Exception("KERNEL PANIC!!!") async def on_error(self, event, *args, **kwargs): - embed = discord.Embed(title="Aïe :/", description="```PYTHON\n{0}```".format(traceback.format_exc()), - color=self.color).set_image(url=random.choice(self.memes)) + """Send error message""" + # Search first channel instance found in arg, then search in kwargs + channel = None + for arg in args: + if type(arg) == Message: + channel = arg.channel + break + if type(arg) == discord.TextChannel: + channel = arg + break + if channel is None: + for _,v in kwargs.items(): + if type(v) == discord.Message: + channel = v.channel + break + if type(v) == discord.TextChannel: + channel = v + break# Create embed + embed = discord.Embed( + title="[Erreur] Aïe :/", + description="```python\n{0}```".format(traceback.format_exc()), + color=self.color) + embed.set_image(url=random.choice(self.config["memes"])) message_list = None - try: - message = await args[0].channel.send( - embed=embed.set_footer(text="Ce message va s'autodétruire dans une minute.", icon_url=self.icon)) - message_list = [message.channel.id, message.id] - self.errorsDeque.append(message_list) - except: - try: - message = args[1].channel.send( - embed=embed.set_footer(text="Ce message va s'autodétruire dans une minute.", icon_url=self.icon)) - message_list = [message.channel.id, message.id] - self.errorsDeque.append(message_list) - except: - pass + + # Send message to dev channels for chanid in self.config["dev_chan"]: try: await self.client.get_channel(chanid).send( embed=embed.set_footer(text="Ce message ne s'autodétruira pas.", icon_url=self.icon)) except: pass - self.objects.save_object('errorsDeque', self.errorsDeque) - await asyncio.sleep(60) - try: - channel = self.client.get_channel(message_list[0]) - delete_message = await channel.fetch_message(message_list[1]) - await delete_message.delete() - except: - raise - finally: + # Send message to current channel if exists + if channel is not None: + message = await channel.send(embed=embed.set_footer(text="Ce message va s'autodétruire dans une minute", + icon_url=self.config["icon"])) + msg_id = {"chan_id": message.channel.id, "msg_id": message.id} + self.errorsDeque.append(msg_id) + # Save message in errorsDeque now to keep them if a reboot happend during next 60 seconds + self.objects.save_object('errorsDeque', self.errorsDeque) + + # Wait 60 seconds and delete message + await asyncio.sleep(60) try: - self.errorsDeque.remove(message_list) - except ValueError: - pass - self.objects.save_object('errorsDeque', self.errorsDeque) + channel = self.client.get_channel(msg_id["chan_id"]) + delete_message = await channel.fetch_message(msg_id["msg_id"]) + await delete_message.delete() + except: + raise + finally: + try: + self.errorsDeque.remove(msg_id) + except ValueError: + pass + # Save now to avoid deleting unkown message + self.objects.save_object('errorsDeque', self.errorsDeque) diff --git a/modules/modules/__init__.py b/modules/modules/__init__.py index d3d73d9..ca7399c 100644 --- a/modules/modules/__init__.py +++ b/modules/modules/__init__.py @@ -36,7 +36,7 @@ class MainClass(BaseClassPython): all_items = os.listdir("modules") modules = [] for item in all_items: - if item not in ["__init__.py", "base", "__pycache__", "dummy"]: + if item not in ["__init__.py", "base", "__pycache__"]: if os.path.isfile(os.path.join("modules", item)): modules.append(item[:-3]) else: @@ -58,7 +58,9 @@ class MainClass(BaseClassPython): return for arg in args: e = self.client.load_module(arg) - if e: + if e == 2: + await message.channel.send("Module {module} is incompatible.") + elif e: await message.channel.send("An error occurred during the loading of the module {module}: {error}." .format(module=arg, error=e)) await self.com_list(message, args, kwargs) @@ -106,10 +108,16 @@ class MainClass(BaseClassPython): async def com_list(self, message, args, kwargs): list_files = self.get_all_modules() activated = set(self.client.config["modules"]) - activated_string = "\n+ " + "\n+ ".join(activated) - deactivated_string = "- " + "\n- ".join(list_files.difference(activated)) + if len(activated): + activated_string = "\n+ " + "\n+ ".join(activated) + else: + activated_string = "" + if len(activated) != len(list_files): + deactivated_string = "\n- " + "\n- ".join(list_files.difference(activated)) + else: + deactivated_string = "" embed = discord.Embed(title="[Modules] - Liste des modules", - description="```diff\n{activated}\n{deactivated}```".format( + description="```diff{activated}{deactivated}```".format( activated=activated_string, deactivated=deactivated_string) ) diff --git a/modules/modules/api.py b/modules/modules/api.py index 4726f03..ef087ed 100644 --- a/modules/modules/api.py +++ b/modules/modules/api.py @@ -31,6 +31,10 @@ class Api: async def download(self, module, version): await self._download("modules/"+module+"/"+version, filename="temp.zip") - shutil.rmtree(os.path.join("modules, module")) + # TODO: Supprimer le dossier ici + try: + shutil.rmtree(os.path.join("modules", module)) + except: + print('Error while deleting directory') with zipfile.ZipFile('temp.zip', "r") as z: z.extractall(os.path.join("modules", module))