From bd152db5c451b11eaf9a0c70bd06504a2ea06719 Mon Sep 17 00:00:00 2001 From: fomys Date: Wed, 22 May 2019 21:30:06 +0200 Subject: [PATCH] j'espere que ca marche --- .gitignore | 1 - main.py | 335 ++++++--------------------------------- modules/base/__init__.py | 272 +++++-------------------------- modules/modules/api.py | 1 + storage/FileSystem.py | 69 ++++++++ storage/__init__.py | 1 + storage/base.py | 107 +++++++++++++ storage/path.py | 7 + 8 files changed, 269 insertions(+), 524 deletions(-) create mode 100644 storage/FileSystem.py create mode 100644 storage/__init__.py create mode 100644 storage/base.py create mode 100644 storage/path.py diff --git a/.gitignore b/.gitignore index 8157f2e..ca19a4c 100644 --- a/.gitignore +++ b/.gitignore @@ -64,7 +64,6 @@ target/ .swp.* temp.zip -storage/* config/* .idea/* diff --git a/main.py b/main.py index c6daac4..2a0c392 100644 --- a/main.py +++ b/main.py @@ -189,13 +189,7 @@ setup_logging() log_discord = logging.getLogger('discord') log_LBI = logging.getLogger('LBI') - -debug = log_LBI.debug -info = log_LBI.info -warning = log_LBI.warning -error = log_LBI.error -critical = log_LBI.critical - +log_communication = logging.getLogger('communication') def load_modules_info(): for mod in os.listdir("modules"): @@ -318,265 +312,10 @@ class LBI(discord.Client): self.modules = {} @event - async def on_ready(self): + async def dispatch(self, event, *args, **kwargs): + super().dispatch(event, *args, **kwargs) for module in self.modules.values(): - await module["initialized_class"].on_ready() - - @event - async def on_socket_raw_receive(self, message): - for module in self.modules.values(): - await module["initialized_class"].on_socket_raw_receive(message) - - @event - async def on_socket_raw_send(self, payload): - for module in self.modules.values(): - await module["initialized_class"].on_socket_raw_send(payload) - - @event - async def on_typing(self, channel, user, when): - for module in self.modules.values(): - await module["initialized_class"].on_typing(channel, user, when) - - @event - async def on_message(self, message): - print(message.content) - try: - for module in self.modules.values(): - await module["initialized_class"]._on_message(message) - except RuntimeError: - info("Liste des modules changée pendant l'execution d'un on_message") - - @event - async def on_message_delete(self, message): - for module in self.modules.values(): - await module["initialized_class"].on_message_delete(message) - - @event - async def on_raw_message_delete(self, payload): - for module in self.modules.values(): - await module["initialized_class"].on_raw_message_delete(payload) - - @event - async def on_raw_bulk_message_delete(self, payload): - for module in self.modules.values(): - await module["initialized_class"].on_raw_bulk_message_delete(payload) - - @event - async def on_message_edit(self, before, after): - for module in self.modules.values(): - await module["initialized_class"].on_message_edit(before, after) - - @event - async def on_raw_message_edit(self, payload): - for module in self.modules.values(): - await module["initialized_class"].on_raw_message_edit(payload) - - @event - async def on_reaction_add(self, reaction, user): - for module in self.modules.values(): - await module["initialized_class"].on_reaction_add(reaction, user) - - @event - async def on_raw_reaction_add(self, payload): - for module in self.modules.values(): - await module["initialized_class"].on_raw_reaction_add(payload) - - @event - async def on_reaction_remove(self, reaction, user): - for module in self.modules.values(): - await module["initialized_class"].on_reaction_remove(reaction, user) - - @event - async def on_raw_reaction_remove(self, payload): - for module in self.modules.values(): - await module["initialized_class"].on_raw_reaction_remove(payload) - - @event - async def on_reaction_clear(self, message, reactions): - for module in self.modules.values(): - await module["initialized_class"].on_reaction_clear(message, reactions) - - @event - async def on_raw_reaction_clear(self, payload): - for module in self.modules.values(): - await module["initialized_class"].on_raw_reaction_clear(payload) - - @event - async def on_private_channel_delete(self, channel): - for module in self.modules.values(): - await module["initialized_class"].on_private_channel_delete(channel) - - @event - async def on_private_channel_create(self, channel): - for module in self.modules.values(): - await module["initialized_class"].on_private_channel_create(channel) - - @event - async def on_private_channel_update(self, before, after): - for module in self.modules.values(): - await module["initialized_class"].on_private_channel_update(before, after) - - @event - async def on_private_channel_pins_update(self, channel, last_pin): - for module in self.modules.values(): - await module["initialized_class"].on_private_channel_pins_update(channel, last_pin) - - @event - async def on_guild_channel_delete(self, channel): - for module in self.modules.values(): - await module["initialized_class"].on_guild_channel_delete(channel) - - @event - async def on_guild_channel_create(self, channel): - for module in self.modules.values(): - await module["initialized_class"].on_guild_channel_create(channel) - - @event - async def on_guild_channel_update(self, before, after): - for module in self.modules.values(): - await module["initialized_class"].on_guild_channel_update(before, after) - - @event - async def on_guild_channel_pins_update(self, channel, last_pin): - for module in self.modules.values(): - await module["initialized_class"].on_guild_channel_pins_update(channel, last_pin) - - @event - async def on_member_join(self, member): - for module in self.modules.values(): - await module["initialized_class"].on_member_join(member) - - @event - async def on_member_remove(self, member): - for module in self.modules.values(): - await module["initialized_class"].on_member_remove(member) - - @event - async def on_member_update(self, before, after): - for module in self.modules.values(): - await module["initialized_class"].on_member_update(before, after) - - @event - async def on_guild_join(self, guild): - for module in self.modules.values(): - await module["initialized_class"].on_guild_join(guild) - - @event - async def on_guild_remove(self, guild): - for module in self.modules.values(): - await module["initialized_class"].on_guild_remove(guild) - - @event - async def on_guild_update(self, before, after): - for module in self.modules.values(): - await module["initialized_class"].on_guild_update(before, after) - - @event - async def on_guild_role_create(self, role): - for module in self.modules.values(): - await module["initialized_class"].on_guild_role_create(role) - - @event - async def on_guild_role_delete(self, role): - for module in self.modules.values(): - await module["initialized_class"].on_guild_role_delete(role) - - @event - async def on_guild_role_update(self, before, after): - for module in self.modules.values(): - await module["initialized_class"].on_guild_role_update(before, after) - - @event - async def on_guild_emojis_update(self, guild, before, after): - for module in self.modules.values(): - await module["initialized_class"].on_guild_emojis_update(guild, before, after) - - @event - async def on_guild_available(self, guild): - for module in self.modules.values(): - await module["initialized_class"].on_guild_available(guild) - - @event - async def on_guild_unavailable(self, guild): - for module in self.modules.values(): - await module["initialized_class"].on_guild_unavailable(guild) - - @event - async def on_voice_state_update(self, member, before, after): - for module in self.modules.values(): - await module["initialized_class"].on_voice_state_update(member, before, after) - - @event - async def on_member_ban(self, guild, user): - for module in self.modules.values(): - await module["initialized_class"].on_member_ban(guild, user) - - @event - async def on_member_unban(self, guild, user): - for module in self.modules.values(): - await module["initialized_class"].on_member_unban(guild, user) - - @event - async def on_group_join(self, channel, user): - for module in self.modules.values(): - await module["initialized_class"].on_group_join(channel, user) - - @event - async def on_group_remove(self, channel, user): - for module in self.modules.values(): - await module["initialized_class"].on_group_remove(channel, user) - - @event - async def on_relationship_add(self, relationship): - for module in self.modules.values(): - await module["initialized_class"].on_relationship_add(relationship) - - @event - async def on_relationship_remove(self, relationship): - for module in self.modules.values(): - await module["initialized_class"].on_relationship_remove(relationship) - - @event - async def on_relationship_update(self, before, after): - for module in self.modules.values(): - await module["initialized_class"].on_relationship_update(before, after) - - @event - async def on_connect(self): - for module in self.modules.values(): - await module["initialized_class"].on_connect() - - @event - async def on_shard_ready(self): - for module in self.modules.values(): - await module["initialized_class"].on_shard_ready() - - @event - async def on_resumed(self): - print("resumed") - for module in self.modules.values(): - await module["initialized_class"].on_resumed() - - @event - async def on_error(self, event_, *args, **kwargs): - print(event_, *args, **kwargs) - print(traceback.format_exc()) - for module in self.modules.values(): - await module["initialized_class"].on_error(event_, *args, **kwargs) - - @event - async def on_guild_integrations_update(self, guild): - for module in self.modules.values(): - await module["initialized_class"].on_guild_integrations_update(guild) - - @event - async def on_webhooks_update(self, channel): - for module in self.modules.values(): - await module["initialized_class"].on_webhooks_update(channel) - - @event - async def on_toto(self, data): - print(data) + await module["initialized_class"].dispatch(event, *args, **kwargs) class ClientById: @@ -629,34 +368,52 @@ class ClientById: channel = self.client.get_channel(id_) return channel.send(*args, **kwargs) + async def get_role(self, id_): + for guild in self.client.guilds: + role = discord.utils.get(guild.roles, id=id_) + if role: + return role + return None + +class Communication: + debug = log_communication.debug + info = log_communication.info + warning = log_communication.warning + error = log_communcation.error + critical = log_communication.critical + def __init__(self, client, sock_file=os.path.join("tmp", os.path.dirname(os.path.realpath(__file__))+".sock")): + self.sock_file = sock_file + self.client = client + + async def start(): + s = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) + try: + os.remove(self.sock_file) + except OSError: + pass + s.bind(sock_file) + while True: + data = conn.recv(1024) + content = data.decode("utf8") + log("Received:"+content) + if content.startwith("setparam"): + await parse_set_param(content) + + async def parse_set_param(self, data): + content = content[8:] + values = content.split("$¤$") + for value in values: + await client.dispatch("setparam", *values.split("$=$")) client = LBI() - - -def read_sock(): - print("connect") - import socket, os - s = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) - try: - os.remove("/tmp/bot.sock") # TODO: Changer le nom du socket car il en faut un par bot - except OSError: - pass - s.bind("/tmp/bot.sock") # TODO: Voir ici aussi - s.listen(1) - conn, addr = s.accept() - while 1: - data = conn.recv(1024) - print(data) - content = data.decode("utf8") - if content.startswith("send"): - print("okip") - client.dispatch("toto", data) - conn.send(data) - +communication = Communication() async def start_bot(): await client.start('TOKEN', max_messages=500000) +async def start_communication(): + await communication.start() + async def stop_bot(): await client.logout() @@ -666,6 +423,6 @@ async def main(): loop = asyncio.get_running_loop() with concurrent.futures.ProcessPoolExecutor() as pool: await loop.run_in_executor(pool, start_bot) - await loop.run_in_executor(pool, read_sock) + await loop.run_in_executor(pool, start_communication) -asyncio.run(main()) \ No newline at end of file +asyncio.run(main()) diff --git a/modules/base/__init__.py b/modules/base/__init__.py index d3ec095..9382fdb 100644 --- a/modules/base/__init__.py +++ b/modules/base/__init__.py @@ -1,40 +1,16 @@ """Base class for module, never use directly !!!""" +import asyncio +import sys + import os import pickle +import traceback import zipfile import discord - -class Storage: - def __init__(self, base_path, client): - self.client = client - self.base_path = base_path - try: - os.makedirs(base_path) - except FileExistsError: - self.client.info("Le dossier {dossier} a déjà été créé.".format(dossier=self.base_path)) - - def mkdir(self, directory): - try: - os.makedirs(self.path(directory)) - except FileExistsError: - self.client.info("Le dossier {dossier} a déjà été créé.".format(dossier=directory)) - - def mkzip(self, files, name): - with zipfile.ZipFile(self.path(files), 'w', zipfile.ZIP_DEFLATED) as zip_file: - for file in files: - zip_file.write(self.path(file), compress_type=zipfile.ZIP_DEFLATED) - return name - - def open(self, filename, *args, **kwargs): - return open(self.path(filename), *args, **kwargs) - - def path(self, filename): - return os.path.join(self.base_path, filename) - - def exists(self, filename): - return os.path.exists(self.path(filename)) +from storage import FSStorage +from storage.path import join class BaseClass: @@ -49,6 +25,7 @@ class BaseClass: help_active = False color = 0x000000 command_text = None + super_users = [] authorized_roles = [] def __init__(self, client): @@ -61,7 +38,7 @@ class BaseClass: self.client = client if not os.path.isdir(os.path.join("storage", self.name)): os.makedirs(os.path.join("storage", self.name)) - self.storage = Storage(os.path.join(self.client.base_path, self.name), client) + self.storage = FSStorage(join(self.client.base_path, self.name)) async def send_help(self, channel): embed = discord.Embed( @@ -175,10 +152,9 @@ class BaseClass: i += 1 return sub_command, args_, kwargs - async def _on_message(self, message): + async def on_message(self, message): """Override this function to deactivate command_text parsing""" await self.parse_command(message) - await self.on_message(message) async def command(self, message, args, kwargs): """Override this function to handle all messages starting with `{prefix}{command_text}` @@ -203,206 +179,34 @@ class BaseClass: """Check if pickle file exists""" return self.storage.exists(object_name) - def on_load(self): - """This function is called when module is loaded""" - pass + def dispatch(self, event, *args, **kwargs): + # Method to call + method = 'on_' + event + try: + # Try to get coro, if not exists pass without raise an error + coro = getattr(self, method) + except AttributeError: + pass + else: + # Run event + asyncio.ensure_future(self._run_event(coro, method, *args, **kwargs), loop=self.loop) - async def on_socket_raw_receive(self, message): - """Override this function to handle this event.""" - pass + 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 - async def on_socket_raw_send(self, payload): - """Override this function to handle this event.""" - pass - - async def on_typing(self, channel, user, when): - """Override this function to handle this event.""" - pass - - async def on_message(self, message): - """Override this function to handle this event.""" - pass - - async def on_message_delete(self, message): - """Override this function to handle this event.""" - pass - - async def on_raw_message_delete(self, payload): - """Override this function to handle this event.""" - pass - - async def on_raw_bulk_message_delete(self, payload): - """Override this function to handle this event.""" - pass - - async def on_message_edit(self, before, after): - """Override this function to handle this event.""" - pass - - async def on_raw_message_edit(self, payload): - """Override this function to handle this event.""" - pass - - async def on_reaction_add(self, reaction, user): - """Override this function to handle this event.""" - pass - - async def on_raw_reaction_add(self, payload): - """Override this function to handle this event.""" - pass - - async def on_reaction_remove(self, reaction, user): - """Override this function to handle this event.""" - pass - - async def on_raw_reaction_remove(self, payload): - """Override this function to handle this event.""" - pass - - async def on_reaction_clear(self, message, reactions): - """Override this function to handle this event.""" - pass - - async def on_raw_reaction_clear(self, payload): - """Override this function to handle this event.""" - pass - - async def on_private_channel_delete(self, channel): - """Override this function to handle this event.""" - pass - - async def on_private_channel_create(self, channel): - """Override this function to handle this event.""" - pass - - async def on_private_channel_update(self, before, after): - """Override this function to handle this event.""" - pass - - async def on_private_channel_pins_update(self, channel, last_pin): - """Override this function to handle this event.""" - pass - - async def on_guild_channel_delete(self, channel): - """Override this function to handle this event.""" - pass - - async def on_guild_channel_create(self, channel): - """Override this function to handle this event.""" - pass - - async def on_guild_channel_update(self, before, after): - """Override this function to handle this event.""" - pass - - async def on_guild_channel_pins_update(self, channel, last_pin): - """Override this function to handle this event.""" - pass - - async def on_member_join(self, member): - """Override this function to handle this event.""" - pass - - async def on_member_remove(self, member): - """Override this function to handle this event.""" - pass - - async def on_member_update(self, before, after): - """Override this function to handle this event.""" - pass - - async def on_guild_join(self, guild): - """Override this function to handle this event.""" - pass - - async def on_guild_remove(self, guild): - """Override this function to handle this event.""" - pass - - async def on_guild_update(self, before, after): - """Override this function to handle this event.""" - pass - - async def on_guild_role_create(self, role): - """Override this function to handle this event.""" - pass - - async def on_guild_role_delete(self, role): - """Override this function to handle this event.""" - pass - - async def on_guild_role_update(self, before, after): - """Override this function to handle this event.""" - pass - - async def on_guild_emojis_update(self, guild, before, after): - """Override this function to handle this event.""" - pass - - async def on_guild_available(self, guild): - """Override this function to handle this event.""" - pass - - async def on_guild_unavailable(self, guild): - """Override this function to handle this event.""" - pass - - async def on_voice_state_update(self, member, before, after): - """Override this function to handle this event.""" - pass - - async def on_member_ban(self, guild, user): - """Override this function to handle this event.""" - pass - - async def on_member_unban(self, guild, user): - """Override this function to handle this event.""" - pass - - async def on_group_join(self, channel, user): - """Override this function to handle this event.""" - pass - - async def on_group_remove(self, channel, user): - """Override this function to handle this event.""" - pass - - async def on_relationship_add(self, relationship): - """Override this function to handle this event.""" - pass - - async def on_relationship_remove(self, relationship): - """Override this function to handle this event.""" - pass - - async def on_relationship_update(self, before, after): - """Override this function to handle this event.""" - pass - - async def on_ready(self): - """Override this function to handle this event.""" - pass - - async def on_connect(self): - """Override this function to handle this event.""" - pass - - async def on_shard_ready(self): - """Override this function to handle this event.""" - pass - - async def on_resumed(self): - """Override this function to handle this event.""" - pass - - async def on_error(self, event, *args, **kwargs): - """Override this function to handle this event.""" - pass - - async def on_guild_integrations_update(self, guild): - """Override this function to handle this event.""" - pass - - async def on_webhooks_update(self, channel): - """Override this function to handle this event.""" - pass + async def on_error(self, event_method, *args, **kwargs): + # Basic error handler + print('Ignoring exception in {}'.format(event_method), file=sys.stderr) + traceback.print_exc() diff --git a/modules/modules/api.py b/modules/modules/api.py index 8d0d589..786c2e4 100644 --- a/modules/modules/api.py +++ b/modules/modules/api.py @@ -32,3 +32,4 @@ class Api: await self._download("modules/"+module+"/"+version, filename="temp.zip") with zipfile.ZipFile('temp.zip', "r") as z: z.extractall(os.path.join("modules", module)) +#78.200.118.13:8000 \ No newline at end of file diff --git a/storage/FileSystem.py b/storage/FileSystem.py new file mode 100644 index 0000000..fb04b1f --- /dev/null +++ b/storage/FileSystem.py @@ -0,0 +1,69 @@ +import os + +from storage.base import Storage + + +class FSStorage(Storage): + """ + Simple filesystem storage + """ + + def __init__(self, base_path="storage"): + super().__init__() + self.base_path = os.path.abspath(base_path) + os.makedirs(self.base_path) + self.current_dir = "/" + + def _topath(self, path): + """Transform a path to a full path""" + 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, + os.path.normpath(path))).lstrip(self.base_path)) + else: + 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, + self.current_dir, + os.path.normpath(path))).lstrip(self.base_path)) + + def access(self, path): + # Normalize path and transform it to absolute path, remove base_path part and add it again to avoid going + # outside protected folder + return os.access(self._topath(path)) + + def chdir(self, path): + self.current_dir = self._topath(path) + return self.current_dir + + def getcwd(self): + return self.current_dir + + def listdir(self, path="."): + return os.listdir(self._topath(path)) + + def mkdir(self, path): + os.mkdir(self._topath(path)) + return self._topath(path) + + def makedirs(self, path, exist_ok=False): + os.makedirs(self._topath(path), exist_ok=exist_ok) + return self._topath(path) + + def remove(self, path): + os.remove(self._topath(path)) + + def rename(self, src, dst): + os.rename(self._topath(src), self._topath(dst)) + return self._topath(dst) + + def rmdir(self, path): + os.rmdir(self._topath(path)) + + def sync(self): + os.sync() + + def open(self, path, mode): + return open(path, mode) + + def exists(self, path): + return os.path.exists(path) diff --git a/storage/__init__.py b/storage/__init__.py new file mode 100644 index 0000000..a3570da --- /dev/null +++ b/storage/__init__.py @@ -0,0 +1 @@ +from storage.FileSystem import FSStorage diff --git a/storage/base.py b/storage/base.py new file mode 100644 index 0000000..def9de3 --- /dev/null +++ b/storage/base.py @@ -0,0 +1,107 @@ +class Storage: + """Basic class for storage interface + + When implementing function be precautionous to forbidden going outside restricted storage zone (storage/modulename + for example). + + All path are on unix format (`/folder1/folder2/file`) + """ + + def __init__(self): + pass + + async def access(self, path): + """ + Return if path is accessible + :param path: Path to check + :return: Boolean + """ + pass + + async def chdir(self, path): + """ + Change working directory for this storage module + :param path: Path to go + :return: New path + """ + pass + + async def getcwd(self): + """ + Get current working directory + :return: Current working directory + """ + pass + + async def listdir(self, path="."): + """ + List all files and folders in directory `path` + :param path: Folder to list + :return: List of filename + """ + pass + + async def mkdir(self, path): + """ + Create directory `path` + :param path: directory to create + :return: Path to new directory + """ + pass + + async def makedirs(self, path, exist_ok=False): + """ + Create directory `path` + :param path: directory to create + :return: Path to new directory + """ + pass + + async def remove(self, path): + """ + Remove file `path` + :param path: File to remove + :return: None + """ + pass + + async def rename(self, src, dst): + """ + Rename file `src` to `dst` + :param src: Source file + :param dst: Destination file + :return: New path + """ + pass + + async def rmdir(self, path): + """ + Remove dir `path` + :param path: Directory to remove + :return: None + """ + pass + + async def sync(self): + """ + Force writing everything on disk (or storage support) + :return: None + """ + pass + + async def open(self, path, mode): + """ + Return a file object + :param path: Path of file + :param mode: mode to open file + :return: file object + """ + pass + + async def exists(self, path): + """ + Return if a file or a folder exists + :param path: Path to test + :return: True if file exists + """ + pass diff --git a/storage/path.py b/storage/path.py new file mode 100644 index 0000000..ccf5837 --- /dev/null +++ b/storage/path.py @@ -0,0 +1,7 @@ +def join(*args): + """ + Join list of path + :param args: List of path + :return: Joined path + """ + return "/".join(args)