cacassetout #1

Manually merged
fomys merged 15 commits from cacassetout into master 2020-04-24 23:41:36 +02:00
80 changed files with 830 additions and 829 deletions
Showing only changes of commit 0ed718d6d4 - Show all commits

View File

@ -1,11 +0,0 @@
{
"version":"0.1.0",
"type": "python",
"dependencies": {
},
"bot_version": {
"min": "0.1.0",
"max": "0.1.0"
}
}

View File

@ -1,11 +0,0 @@
{
"version":"0.1.0",
"type": "python",
"dependencies": {
},
"bot_version": {
"min": "0.1.0",
"max": "0.1.0"
}
}

View File

@ -1,11 +0,0 @@
{
"version":"0.1.0",
"type": "python",
"dependencies": {
},
"bot_version": {
"min": "0.1.0",
"max": "0.1.0"
}
}

View File

@ -1,11 +0,0 @@
{
"version":"0.1.0",
"type": "python",
"dependencies": {
},
"bot_version": {
"min": "0.1.0",
"max": "0.1.0"
}
}

View File

@ -1,11 +0,0 @@
{
"version":"0.1.0",
"type": "python",
"dependencies": {
},
"bot_version": {
"min": "0.1.0",
"max": "0.1.0"
}
}

View File

@ -1,11 +0,0 @@
{
"version":"0.1.0",
"type": "python",
"dependencies": {
},
"bot_version": {
"min": "0.1.0",
"max": "0.1.0"
}
}

View File

@ -1,11 +0,0 @@
{
"version":"0.1.0",
"type": "python",
"dependencies": {
},
"bot_version": {
"min": "0.1.0",
"max": "0.1.0"
}
}

View File

@ -1,11 +0,0 @@
{
"version":"0.1.0",
"type": "python",
"dependencies": {
},
"bot_version": {
"min": "0.1.0",
"max": "0.1.0"
}
}

View File

@ -1,28 +1,28 @@
class LBIException(Exception):
"""
Base exception class for LBI
All other exceptions are subclasses
"""
pass
class ModuleException(LBIException):
"""
Base exception class for all module errors
"""
pass
class ModuleNotInstalled(ModuleException):
"""
Raised when a module is not found in module directory
"""
pass
class IncompatibleModule(ModuleException):
"""
Raised when a module is not compatible with bot version
"""
pass
class LBIException(Exception):
"""
Base exception class for LBI
All other exceptions are subclasses
"""
pass
class ModuleException(LBIException):
"""
Base exception class for all module errors
"""
pass
class ModuleNotInstalled(ModuleException):
"""
Raised when a module is not found in module directory
"""
pass
class IncompatibleModule(ModuleException):
"""
Raised when a module is not compatible with bot version
"""
pass

View File

@ -1,499 +1,499 @@
#!/usr/bin/python3
from __future__ import annotations
import asyncio
import importlib
import json
import locale
import logging
import logging.config
import os
import sys
import traceback
from typing import Dict
import discord
import humanize
from packaging.version import Version
from config import Config, config_types
from config.config_types import factory
from errors import IncompatibleModule
from modules.base import base_supported_type
__version__ = "0.1.0"
class Module:
name: str
def __init__(self, name: str):
"""
Init module
:param name: Module name
:type name: str
"""
self.name = name
MODULES.update({self.name: self})
@property
def type(self) -> str:
"""
Return module type. It can be python or lua
:return: Module type
:rtype: str
"""
if not os.path.exists(os.path.join("modules", self.name, "version.json")):
return ""
with open(os.path.join("modules", self.name, "version.json")) as file:
versions = json.load(file)
return versions["type"]
@property
def exists(self) -> bool:
"""
Check if module exists
:return: True if module is present in modules folders
:rtype: bool
"""
if not os.path.isdir(os.path.join("modules", self.name)):
return False
return True
@property
def complete(self) -> bool:
"""
Check if module is complete
:return: True if module is compatible
:rtype: Boolean
"""
# Check if version.json exists
if not os.path.exists(os.path.join("modules", self.name, "version.json")):
return False
with open(os.path.join("modules", self.name, "version.json")) as file:
versions = json.load(file)
if "version" not in versions.keys():
return False
if "dependencies" not in versions.keys():
return False
if "bot_version" not in versions.keys():
return False
if "type" not in versions.keys():
return False
if versions["type"] not in base_supported_type:
return False
return True
@property
def version(self) -> Version:
"""
Returns module version
:return: current module version
:rtype: Version
"""
with open(os.path.join("modules", self.name, "version.json")) as file:
versions = json.load(file)
return Version(versions["version"])
@property
def bot_version(self) -> dict:
"""
returns the min and max version of the bot that is compatible with the module
:return: Min and max version for bot
:rtype: dict
:raises IncompatibleModule: If bot_version is not properly formated (there must be min and max keys)
"""
with open(os.path.join("modules", self.name, "version.json")) as file:
versions = json.load(file)
try:
return {"min": Version(versions["bot_version"]["min"]),
"max": Version(versions["bot_version"]["max"])}
except KeyError:
raise IncompatibleModule(f"Module {self.name} is not compatible with bot (version.json does not "
f"contain bot_version.max or bot_version.min item)")
@property
def dependencies(self) -> dict:
"""
return list of dependencies version
:raise IncompatibleModule: If bot_version is not properly formated (there must be min and max keys for each dependencies)
:return: list of dependencies version
:rtype: dict
"""
with open(os.path.join("modules", self.name, "version.json")) as file:
versions = json.load(file)
try:
deps = {}
for name, dep in versions["dependencies"].items():
dep_ver = {"min": Version(dep["min"]),
"max": Version(dep["max"])}
deps.update({name: dep_ver})
return deps
except KeyError:
raise IncompatibleModule(f"Module {self.name} is not compatible with bot (version.json does not "
f"contain dependencies.modulename.max or dependencies.modulename.min item)")
@property
def compatible(self) -> bool:
"""
Check if module is compatible with current installation
:return: True if all dependencies are okays
:rtype: bool
"""
# Check bot version
bot_ver = Version(__version__)
if bot_ver < self.bot_version["min"]:
return False
if bot_ver > self.bot_version["max"]:
return False
for name, dep in self.dependencies.items():
if name not in MODULES.keys():
Module(name)
if MODULES[name].version < dep["min"]:
return False
if MODULES[name].version > dep["max"]:
return False
return True
MODULES: Dict[str, Module] = {}
def setup_logging(default_path='config/log_config.json', default_level=logging.INFO, env_key='LBI_LOG_CONFIG'):
"""Setup logging configuration
"""
path = default_path
value = os.getenv(env_key, None)
if value:
path = value
if os.path.exists(path):
with open(path, 'rt') as f:
config = json.load(f)
logging.config.dictConfig(config)
else:
logging.basicConfig(level=default_level)
def modules_edit(func):
def wrapper(self, *args, **kwargs):
if self.reloading:
return func(self, *args, **kwargs)
else:
self.reloading = True
a = func(self, *args, **kwargs)
self.reloading = False
return a
return wrapper
def event(func):
def wrapper(self, *args, **kwargs):
if self.reloading:
return lambda: None
else:
return func(self, *args, **kwargs)
return wrapper
"""def async_event(func):
async def wrapper(self, *args, **kwargs):
if self.reloading:
return lambda: None
else:
return func(self, *args, **kwargs)
return wrapper"""
setup_logging()
log_discord = logging.getLogger('discord_types')
log_LBI = logging.getLogger('LBI')
log_communication = logging.getLogger('communication')
def load_modules_info():
for mod in os.listdir("modules"):
Module(mod)
class LBI(discord.Client):
by_id: ClientById
base_path = "data"
debug = log_LBI.debug
info = log_LBI.info
warning = log_LBI.warning
warn = warning
error = log_LBI.error
critical = log_LBI.critical
def __init__(self, config: Config = None, *args, **kwargs):
super().__init__(*args, **kwargs)
if config is None:
config = Config(path="data/config.toml", client=self)
self.reloading = False
self.by_id = ClientById(self)
self.ready = False
# Content: {"module_name": {"module": imported module, "class": initialized class}}
self.modules = {}
self.config = config
self.config.register("modules", factory(config_types.List, factory(config_types.Str)))
self.config.register("prefix", factory(config_types.Str))
self.config.register("admin_roles", factory(config_types.List, factory(config_types.discord_types.Role, self)))
self.config.register("admin_users", factory(config_types.List, factory(config_types.discord_types.User, self)))
self.config.register("main_guild", factory(config_types.discord_types.Guild, self))
self.config.register("locale", factory(config_types.Str))
self.config.set({
"modules": ["modules", "errors"],
"prefix": "%",
"admin_roles": [],
"admin_users": [],
"main_guild": None,
"locale": "fr_FR.UTF8",
})
locale.setlocale(locale.LC_TIME, self.config['locale'])
humanize.i18n.activate(self.config['locale'])
self.load_modules()
@modules_edit
def load_modules(self):
self.info("Starts to load modules...")
e = {}
for module in self.config["modules"]:
e.update({module: self.load_module(module)})
self.info("Finished to load all modules.")
return e
@modules_edit
def load_module(self, module):
"""
Status codes:
- 0: Module loaded
- 1: Module not in modules folder
- 2: Module incomplete
- 3: Module incompatible
:param module: Module name
:return: Status code
"""
# Check module compatibility
load_modules_info()
if not MODULES.get(module):
return 1
if not MODULES[module].exists:
return 1
if not MODULES[module].complete:
return 2
if not MODULES[module].compatible:
return 3
deps = MODULES[module].dependencies
for dep in deps.keys():
if dep not in self.modules.keys():
if dep != "base":
self.load_module(dep)
if MODULES[module].type == "python":
try:
self.info("Start loading module {module}...".format(module=module))
imported = importlib.import_module('modules.' + module)
importlib.reload(imported)
initialized_class = imported.MainClass(self)
self.modules.update({module: {"imported": imported, "initialized_class": initialized_class}})
self.info("Module {module} successfully imported.".format(module=module))
initialized_class.dispatch("load")
if module not in self.config["modules"]:
self.config["modules"].append(module)
self.config.save()
except AttributeError as e:
self.error("Module {module} doesn't have MainClass.".format(module=module))
raise e
return 0
elif MODULES[module].type == "lua":
self.info(f"Start loading module {module}...")
imported = importlib.import_module('modules.base.BaseLua')
importlib.reload(imported)
initialized_class = imported.BaseClassLua(self, path=f"modules/{module}/main")
self.modules.update({module: {"imported": imported, "initialized_class": initialized_class}})
self.info(f"Module {module} successfully imported.")
initialized_class.dispatch("load")
if module not in self.config["modules"]:
self.config["modules"].append(module)
self.config.save()
return 0
@modules_edit
def unload_module(self, module):
self.info("Start unload module {module}...".format(module=module))
try:
if module in self.config["modules"]:
self.config["modules"].remove(module)
self.config.save()
self.unload_all()
self.load_modules()
except KeyError as e:
self.error("Module {module} not loaded.").format(module=module)
return e
@modules_edit
def reload(self):
del self.modules
self.load_modules()
@modules_edit
def unload_all(self):
del self.modules
self.modules = {}
@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)
async def on_error(self, event_method, *args, **kwargs):
"""Function called when error happend"""
# This event is special because it is call directly
self.error(traceback.format_exc())
for module in self.modules.values():
await module["initialized_class"].on_error(event_method, *args, **kwargs)
class ClientById:
client: LBI
def __init__(self, client_):
self.client = client_
async def fetch_message(self, id_, *args, **kwargs):
"""Find a message by id
:param id_: Id of message to find
:type id_: int
:raises discord_types.NotFound: This exception is raised when a message is not found (or not accessible by bot)
:rtype: discord.Message
:return: discord_types.Message instance if message is found.
"""
msg = None
for channel in self.client.get_all_channels():
try:
return await channel.fetch_message(id_, *args, **kwargs)
except discord.NotFound:
continue
if msg is None:
raise discord.NotFound(None, "Message not found")
async def edit_message(self, id, *args, **kwargs):
"""
Edit message by id
:param id: Id of the message to edit
:type id: int"""
message = await self.fetch_message(id)
return await message.edit(**kwargs)
async def remove_reaction(self, id_message, *args, **kwargs):
"""Remove reaction from message by id
:param id_message: Id of message
:type id_message: int"""
message = await self.fetch_message(id_message)
return await message.remove_reaction(*args, **kwargs)
async def send_message(self, id_, *args, **kwargs):
"""Send message by channel id
:param id_: Id of channel where to send message
:type id_: int"""
channel = self.client.get_channel(id_)
return channel.send(*args, **kwargs)
def get_role(self, id_=None, name=None, check=None, guilds=None):
"""Get role by id or with custom check"""
if guilds is None:
guilds = self.client.guilds
if id_ is not None:
for guild in guilds:
role = discord.utils.get(guild.roles, id=id_)
if role:
return role
if name is not None:
for guild in guilds:
role = discord.utils.get(guild.roles, name=name)
if role:
return role
if check is not None:
role = None
for guild in guilds:
for role_ in guild.roles:
if check(role_):
role = role_
break
if role is not None:
break
return role
return None
class Communication(asyncio.Protocol):
debug = log_communication.debug
info = log_communication.info
warning = log_communication.warning
error = log_communication.error
critical = log_communication.critical
name = "Communication"
def __init__(self, client):
self.client = client
self.transport = None
def connection_made(self, transport):
print('%s: connection made' % self.name)
self.transport = transport
def data_received(self, data):
print('%s: data received: %r' % (self.name, data))
def eof_received(self):
pass
def connection_lost(self, exc):
print('%s: connection lost: %s' % (self.name, exc))
if __name__ == "__main__":
client1 = LBI(max_messages=500000)
communication = Communication(client1)
async def start_bot():
await client1.start(os.environ.get("DISCORD_TOKEN"))
print(os.path.join("/tmp", os.path.dirname(os.path.realpath(__file__))) + ".sock")
loop = asyncio.get_event_loop()
t = loop.create_unix_server(Communication,
path=os.path.join("/tmp", os.path.dirname(os.path.realpath(__file__)) + ".sock"))
if not sys.platform == "win32":
loop.run_until_complete(t)
loop.create_task(start_bot())
loop.run_forever()
#!/usr/bin/python3
from __future__ import annotations
import asyncio
import importlib
import json
import locale
import logging
import logging.config
import os
import sys
import traceback
from typing import Dict
import discord
import humanize
from packaging.version import Version
from config import Config, config_types
from config.config_types import factory
from errors import IncompatibleModule
from modules.base import base_supported_type
__version__ = "0.1.0"
class Module:
name: str
def __init__(self, name: str):
"""
Init module
:param name: Module name
:type name: str
"""
self.name = name
MODULES.update({self.name: self})
@property
def type(self) -> str:
"""
Return module type. It can be python or lua
:return: Module type
:rtype: str
"""
if not os.path.exists(os.path.join("modules", self.name, "version.json")):
return ""
with open(os.path.join("modules", self.name, "version.json")) as file:
versions = json.load(file)
return versions["type"]
@property
def exists(self) -> bool:
"""
Check if module exists
:return: True if module is present in modules folders
:rtype: bool
"""
if not os.path.isdir(os.path.join("modules", self.name)):
return False
return True
@property
def complete(self) -> bool:
"""
Check if module is complete
:return: True if module is compatible
:rtype: Boolean
"""
# Check if version.json exists
if not os.path.exists(os.path.join("modules", self.name, "version.json")):
return False
with open(os.path.join("modules", self.name, "version.json")) as file:
versions = json.load(file)
if "version" not in versions.keys():
return False
if "dependencies" not in versions.keys():
return False
if "bot_version" not in versions.keys():
return False
if "type" not in versions.keys():
return False
if versions["type"] not in base_supported_type:
return False
return True
@property
def version(self) -> Version:
"""
Returns module version
:return: current module version
:rtype: Version
"""
with open(os.path.join("modules", self.name, "version.json")) as file:
versions = json.load(file)
return Version(versions["version"])
@property
def bot_version(self) -> dict:
"""
returns the min and max version of the bot that is compatible with the module
:return: Min and max version for bot
:rtype: dict
:raises IncompatibleModule: If bot_version is not properly formated (there must be min and max keys)
"""
with open(os.path.join("modules", self.name, "version.json")) as file:
versions = json.load(file)
try:
return {"min": Version(versions["bot_version"]["min"]),
"max": Version(versions["bot_version"]["max"])}
except KeyError:
raise IncompatibleModule(f"Module {self.name} is not compatible with bot (version.json does not "
f"contain bot_version.max or bot_version.min item)")
@property
def dependencies(self) -> dict:
"""
return list of dependencies version
:raise IncompatibleModule: If bot_version is not properly formated (there must be min and max keys for each dependencies)
:return: list of dependencies version
:rtype: dict
"""
with open(os.path.join("modules", self.name, "version.json")) as file:
versions = json.load(file)
try:
deps = {}
for name, dep in versions["dependencies"].items():
dep_ver = {"min": Version(dep["min"]),
"max": Version(dep["max"])}
deps.update({name: dep_ver})
return deps
except KeyError:
raise IncompatibleModule(f"Module {self.name} is not compatible with bot (version.json does not "
f"contain dependencies.modulename.max or dependencies.modulename.min item)")
@property
def compatible(self) -> bool:
"""
Check if module is compatible with current installation
:return: True if all dependencies are okays
:rtype: bool
"""
# Check bot version
bot_ver = Version(__version__)
if bot_ver < self.bot_version["min"]:
return False
if bot_ver > self.bot_version["max"]:
return False
for name, dep in self.dependencies.items():
if name not in MODULES.keys():
Module(name)
if MODULES[name].version < dep["min"]:
return False
if MODULES[name].version > dep["max"]:
return False
return True
MODULES: Dict[str, Module] = {}
def setup_logging(default_path='config/log_config.json', default_level=logging.INFO, env_key='LBI_LOG_CONFIG'):
"""Setup logging configuration
"""
path = default_path
value = os.getenv(env_key, None)
if value:
path = value
if os.path.exists(path):
with open(path, 'rt') as f:
config = json.load(f)
logging.config.dictConfig(config)
else:
logging.basicConfig(level=default_level)
def modules_edit(func):
def wrapper(self, *args, **kwargs):
if self.reloading:
return func(self, *args, **kwargs)
else:
self.reloading = True
a = func(self, *args, **kwargs)
self.reloading = False
return a
return wrapper
def event(func):
def wrapper(self, *args, **kwargs):
if self.reloading:
return lambda: None
else:
return func(self, *args, **kwargs)
return wrapper
"""def async_event(func):
async def wrapper(self, *args, **kwargs):
if self.reloading:
return lambda: None
else:
return func(self, *args, **kwargs)
return wrapper"""
setup_logging()
log_discord = logging.getLogger('discord_types')
log_LBI = logging.getLogger('LBI')
log_communication = logging.getLogger('communication')
def load_modules_info():
for mod in os.listdir("modules"):
Module(mod)
class LBI(discord.Client):
by_id: ClientById
base_path = "data"
debug = log_LBI.debug
info = log_LBI.info
warning = log_LBI.warning
warn = warning
error = log_LBI.error
critical = log_LBI.critical
def __init__(self, config: Config = None, *args, **kwargs):
super().__init__(*args, **kwargs)
if config is None:
config = Config(path="data/config.toml", client=self)
self.reloading = False
self.by_id = ClientById(self)
self.ready = False
# Content: {"module_name": {"module": imported module, "class": initialized class}}
self.modules = {}
self.config = config
self.config.register("modules", factory(config_types.List, factory(config_types.Str)))
self.config.register("prefix", factory(config_types.Str))
self.config.register("admin_roles", factory(config_types.List, factory(config_types.discord_types.Role, self)))
self.config.register("admin_users", factory(config_types.List, factory(config_types.discord_types.User, self)))
self.config.register("main_guild", factory(config_types.discord_types.Guild, self))
self.config.register("locale", factory(config_types.Str))
self.config.set({
"modules": ["modules", "errors"],
"prefix": "%",
"admin_roles": [],
"admin_users": [],
"main_guild": None,
"locale": "fr_FR.UTF8",
})
locale.setlocale(locale.LC_TIME, self.config['locale'])
humanize.i18n.activate(self.config['locale'])
self.load_modules()
@modules_edit
def load_modules(self):
self.info("Starts to load modules...")
e = {}
for module in self.config["modules"]:
e.update({module: self.load_module(module)})
self.info("Finished to load all modules.")
return e
@modules_edit
def load_module(self, module):
"""
Status codes:
- 0: Module loaded
- 1: Module not in modules folder
- 2: Module incomplete
- 3: Module incompatible
:param module: Module name
:return: Status code
"""
# Check module compatibility
load_modules_info()
if not MODULES.get(module):
return 1
if not MODULES[module].exists:
return 1
if not MODULES[module].complete:
return 2
if not MODULES[module].compatible:
return 3
deps = MODULES[module].dependencies
for dep in deps.keys():
if dep not in self.modules.keys():
if dep != "base":
self.load_module(dep)
if MODULES[module].type == "python":
try:
self.info("Start loading module {module}...".format(module=module))
imported = importlib.import_module('modules.' + module)
importlib.reload(imported)
initialized_class = imported.MainClass(self)
self.modules.update({module: {"imported": imported, "initialized_class": initialized_class}})
self.info("Module {module} successfully imported.".format(module=module))
initialized_class.dispatch("load")
if module not in self.config["modules"]:
self.config["modules"].append(module)
self.config.save()
except AttributeError as e:
self.error("Module {module} doesn't have MainClass.".format(module=module))
raise e
return 0
elif MODULES[module].type == "lua":
self.info(f"Start loading module {module}...")
imported = importlib.import_module('modules.base.BaseLua')
importlib.reload(imported)
initialized_class = imported.BaseClassLua(self, path=f"modules/{module}/main")
self.modules.update({module: {"imported": imported, "initialized_class": initialized_class}})
self.info(f"Module {module} successfully imported.")
initialized_class.dispatch("load")
if module not in self.config["modules"]:
self.config["modules"].append(module)
self.config.save()
return 0
@modules_edit
def unload_module(self, module):
self.info("Start unload module {module}...".format(module=module))
try:
if module in self.config["modules"]:
self.config["modules"].remove(module)
self.config.save()
self.unload_all()
self.load_modules()
except KeyError as e:
self.error("Module {module} not loaded.").format(module=module)
return e
@modules_edit
def reload(self):
del self.modules
self.load_modules()
@modules_edit
def unload_all(self):
del self.modules
self.modules = {}
@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)
async def on_error(self, event_method, *args, **kwargs):
"""Function called when error happend"""
# This event is special because it is call directly
self.error(traceback.format_exc())
for module in self.modules.values():
await module["initialized_class"].on_error(event_method, *args, **kwargs)
class ClientById:
client: LBI
def __init__(self, client_):
self.client = client_
async def fetch_message(self, id_, *args, **kwargs):
"""Find a message by id
:param id_: Id of message to find
:type id_: int
:raises discord_types.NotFound: This exception is raised when a message is not found (or not accessible by bot)
:rtype: discord.Message
:return: discord_types.Message instance if message is found.
"""
msg = None
for channel in self.client.get_all_channels():
try:
return await channel.fetch_message(id_, *args, **kwargs)
except discord.NotFound:
continue
if msg is None:
raise discord.NotFound(None, "Message not found")
async def edit_message(self, id, *args, **kwargs):
"""
Edit message by id
:param id: Id of the message to edit
:type id: int"""
message = await self.fetch_message(id)
return await message.edit(**kwargs)
async def remove_reaction(self, id_message, *args, **kwargs):
"""Remove reaction from message by id
:param id_message: Id of message
:type id_message: int"""
message = await self.fetch_message(id_message)
return await message.remove_reaction(*args, **kwargs)
async def send_message(self, id_, *args, **kwargs):
"""Send message by channel id
:param id_: Id of channel where to send message
:type id_: int"""
channel = self.client.get_channel(id_)
return channel.send(*args, **kwargs)
def get_role(self, id_=None, name=None, check=None, guilds=None):
"""Get role by id or with custom check"""
if guilds is None:
guilds = self.client.guilds
if id_ is not None:
for guild in guilds:
role = discord.utils.get(guild.roles, id=id_)
if role:
return role
if name is not None:
for guild in guilds:
role = discord.utils.get(guild.roles, name=name)
if role:
return role
if check is not None:
role = None
for guild in guilds:
for role_ in guild.roles:
if check(role_):
role = role_
break
if role is not None:
break
return role
return None
class Communication(asyncio.Protocol):
debug = log_communication.debug
info = log_communication.info
warning = log_communication.warning
error = log_communication.error
critical = log_communication.critical
name = "Communication"
def __init__(self, client):
self.client = client
self.transport = None
def connection_made(self, transport):
print('%s: connection made' % self.name)
self.transport = transport
def data_received(self, data):
print('%s: data received: %r' % (self.name, data))
def eof_received(self):
pass
def connection_lost(self, exc):
print('%s: connection lost: %s' % (self.name, exc))
if __name__ == "__main__":
client1 = LBI(max_messages=500000)
communication = Communication(client1)
async def start_bot():
await client1.start(os.environ.get("DISCORD_TOKEN"))
print(os.path.join("/tmp", os.path.dirname(os.path.realpath(__file__))) + ".sock")
loop = asyncio.get_event_loop()
t = loop.create_unix_server(Communication,
path=os.path.join("/tmp", os.path.dirname(os.path.realpath(__file__)) + ".sock"))
if not sys.platform == "win32":
loop.run_until_complete(t)
loop.create_task(start_bot())
loop.run_forever()

View File

View File

@ -1,11 +1,11 @@
{
"version":"0.1.0",
"type": "python",
"dependencies": {
},
"bot_version": {
"min": "0.1.0",
"max": "0.1.0"
}
{
"version":"0.1.0",
"type": "python",
"dependencies": {
},
"bot_version": {
"min": "0.1.0",
"max": "0.1.0"
}
}

View File

@ -1,3 +1,3 @@
from .BasePython import BaseClassPython
from .BaseLua import BaseClassLua
from .BasePython import BaseClassPython
from .BaseLua import BaseClassLua
base_supported_type = ["python", "lua"]

View File

@ -5,7 +5,8 @@ from typing import List, Union, Optional
import discord
from config import Config, config_types
from config import Config
from config import config_types
from config.config_types import factory
from storage import Objects
from utils import emojis
@ -35,9 +36,9 @@ class BaseClass:
self.config.register("color", factory(config_types.Color))
self.config.register("auth_everyone", factory(config_types.Bool))
self.config.register("authorized_roles",
factory(config_types.List, factory(config_types.discord_types.Role, client)))
factory(config_types.List, factory(config.config_types.discord_types.Role, client)))
self.config.register("authorized_users",
factory(config_types.List, factory(config_types.discord_types.User, client)))
factory(config_types.List, factory(config.config_types.discord_types.User, client)))
self.config.register("command_text", factory(config_types.Str))
self.config.set({"help_active": True,
"color": 0x000000,

View File

@ -4,7 +4,7 @@ import asyncio
import discord
import lupa
from modules.base.Base import BaseClass
from modules import BaseClass
class BaseClassLua(BaseClass):

View File

@ -1,6 +1,6 @@
"""Base class for module, never use directly !!!"""
from modules.base.Base import BaseClass
from .Base import BaseClass
class BaseClassPython(BaseClass):

View File

@ -1,11 +1,11 @@
{
"version":"0.1.0",
"type": "python",
"dependencies": {
},
"bot_version": {
"min": "0.1.0",
"max": "0.1.0"
}
{
"version":"0.1.0",
"type": "python",
"dependencies": {
},
"bot_version": {
"min": "0.1.0",
"max": "0.1.0"
}
}

View File

@ -1,11 +1,11 @@
{
"version":"0.1.0",
"type": "python",
"dependencies": {
},
"bot_version": {
"min": "0.1.0",
"max": "0.1.0"
}
{
"version":"0.1.0",
"type": "python",
"dependencies": {
},
"bot_version": {
"min": "0.1.0",
"max": "0.1.0"
}
}

View File

@ -1,14 +1,14 @@
{
"version": "0.1.0",
"type": "python",
"dependencies": {
"base": {
"min": "0.1.0",
"max": "0.1.0"
}
},
"bot_version": {
"min": "0.1.0",
"max": "0.1.0"
}
{
"version": "0.1.0",
"type": "python",
"dependencies": {
"base": {
"min": "0.1.0",
"max": "0.1.0"
}
},
"bot_version": {
"min": "0.1.0",
"max": "0.1.0"
}
}

View File

@ -1,11 +1,11 @@
{
"version":"0.1.0",
"type": "python",
"dependencies": {
},
"bot_version": {
"min": "0.1.0",
"max": "0.1.0"
}
{
"version":"0.1.0",
"type": "python",
"dependencies": {
},
"bot_version": {
"min": "0.1.0",
"max": "0.1.0"
}
}

View File

@ -1,141 +1,141 @@
import os
import discord
from aiohttp import ClientConnectorError
from modules.base import BaseClassPython
from modules.modules.api import Api
class MainClass(BaseClassPython):
name = "modules"
help = {
"description": "Manage bot modules.",
"commands": {
"`{prefix}{command} list`": "List of available modules.",
"`{prefix}{command} enable <module>`": "Enable module `<module>`.",
"`{prefix}{command} disable <module>`": "Disable module `<module>`.",
"`{prefix}{command} reload <module>`": "Reload module `<module>`",
"`{prefix}{command} web_list`": "List all available modules from repository",
# "`{prefix}{command} web_source`": "List all source repositories",
# "`{prefix}{command} web_source remove <url>`": "Remove url from repository list",
# "`{prefix}{command} web_source add <url>`": "Add url to repository list",
}
}
def __init__(self, client):
super().__init__(client)
os.makedirs("modules", exist_ok=True)
self.api = Api()
@staticmethod
def get_all_modules():
all_items = os.listdir("modules")
modules = []
for item in all_items:
if item not in ["__init__.py", "base", "__pycache__"]:
if os.path.isfile(os.path.join("modules", item)):
modules.append(item[:-3])
else:
modules.append(item)
return set(modules)
async def com_enable(self, message, args, kwargs):
args = args[1:]
if len(args) == 0:
await message.channel.send("You must specify at least one module.")
return
if len(args) == 1 and args[0] == "*":
for module in self.get_all_modules():
e = self.client.load_module(module)
if e:
await message.channel.send("An error occurred during the loading of the module {module}."
.format(module=module))
await self.com_list(message, args, kwargs)
return
for arg in args:
e = self.client.load_module(arg)
if e == 1:
await message.channel.send(f"Module {arg} not exists.")
if e == 2:
await message.channel.send(f"Module {arg} is incompatible.")
elif e:
await message.channel.send(f"An error occurred during the loading of the module {arg}: {e}.")
await self.com_list(message, args, kwargs)
async def com_reload(self, message, args, kwargs):
args = args[1:]
if len(args) == 0:
await message.channel.send("You must specify at least one module.")
return
if len(args) == 1 and args[0] == "*":
for module in self.get_all_modules():
e = self.client.unload_module(module)
if e:
await message.channel.send(f"An error occurred during the unloading of the module {module}.")
e = self.client.load_module(module)
if e:
await message.channel.send(f"An error occurred during the loading of the module {module}.")
await self.com_list(message, args, kwargs)
return
for arg in args:
e = self.client.unload_module(arg)
if e:
await message.channel.send(f"An error occurred during the unloading of the module {arg}.")
e = self.client.load_module(arg)
if e:
await message.channel.send(f"An error occurred during the loading of the module {arg}.")
await self.com_list(message, [], [])
async def com_disable(self, message, args, kwargs):
args = args[1:]
if len(args) == 0:
await message.channel.send("You must specify at least one module.")
return
if len(args) == 1 and args[0] == "*":
for module in self.get_all_modules():
e = self.client.unload_module(module)
if e:
await message.channel.send(f"An error occurred during the loading of the module {module}.")
await self.com_list(message, args, kwargs)
return
for arg in args:
e = self.client.unload_module(arg)
if e:
await message.channel.send(f"An error occurred during the loading of the module {arg}: {e}.")
await self.com_list(message, [], [])
async def com_list(self, message, args, kwargs):
list_files = self.get_all_modules()
activated = set(self.client.config["modules"])
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{activated}{deactivated}```".format(
activated=activated_string,
deactivated=deactivated_string)
)
await message.channel.send(embed=embed)
async def com_web_list(self, message, args, kwargs):
try:
modules = await self.api.list()
except ClientConnectorError:
await message.channel.send("Connection impossible au serveur.")
return
text = ""
for module, versions in modules.items():
text += module + " - " + ", ".join(versions)
await message.channel.send(text)
async def com_web_dl(self, message, args, kwargs):
try:
await self.api.download(args[1], args[2])
except ClientConnectorError:
await message.channel.send("Connection impossible au serveur.")
import os
import discord
from aiohttp import ClientConnectorError
from modules.base import BaseClassPython
from modules.modules.api import Api
class MainClass(BaseClassPython):
name = "modules"
help = {
"description": "Manage bot modules.",
"commands": {
"`{prefix}{command} list`": "List of available modules.",
"`{prefix}{command} enable <module>`": "Enable module `<module>`.",
"`{prefix}{command} disable <module>`": "Disable module `<module>`.",
"`{prefix}{command} reload <module>`": "Reload module `<module>`",
"`{prefix}{command} web_list`": "List all available modules from repository",
# "`{prefix}{command} web_source`": "List all source repositories",
# "`{prefix}{command} web_source remove <url>`": "Remove url from repository list",
# "`{prefix}{command} web_source add <url>`": "Add url to repository list",
}
}
def __init__(self, client):
super().__init__(client)
os.makedirs("modules", exist_ok=True)
self.api = Api()
@staticmethod
def get_all_modules():
all_items = os.listdir("modules")
modules = []
for item in all_items:
if item not in ["__init__.py", "base", "__pycache__"]:
if os.path.isfile(os.path.join("modules", item)):
modules.append(item[:-3])
else:
modules.append(item)
return set(modules)
async def com_enable(self, message, args, kwargs):
args = args[1:]
if len(args) == 0:
await message.channel.send("You must specify at least one module.")
return
if len(args) == 1 and args[0] == "*":
for module in self.get_all_modules():
e = self.client.load_module(module)
if e:
await message.channel.send("An error occurred during the loading of the module {module}."
.format(module=module))
await self.com_list(message, args, kwargs)
return
for arg in args:
e = self.client.load_module(arg)
if e == 1:
await message.channel.send(f"Module {arg} not exists.")
if e == 2:
await message.channel.send(f"Module {arg} is incompatible.")
elif e:
await message.channel.send(f"An error occurred during the loading of the module {arg}: {e}.")
await self.com_list(message, args, kwargs)
async def com_reload(self, message, args, kwargs):
args = args[1:]
if len(args) == 0:
await message.channel.send("You must specify at least one module.")
return
if len(args) == 1 and args[0] == "*":
for module in self.get_all_modules():
e = self.client.unload_module(module)
if e:
await message.channel.send(f"An error occurred during the unloading of the module {module}.")
e = self.client.load_module(module)
if e:
await message.channel.send(f"An error occurred during the loading of the module {module}.")
await self.com_list(message, args, kwargs)
return
for arg in args:
e = self.client.unload_module(arg)
if e:
await message.channel.send(f"An error occurred during the unloading of the module {arg}.")
e = self.client.load_module(arg)
if e:
await message.channel.send(f"An error occurred during the loading of the module {arg}.")
await self.com_list(message, [], [])
async def com_disable(self, message, args, kwargs):
args = args[1:]
if len(args) == 0:
await message.channel.send("You must specify at least one module.")
return
if len(args) == 1 and args[0] == "*":
for module in self.get_all_modules():
e = self.client.unload_module(module)
if e:
await message.channel.send(f"An error occurred during the loading of the module {module}.")
await self.com_list(message, args, kwargs)
return
for arg in args:
e = self.client.unload_module(arg)
if e:
await message.channel.send(f"An error occurred during the loading of the module {arg}: {e}.")
await self.com_list(message, [], [])
async def com_list(self, message, args, kwargs):
list_files = self.get_all_modules()
activated = set(self.client.config["modules"])
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{activated}{deactivated}```".format(
activated=activated_string,
deactivated=deactivated_string)
)
await message.channel.send(embed=embed)
async def com_web_list(self, message, args, kwargs):
try:
modules = await self.api.list()
except ClientConnectorError:
await message.channel.send("Connection impossible au serveur.")
return
text = ""
for module, versions in modules.items():
text += module + " - " + ", ".join(versions)
await message.channel.send(text)
async def com_web_dl(self, message, args, kwargs):
try:
await self.api.download(args[1], args[2])
except ClientConnectorError:
await message.channel.send("Connection impossible au serveur.")

View File

@ -1,14 +1,14 @@
{
"version": "0.1.0",
"type": "python",
"dependencies": {
"base": {
"min": "0.1.0",
"max": "0.1.0"
}
},
"bot_version": {
"min": "0.1.0",
"max": "0.1.0"
}
{
"version": "0.1.0",
"type": "python",
"dependencies": {
"base": {
"min": "0.1.0",
"max": "0.1.0"
}
},
"bot_version": {
"min": "0.1.0",
"max": "0.1.0"
}
}

View File

@ -0,0 +1,11 @@
{
"version":"0.1.0",
"type": "python",
"dependencies": {
},
"bot_version": {
"min": "0.1.0",
"max": "0.1.0"
}
}

View File

@ -0,0 +1,11 @@
{
"version":"0.1.0",
"type": "python",
"dependencies": {
},
"bot_version": {
"min": "0.1.0",
"max": "0.1.0"
}
}

View File

@ -0,0 +1,11 @@
{
"version":"0.1.0",
"type": "python",
"dependencies": {
},
"bot_version": {
"min": "0.1.0",
"max": "0.1.0"
}
}

View File

@ -0,0 +1,11 @@
{
"version":"0.1.0",
"type": "python",
"dependencies": {
},
"bot_version": {
"min": "0.1.0",
"max": "0.1.0"
}
}

View File

@ -0,0 +1,11 @@
{
"version":"0.1.0",
"type": "python",
"dependencies": {
},
"bot_version": {
"min": "0.1.0",
"max": "0.1.0"
}
}

View File

@ -0,0 +1,11 @@
{
"version":"0.1.0",
"type": "python",
"dependencies": {
},
"bot_version": {
"min": "0.1.0",
"max": "0.1.0"
}
}

View File

@ -0,0 +1,11 @@
{
"version":"0.1.0",
"type": "python",
"dependencies": {
},
"bot_version": {
"min": "0.1.0",
"max": "0.1.0"
}
}

View File

@ -0,0 +1,11 @@
{
"version":"0.1.0",
"type": "python",
"dependencies": {
},
"bot_version": {
"min": "0.1.0",
"max": "0.1.0"
}
}

0
src/utils/__init__.py Normal file
View File