Improved error handling for MySQL connection issues and added support to PM users on certain errors

doc_update
Joey Hines 2018-08-19 11:37:59 -05:00
parent f801016a5b
commit 7532912d21
3 changed files with 43 additions and 26 deletions

View File

@ -7,6 +7,7 @@ def create_config(config):
'Status': '',
'Prefix': '?',
'Bot_Mod': ''
'Error_Users: '''
}
config['SQL'] = {'Dialect+Driver': 'mysql+mysqldb',
'Username': '',
@ -51,6 +52,7 @@ class Config:
self.prefix = self.config['Discord']['Prefix']
self.dynmap_url = self.config['Minecraft']['Dynmap_Url']
self.bot_mod = self.config['Discord']['Bot_Mod'].split(',')
self.error_users = self.config['Discord']['Error_Users'].split(',')
self.count = int(self.config['Logging']['Count'])
self.rotation_duration = int(self.config['Logging']['Rotation_Duration'])
self.special_name_list = dict(self.config.items('Special Names'))

38
bot.py
View File

@ -4,15 +4,14 @@ import logging
from discord import Game
from discord.ext import commands
from discord.utils import oauth_url
from sqlalchemy.exc import OperationalError
from BotConfig import *
from BotConfig import bot_config
from BotErrors import *
from Commands import Commands
from DatabaseModels import Player
from MinecraftAccountInfoGrabber import *
from pymysql.err import OperationalError
logger = logging.getLogger(__name__)
description = '''
@ -27,11 +26,7 @@ If have a suggestion or if something is borked, you can PM my ding dong of a cre
'''
bad_error_message = 'OOPSIE WOOPSIE!! Uwu We made a fucky wucky!! A wittle fucko boingo! The admins at our ' \
'headquarters are working VEWY HAWD to fix this! (Error in command {}: {})'
bot = commands.Bot(command_prefix=bot_config.prefix, description=description, case_insensitive=True)
bot_commands = Commands()
'headquarters are working VEWY HAWD to fix this! (Error in command {})'
extensions = ['cogs.Add_Commands',
'cogs.Delete_Commands',
@ -39,6 +34,13 @@ extensions = ['cogs.Add_Commands',
'cogs.Search_Commands',
'cogs.Admin_Commands']
bot = commands.Bot(command_prefix=bot_config.prefix, description=description, case_insensitive=True)
try:
bot_commands = Commands()
except OperationalError:
logger.info('Could not connect to MySQL server.')
@bot.event
async def on_ready():
@ -54,7 +56,7 @@ async def on_command(command, ctx):
if ctx.invoked_subcommand is None:
subcommand = ""
else:
subcommand = ":"+ctx.invoked_subcommand
subcommand = ":" + ctx.invoked_subcommand
logger.info("User %s, used command %s%s with context: %s", ctx.message.author, command, subcommand, ctx.args)
@ -69,7 +71,7 @@ async def on_command_error(error, ctx):
elif isinstance(error, commands.CommandOnCooldown):
return
elif isinstance(error, commands.UserInputError):
error_str = 'Invalid syntax for **{}** you ding dong:'\
error_str = 'Invalid syntax for **{}** you ding dong:' \
.format(ctx.invoked_with, ctx.invoked_with)
pages = bot.formatter.format_help_for(ctx, ctx.command)
@ -84,23 +86,31 @@ async def on_command_error(error, ctx):
elif isinstance(error.original, PlayerNotFound):
error_str = 'Make sure to use ?register first you ding dong.'
elif isinstance(error.original, EntryNameNotUniqueError):
error_str = 'An entry in the database already has that name ding dong.'
error_str = 'An entry in the database already has that name you ding dong.'
elif isinstance(error.original, DatabaseValueError):
error_str = 'Use a shorter name or a smaller value, dong ding.'
elif isinstance(error.original, NotOnServerError):
error_str = 'Command needs to be run on 24CC. Run this command there whoever you are.'.format()
elif isinstance(error.original, OperationalError):
await send_error_message('Error connecting to the MySQL server, is it offline?')
error_str = 'Database connection issue, looks like some admin has to fix something.'.format()
else:
await send_error_message('Geoffrey encountered unhandled exception: {}. Context:'.format(error, ctx.args))
logger.error("Geoffrey encountered unhandled exception: %s", error)
error_str = bad_error_message.format(ctx.invoked_with, error)
error_str = bad_error_message.format(ctx.invoked_with)
await bot.send_message(ctx.message.channel, '{} **Error Running Command:** {}'.format(ctx.message.author.mention,
error_str))
async def send_error_message(msg):
for user_id in bot_config.error_users:
user = await bot.get_user_info(user_id)
await bot.send_message(user, msg)
async def username_update():
session = None
await bot.wait_until_ready()
while not bot.is_closed:
session = bot_commands.interface.database.Session()
@ -118,6 +128,7 @@ async def username_update():
logger.info("Username lookup error.")
session.rollback()
except OperationalError:
await send_error_message('Error connecting to the MySQL server, is it offline?')
logger.info("MySQL connection error")
finally:
session.close()
@ -126,6 +137,7 @@ async def username_update():
def start_bot():
try:
Commands()
for extension in extensions:
try:
bot.load_extension(extension)

View File

@ -15,7 +15,7 @@ class Search_Commands:
@commands.command(pass_context=True)
@commands.cooldown(5, 60, commands.BucketType.user)
async def find(self, ctx, * args):
async def find(self, ctx, *args):
"""
Finds all the locations and tunnels matching the search term
?find [Search]
@ -28,10 +28,11 @@ class Search_Commands:
result = bot_commands.find(search)
await self.bot.say('{}, The following entries match **{}**:\n{}'.format(ctx.message.author.mention, search, result))
await self.bot.say(
'{}, The following entries match **{}**:\n{}'.format(ctx.message.author.mention, search, result))
except LocationLookUpError:
await self.bot.say('{}, no matches to **{}** were found in the database.'.format(ctx.message.author.mention, search))
await self.bot.say(
'{}, no matches to **{}** were found in the database.'.format(ctx.message.author.mention, search))
@commands.command(pass_context=True)
@commands.cooldown(5, 60, commands.BucketType.user)
@ -43,15 +44,15 @@ class Search_Commands:
try:
result = bot_commands.tunnel(player)
await self.bot.say('{}, **{}** owns the following tunnels: \n{}'.format(ctx.message.author.mention, player, result))
await self.bot.say(
'{}, **{}** owns the following tunnels: \n{}'.format(ctx.message.author.mention, player, result))
except LocationLookUpError:
await self.bot.say('{}, no tunnels for **{}** were found in the database.'
.format(ctx.message.author.mention, player))
.format(ctx.message.author.mention, player))
@commands.command(pass_context=True)
@commands.cooldown(5, 60, commands.BucketType.user)
async def find_around(self, ctx, x_pos: int, z_pos: int, * args):
async def find_around(self, ctx, x_pos: int, z_pos: int, *args):
"""
Finds all the locations around a certain point.
The radius defaults to 200 blocks if no value is given.
@ -84,10 +85,11 @@ class Search_Commands:
ctx.message.author.mention, radius, base_string))
else:
await self.bot.say('{}, there are no locations within {} blocks of that point'
.format(ctx.message.author.mention, radius))
.format(ctx.message.author.mention, radius))
except ValueError:
await self.bot.say('{}, invalid radius, the radius must be a whole number.'.format(ctx.message.author.mention,
radius))
await self.bot.say(
'{}, invalid radius, the radius must be a whole number.'.format(ctx.message.author.mention,
radius))
except InvalidDimError:
await self.bot.say('{}, {} is an invalid dimension.'.format(ctx.message.author.mention, dimension))
@ -100,13 +102,14 @@ class Search_Commands:
"""
try:
result = bot_commands.selling(item_name)
await self.bot.say('{}, the following shops sell **{}**: \n{}'.format(ctx.message.author.mention, item_name, result))
await self.bot.say(
'{}, the following shops sell **{}**: \n{}'.format(ctx.message.author.mention, item_name, result))
except ItemNotFound:
await self.bot.say('{}, no shop sells **{}**.'.format(ctx.message.author.mention, item_name))
@commands.command(pass_context=True)
@commands.cooldown(5, 60, commands.BucketType.user)
async def info(self, ctx, * args):
async def info(self, ctx, *args):
"""
Displays info about a location.
If the location is a shop, it displays the shop's inventory.