Initial Commit

This commit is contained in:
InValidFire 2021-03-03 21:49:11 -05:00
parent ecdfb090e8
commit f928c6df20
8 changed files with 270 additions and 1 deletions

View file

@ -1,2 +1,3 @@
# discord-bot-template
# Discord Bot Template
This template is used by my Discord Bots to speed up the process of getting started.

0
applog/__init__.py Normal file
View file

40
applog/logging.yaml Normal file
View file

@ -0,0 +1,40 @@
version: 1
disable_existing_loggers: True
formatters:
simple:
format: "%(asctime)s - [%(threadName)s|%(levelname)s] - %(message)s"
handlers:
console:
class: logging.StreamHandler
level: DEBUG
formatter: simple
stream: ext://sys.stdout
info_file_handler:
class: logging.handlers.RotatingFileHandler
level: INFO
formatter: simple
filename: applog/info.log
maxBytes: 10485760 # 10MB
backupCount: 20
encoding: utf8
error_file_handler:
class: logging.handlers.RotatingFileHandler
level: ERROR
formatter: simple
filename: applog/errors.log
maxBytes: 10485760 # 10MB
backupCount: 20
encoding: utf8
loggers:
system:
level: INFO
handlers: [ console, info_file_handler ]
propogate: no
discord:
level: INFO
handlers: [ console, info_file_handler ]
propogate: no
bot:
level: INFO
handlers: [ console, info_file_handler ]
propogate: no

26
applog/utils.py Normal file
View file

@ -0,0 +1,26 @@
"""Original Credit: https://github.com/tiangolo/fastapi/issues/290#issuecomment-500119238"""
import logging.config
import os
import yaml
def read_logging_config(default_path="logging.yaml", env_key="LOG_CFG"):
path = default_path
value = os.getenv(env_key, None)
if value:
path = value
if os.path.exists(path):
with open(path, "rt") as f:
logging_config = yaml.safe_load(f.read())
return logging_config
else:
return None
def setup_logging(logging_config, default_level=logging.INFO):
if logging_config:
logging.config.dictConfig(logging_config)
else:
logging.basicConfig(level=default_level)

34
bot.py Normal file
View file

@ -0,0 +1,34 @@
from applog.utils import read_logging_config, setup_logging
import logging
from discord.ext import commands
import core.common as common
from pathlib import Path
logger = logging.getLogger(__name__)
discord_logger = logging.getLogger('discord')
log_config_dict = read_logging_config("applog/logging.yaml")
setup_logging(log_config_dict)
common.prompt_config("config.json", "Enter repository URL: ", "repo_link")
common.prompt_config("config.json", "Enter bot token: ", "token")
common.prompt_config("config.json", "Enter bot prefix: ", "prefix")
common.prompt_config("config.json", "Enter ServerAPI token: ", "api_token")
config, _ = common.load_config("config.json")
bot = commands.Bot(command_prefix=config['prefix'])
def get_extensions(): # Gets extension list dynamically
extensions = []
for file in Path("cogs").glob("**/*.py"):
extensions.append(str(file).replace("/", ".").replace(".py", ""))
return extensions
for ext in get_extensions():
bot.load_extension(ext)
logger.info("starting bot.")
bot.run(config['token'])

90
cogs/system.py Normal file
View file

@ -0,0 +1,90 @@
from discord.ext import commands
import discord
import core.common as common
import sys
import subprocess
import logging
logger = logging.getLogger(__name__)
class System(commands.Cog):
def __init__(self, bot):
self.bot = bot
self.commit = subprocess.run(["git", "show", "-s", "--format=%h"],
capture_output=True,
encoding="utf-8").stdout.strip()
@commands.group()
async def bot(self, ctx):
if ctx.invoked_subcommand is None:
await ctx.send('No subcommand invoked.')
@bot.command()
async def ping(self, ctx):
await ctx.message.delete()
embed = discord.Embed(title="Pong!",
description=str(round(self.bot.latency * 1000, 1)) + "ms",
colour=common.random_rgb())
embed.set_footer(text=f"requested by {ctx.author}",
icon_url=ctx.author.avatar_url)
await ctx.send(embed=embed)
@bot.command()
@commands.is_owner()
async def stop(self, ctx):
await ctx.message.delete()
embed = discord.Embed(title="Stopping Bot!",
color=common.random_rgb())
embed.set_footer(text=f"requested by {ctx.author}",
icon_url=ctx.author.avatar_url)
await ctx.send(embed=embed)
sys.exit()
@bot.command()
@commands.is_owner()
async def restart(self, ctx):
await ctx.message.delete()
embed = discord.Embed(title="Restarting Bot!",
color=common.random_rgb())
embed.set_footer(text=f"requested by {ctx.author}",
icon_url=ctx.author.avatar_url)
await ctx.send(embed=embed)
sys.exit(26)
@commands.group()
async def git(self, ctx):
if ctx.invoked_subcommand is None:
await ctx.send('No subcommand invoked.')
@git.command()
async def version(self, ctx):
await ctx.message.delete()
d = subprocess.run(["git", "show", "-s", "--format=%ci", self.commit],
capture_output=True,
encoding="utf-8")
m = subprocess.run(['git', 'show', '-s', '--format=%B', self.commit],
capture_output=True,
encoding="utf-8")
embed = discord.Embed(title="Bot Version",
description="Current Bot Version",
color=common.random_rgb(self.commit))
embed.set_footer(text=f"requested by {ctx.author}", icon_url=ctx.author.avatar_url)
embed.add_field(name="ID", value=self.commit, inline=False)
embed.add_field(name="Date", value=d.stdout, inline=False)
embed.add_field(name="Changelog", value=m.stdout, inline=False)
await ctx.send(embed=embed)
@git.command()
async def repo(self, ctx):
await ctx.message.delete()
embed = discord.Embed(title="Code Repository",
description="You can find my source code on [GitDab]("
f"{common.load_config('config.json')[0]['repo_link']}).",
color=common.random_rgb())
embed.set_footer(text=f"requested by {ctx.author}", icon_url=ctx.author.avatar_url)
await ctx.send(embed=embed)
def setup(bot):
bot.add_cog(System(bot))

49
core/common.py Normal file
View file

@ -0,0 +1,49 @@
import json
from pathlib import Path
from typing import Tuple
import logging
import discord
import random
logger = logging.getLogger(__name__)
def load_config(conf_file) -> Tuple[dict, Path]:
"""Load data from a config file.\n
Returns a tuple containing the data as a dict, and the file as a Path"""
config_file = Path(conf_file)
config_file.touch(exist_ok=True)
if config_file.read_text() == "":
config_file.write_text("{}")
logger.debug("config file created.")
with config_file.open("r") as f:
config = json.load(f)
logger.debug("config file loaded.")
return config, config_file
def prompt_config(conf_file, msg, key):
"""Ensure a value exists in the config file, if it doesn't prompt the bot owner to input via the console."""
logger.debug(f"checking if {key} is in config.")
config, config_file = load_config(conf_file)
if key not in config:
logger.debug(f"{key} not found in config file.")
config[key] = input(msg)
with config_file.open("w+") as f:
json.dump(config, f, indent=4)
logger.debug(f"'{config[key]}' saved to config file under '{key}'.")
def update_config(conf_file, key, value):
logger.debug(f"updating config file '{conf_file}' key '{key}' to '{value}'")
config, config_file = load_config(conf_file)
config[key] = value
with config_file.open("w+") as f:
json.dump(config, f, indent=4)
logger.debug(f"config file '{conf_file}' key '{key}' has been updated to '{value}'")
def random_rgb(seed=None):
if seed is not None:
random.seed(seed)
return discord.Colour.from_rgb(random.randrange(0, 255), random.randrange(0, 255), random.randrange(0, 255))

29
main.py Normal file
View file

@ -0,0 +1,29 @@
#!/usr/bin/env/python
import subprocess
import logging
import sys
import time
logger = logging.getLogger(__name__)
logger.setLevel(logging.DEBUG)
logger_handler = logging.StreamHandler()
logger_handler.setFormatter(logging.Formatter('[%(levelname)s] (%(name)s) - %(message)s'))
logger.addHandler(logger_handler)
logger.info("Bot Manager Started!")
def start_bot():
bot_process = subprocess.Popen(["python3", "-B", "bot.py"], stdout=sys.stdout)
return bot_process
bot = start_bot()
while True:
if bot.poll() is not None:
if bot.returncode == 26:
logger.info("exit code 26 received, restarting bot!")
bot = start_bot()
else:
break
time.sleep(1) # keeps code from overworking.