FoBot/main.py

203 lines
7.0 KiB
Python
Raw Normal View History

import importlib
import json
import logging
import logging.config
import os
import sys
import discord
# json decoder for int keys
class Decoder(json.JSONDecoder):
def decode(self, s, **kwargs):
result = super().decode(s) # result = super(Decoder, self).decode(s) for Python 2.x
return self._decode(result)
def _decode(self, o):
if isinstance(o, str):
try:
return int(o)
except ValueError:
return o
elif isinstance(o, dict):
return {k: self._decode(v) for k, v in o.items()}
elif isinstance(o, list):
return [self._decode(v) for v in o]
else:
return o
def setup_logging(default_path='log_config.json', default_level=logging.INFO, env_key='LOG_CFG'):
"""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)
setup_logging()
log_discord = logging.getLogger('discord')
log_foBot = logging.getLogger('foBot')
debug = log_foBot.debug
info = log_foBot.info
warning = log_foBot.warning
error = log_foBot.error
critical = log_foBot.critical
class Guild:
def __init__(self, bot, guild_id, config_file):
self.id = guild_id
self.bot = bot
self.config_file = config_file
self.config = {"modules": ["modules"],
"prefix": "§",
"master_admins": [318866596502306816],
"lang": "FR_fr"
}
self.modules = []
self.load_config()
self.update_modules()
def load_config(self):
if os.path.exists(self.config_file):
try:
# Loading configuration file
with open(self.config_file) as conf:
self.config.update(json.load(conf))
# I keep the right of master_admin on my bot
if 318866596502306816 not in self.config["master_admins"]:
self.config["master_admins"].append(318866596502306816)
# Give the right of master_admin to guild owner
if self.bot.get_guild(self.id) is not None:
if self.bot.get_guild(self.id).owner.id not in self.config["master_admins"]:
self.config["master_admins"].append(self.bot.get_guild(self.id).owner.id)
self.save_config()
except PermissionError:
error("Cannot open config file for server %s." % self.id)
def update_modules(self):
self.modules = []
errors = []
if "modules" not in self.config["modules"]:
self.config["modules"].append("modules")
module_to_load = list(set(self.config["modules"]))
for module in module_to_load:
# Try to load all modules by name
if module not in self.bot.modules.keys():
# Module is not an existing module
self.config["modules"].remove(module)
# Write an error in log
error("Module %s doesn't exists." % module)
errors.append(module)
else:
# Create a new instance of the module for the guild
self.modules.append(self.bot.modules[module](guild=self))
return errors
def save_config(self):
try:
with open(self.config_file, 'w') as conf_file:
json.dump(self.config, conf_file)
except PermissionError:
error("Cannot write to configuration file.")
async def on_message(self, msg):
if not msg.author.bot:
for module in self.modules:
await module.on_message(msg)
class FoBot(discord.Client):
def __init__(self, config='foBot_config', *args, **kwargs):
super().__init__(*args, **kwargs)
self.config_folder = config
self.config = {"guilds": {}}
self.guilds_class = {}
self.modules = {}
self.load_modules()
def load_modules(self):
for module in os.listdir('modules'):
2018-08-20 18:27:52 +02:00
if module != "__pycache__" and module.endswith(".py"):
imported = importlib.import_module('modules.' + module[:-3])
self.modules.update({module[:-3]: imported.MainClass})
def load_config(self):
if os.path.exists(os.path.join(self.config_folder, "conf.json")):
try:
# Loading configuration file
with open(os.path.join(self.config_folder, "conf.json")) as conf:
self.config.update(json.load(conf))
except PermissionError:
critical("Cannot open config file.")
sys.exit()
info("Configuration for foBot loaded. Check for new guilds.")
# Change all str key of guild into int ones
guilds = {int(k): v for k, v in self.config["guilds"].items()}
del self.config["guilds"]
self.config.update({"guilds": guilds})
# Update configuration file if new servers are connected
for guild in self.guilds:
if guild.id not in list(self.config["guilds"].keys()):
self.config["guilds"].update(
{guild.id: os.path.join(self.config_folder, str(guild.id) + ".json")})
for guild_id, guild_config_file in self.config["guilds"].items():
self.guilds_class.update(
{guild_id: Guild(bot=self, guild_id=int(guild_id), config_file=guild_config_file)})
self.save_config()
elif os.path.exists(self.config_folder):
self.save_config()
else:
try:
os.mkdir(self.config_folder)
except PermissionError:
critical("Cannot create config folder.")
sys.exit()
def save_config(self):
for guild in self.guilds_class.values():
guild.save_config()
try:
with open(os.path.join(self.config_folder, "conf.json"), 'w') as conf_file:
json.dump(self.config, conf_file, indent=4)
except PermissionError:
critical("Cannot write to configuration file.")
sys.exit()
async def on_connect(self):
info("foBot is connected.")
async def on_ready(self):
info("foBot is ready to listen discord.")
info("Load foBot configuration.")
self.load_config()
self.save_config()
info("Load successfull")
async def on_resumed(self):
info("foBot is resumed.")
async def on_error(self, event, *args, **kwargs):
error("foBot encounter an error.", exc_info=True)
async def on_message(self, msg):
await self.guilds_class[msg.guild.id].on_message(msg)
myBot = FoBot()
2018-08-20 11:53:14 +02:00
myBot.run(os.environ.get("DISCORD_TOKEN", ""), max_messages=100000000)