diff --git a/.gitignore b/.gitignore index ca19a4c..048da31 100644 --- a/.gitignore +++ b/.gitignore @@ -67,3 +67,5 @@ temp.zip config/* .idea/* +venv/* +data/* diff --git a/main.py b/main.py index d5e310e..72264a2 100644 --- a/main.py +++ b/main.py @@ -215,7 +215,7 @@ def load_modules_info(): class LBI(discord.Client): - base_path = "storage" + base_path = "data" debug = log_LBI.debug info = log_LBI.info warning = log_LBI.warning @@ -344,10 +344,18 @@ class LBI(discord.Client): @event def dispatch(self, event, *args, **kwargs): + # Dispatch to handle wait_* commands super().dispatch(event, *args, **kwargs) + # Dispatch to modules for module in self.modules.values(): module["initialized_class"].dispatch(event, *args, **kwargs) + @event + async def on_error(self, event_method, *args, **kwargs): + # This event is special because it is call directly + for module in self.modules.values(): + await module["initialized_class"].on_error(event_method, *args, **kwargs) + class ClientById: client: LBI @@ -453,7 +461,7 @@ print(os.path.join("/tmp", os.path.dirname(os.path.realpath(__file__))) + ".sock loop = asyncio.get_event_loop() #loop.add_signal_handler(signal.SIGINT, loop.stop) -loop.set_exception_handler(execption_handler) +#loop.set_exception_handler(execption_handler) t = loop.create_unix_server(Communication, path=os.path.join("/tmp", os.path.dirname(os.path.realpath(__file__)) + ".sock")) loop.run_until_complete(t) diff --git a/modules/base/Base.py b/modules/base/Base.py index ff7c3ae..4db4d80 100644 --- a/modules/base/Base.py +++ b/modules/base/Base.py @@ -35,8 +35,9 @@ class BaseClass: self.client = client self.storage = FSStorage(path.join(self.client.base_path, self.name)) self.objects = FSObjects(self.storage) - if not self.storage.isdir(path.join("storage", self.name)): - self.storage.makedirs(path.join("storage", self.name), exist_ok=True) + # Non necessaire car géré par fsstorage + #if not self.storage.isdir(path.join("storage", self.name)): + # self.storage.makedirs(path.join("storage", self.name), exist_ok=True) async def send_help(self, channel): embed = discord.Embed( @@ -50,7 +51,9 @@ class BaseClass: inline=False) await channel.send(embed=embed) - async def auth(self, user, role_list): + async def auth(self, user, role_list=None): + if role_list is None: + role_list = self.authorized_roles if type(role_list) == list: if user.id in self.client.owners: return True @@ -88,10 +91,13 @@ class BaseClass: self.client.config["prefix"] + (self.command_text if self.command_text else "")) sub_command, args, kwargs = self._parse_command_content(content) sub_command = "com_" + sub_command - if sub_command in dir(self): - await self.__getattribute__(sub_command)(message, args, kwargs) + if await self.auth(message.author): + if sub_command in dir(self): + await self.__getattribute__(sub_command)(message, args, kwargs) + else: + await self.command(message, [sub_command[4:]] + args, kwargs) else: - await self.command(message, [sub_command[4:]] + args, kwargs) + await self.unauthorized(message, [sub_command[4:]] + args, kwargs) @staticmethod def _parse_command_content(content): @@ -160,7 +166,8 @@ class BaseClass: Function which is executed for all command_text doesn't match with a `com_{subcommand}` function""" pass - + async def unauthorized(self, message): + await message.channel.send("Vous n'êtes pas autorisé à effectuer cette commande") def dispatch(self, event, *args, **kwargs): # Method to call @@ -172,22 +179,7 @@ class BaseClass: pass else: # Run event - asyncio.ensure_future(self._run_event(coro, method, *args, **kwargs), loop=self.client.loop) - - async def _run_event(self, coro, event_name, *args, **kwargs): - # Run event - try: - await coro(*args, **kwargs) - except asyncio.CancelledError: - # If function is cancelled pass silently - pass - except Exception: - try: - # Call error function - await self.on_error(event_name, *args, **kwargs) - except asyncio.CancelledError: - # If error event is canceled pass silently - pass + asyncio.ensure_future(self.client._run_event(coro, method, *args, **kwargs), loop=self.client.loop) async def on_error(self, event_method, *args, **kwargs): # Basic error handler diff --git a/modules/base/BaseLua.py b/modules/base/BaseLua.py index 7c4a105..3397065 100644 --- a/modules/base/BaseLua.py +++ b/modules/base/BaseLua.py @@ -41,35 +41,48 @@ class BaseClassLua(BaseClass): print(os.path.abspath(path)) self.luaMethods = self.lua.require(path) + def call(self, method, *args, **kwargs): + # Try to run lua method then python one + if self.luaMethods[method] is not None: + async def coro(*args, **kwargs): + self.luaMethods[method](self, asyncio.ensure_future, discord, *args, *kwargs) + asyncio.ensure_future(self.client._run_event(coro, method, *args, **kwargs), loop=self.client.loop) + try: + coro = getattr(self, method) + except AttributeError: + pass + else: + asyncio.ensure_future(self.client._run_event(coro, method, *args, **kwargs), loop=self.client.loop) + def dispatch(self, event, *args, **kwargs): method = "on_"+event if self.luaMethods[method] is not None: - self.luaMethods[method](asyncio.ensure_future, self, *args, **kwargs) - else: # If lua methods not found, dispatch to python methods + async def coro(*args, **kwargs): + self.luaMethods[method](self, asyncio.ensure_future, discord, *args, **kwargs) + asyncio.ensure_future(self.client._run_event(coro, method, *args, **kwargs), loop=self.client.loop) + else: # If lua method not found, pass super().dispatch(event, *args, **kwargs) - async def _run_event(self, coro, event_name, *args, **kwargs): - # Overide here to execute lua on_error if it exists - # Run event - try: - await coro(*args, **kwargs) - except asyncio.CancelledError: - # If function is cancelled pass silently - pass - except Exception: - try: - # Call error function - if self.luaMethods["on_error"] is not None: - self.luaMethods["on_error"](self, asyncio.ensure_future, discord, *args, **kwargs) + async def parse_command(self, message): + """Parse a command_text from received message and execute function + %git update + com_update(m..) + Parse message like `{prefix}{command_text} subcommand` and call class method `com_{subcommand}`. + + :param message: message to parse + :type message: discord.Message""" + if message.content.startswith(self.client.config["prefix"] + (self.command_text if self.command_text else "")): + + content = message.content.lstrip( + self.client.config["prefix"] + (self.command_text if self.command_text else "")) + sub_command, args, kwargs = self._parse_command_content(content) + sub_command = "com_" + sub_command + if await self.auth(message.user): + if self.luaMethods[sub_command] is not None: + self.luaMethods[sub_command](self, asyncio.ensure_future, discord, message, args, kwargs) else: - await self.on_error(event_name, *args, **kwargs) - except asyncio.CancelledError: - # If error event is canceled pass silently - pass - - async def on_error(self, event_method, *args, **kwargs): - # Base on_error event, executed if lua not provide it - # Basic error handler - print('Ignoring exception in {}'.format(event_method), file=sys.stderr) - traceback.print_exc() + if self.luaMethods["command"] is not None: + self.luaMethods["command"](self, asyncio.ensure_future, discord, message, [sub_command[4:]] + args, kwargs) + else: + await self.unautorized(message, [sub_command[4:]] + args, kwargs) diff --git a/modules/errors/__init__.py b/modules/errors/__init__.py index 23d8480..1dc3626 100644 --- a/modules/errors/__init__.py +++ b/modules/errors/__init__.py @@ -44,10 +44,10 @@ class MainClass(BaseClassPython): await delete_message.delete() except: raise - self.objects.save_object(self.errorsDeque, 'errorsDeque') + self.objects.save_object('errorsDeque', self.errorsDeque) async def command(self, message, args, kwargs): - raise Exception("Si cette erreur apparait, alors tout est normal") + 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()), @@ -72,7 +72,7 @@ class MainClass(BaseClassPython): embed=embed.set_footer(text="Ce message ne s'autodétruira pas.", icon_url=self.icon)) except: pass - self.objects.save_object(self.errorsDeque, 'errorsDeque') + self.objects.save_object('errorsDeque', self.errorsDeque) await asyncio.sleep(60) try: channel = self.client.get_channel(message_list[0]) @@ -85,4 +85,4 @@ class MainClass(BaseClassPython): self.errorsDeque.remove(message_list) except ValueError: pass - self.objects.save_object(self.errorsDeque, 'errorsDeque') + self.objects.save_object('errorsDeque', self.errorsDeque) diff --git a/modules/modules/__init__.py b/modules/modules/__init__.py index 40cbbcc..b991347 100644 --- a/modules/modules/__init__.py +++ b/modules/modules/__init__.py @@ -19,6 +19,9 @@ class MainClass(BaseClassPython): "`{prefix}{command} disable `": "Disable module ``.", "`{prefix}{command} reload `": "Reload module ``", "`{prefix}{command} web_list`": "List all available modules from repository", + # "`{prefix}{command} web_source`": "List all source repositories", + # "`{prefix}{command} web_source remove `": "Remove url from repository list", + # "`{prefix}{command} web_source add `": "Add url to repository list", } } @@ -27,7 +30,8 @@ class MainClass(BaseClassPython): self.storage.mkdir("modules", exist_ok=True) self.api = Api() - def get_all_modules(self): + @staticmethod + def get_all_modules(): all_items = os.listdir("modules") modules = [] for item in all_items: diff --git a/modules/test_lua/main.lua b/modules/test_lua/main.lua index ad966f0..f713517 100644 --- a/modules/test_lua/main.lua +++ b/modules/test_lua/main.lua @@ -2,7 +2,7 @@ main = {} function main.on_message(self, await, discord, message) if message.author.bot == false then - + -- message.channel.send("Test") end end diff --git a/storage/FileSystem.py b/storage/FileSystem.py index 3295412..9a9f913 100644 --- a/storage/FileSystem.py +++ b/storage/FileSystem.py @@ -15,6 +15,7 @@ class FSStorage(Storage): def _topath(self, path): """Transform a path to a full path""" + return os.path.join(self.base_path, path) # TODO: Modifier ca if path.startswith("/"): return os.path.join(self.base_path, # Always add baspath to avoid going outside protected zone os.path.abspath(os.path.join(self.base_path, @@ -65,10 +66,10 @@ class FSStorage(Storage): os.sync() def open(self, path, mode): - return open(path, mode) + return open(self._topath(path), mode) def exists(self, path): - return os.path.exists(path) + return os.path.exists(self._topath(path)) def isdir(self, path): return os.path.isdir(self._topath(path)) diff --git a/storage/base.py b/storage/base.py index c5b2b10..402a05a 100644 --- a/storage/base.py +++ b/storage/base.py @@ -122,8 +122,11 @@ class Storage: class Objects: - def __init__(self, storage): + storage: Storage + + def __init__(self, storage: Storage): self.storage = storage + self.storage.makedirs("objects", exist_ok=True) def save_object(self, object_name, object_instance): """Save object into pickle file"""