2018-08-12 19:00:04 +00:00
|
|
|
import asyncio
|
|
|
|
import logging
|
|
|
|
|
|
|
|
from discord import Game
|
|
|
|
from discord.ext import commands
|
|
|
|
from discord.utils import oauth_url
|
2018-08-19 16:37:59 +00:00
|
|
|
from sqlalchemy.exc import OperationalError
|
2018-08-12 19:00:04 +00:00
|
|
|
|
2018-08-29 15:08:21 +00:00
|
|
|
import logging.handlers as handlers
|
|
|
|
from sys import stdout
|
|
|
|
|
|
|
|
|
2018-08-21 20:36:51 +00:00
|
|
|
from geoffrey.BotConfig import bot_config
|
|
|
|
from geoffrey.BotErrors import *
|
|
|
|
from geoffrey.Commands import Commands
|
|
|
|
from geoffrey.DatabaseModels import Player
|
|
|
|
from geoffrey.MinecraftAccountInfoGrabber import *
|
2018-08-12 03:21:21 +00:00
|
|
|
|
|
|
|
logger = logging.getLogger(__name__)
|
2018-08-11 21:07:33 +00:00
|
|
|
|
|
|
|
description = '''
|
|
|
|
Geoffrey (pronounced JOFF-ree) started his life as an inside joke none of you will understand.
|
|
|
|
At some point, she was to become an airhorn bot. Now, they know where your stuff is.
|
|
|
|
|
|
|
|
Please respect Geoffrey, the bot is very sensitive.
|
|
|
|
|
|
|
|
If have a suggestion or if something is borked, you can PM my ding dong of a creator ZeroHD.
|
|
|
|
|
|
|
|
*You must use ?register before adding things to Geoffrey*
|
|
|
|
'''
|
|
|
|
|
|
|
|
bad_error_message = 'OOPSIE WOOPSIE!! Uwu We made a fucky wucky!! A wittle fucko boingo! The admins at our ' \
|
2018-08-19 16:37:59 +00:00
|
|
|
'headquarters are working VEWY HAWD to fix this! (Error in command {})'
|
2018-08-11 21:07:33 +00:00
|
|
|
|
2018-08-29 15:49:32 +00:00
|
|
|
extensions = ['geoffrey.cogs.Add_Commands',
|
|
|
|
'geoffrey.cogs.Delete_Commands',
|
|
|
|
'geoffrey.cogs.Edit_Commands',
|
|
|
|
'geoffrey.cogs.Search_Commands',
|
|
|
|
'geoffrey.cogs.Admin_Commands']
|
2018-08-11 21:07:33 +00:00
|
|
|
|
2018-08-19 16:37:59 +00:00
|
|
|
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.')
|
|
|
|
|
2018-08-11 21:07:33 +00:00
|
|
|
|
|
|
|
@bot.event
|
|
|
|
async def on_ready():
|
2018-08-12 15:32:35 +00:00
|
|
|
logger.info("%s Online, ID: %s", bot.user.name, bot.user.id)
|
2018-08-12 19:00:04 +00:00
|
|
|
info = await bot.application_info()
|
|
|
|
url = oauth_url(info.id)
|
|
|
|
logger.info("Bot url: %s", url)
|
2018-08-11 21:07:33 +00:00
|
|
|
await bot.change_presence(game=Game(name=bot_config.status))
|
|
|
|
|
|
|
|
|
2018-08-12 15:32:35 +00:00
|
|
|
@bot.event
|
|
|
|
async def on_command(command, ctx):
|
|
|
|
if ctx.invoked_subcommand is None:
|
|
|
|
subcommand = ""
|
|
|
|
else:
|
2018-08-19 16:37:59 +00:00
|
|
|
subcommand = ":" + ctx.invoked_subcommand
|
2018-08-12 15:32:35 +00:00
|
|
|
|
|
|
|
logger.info("User %s, used command %s%s with context: %s", ctx.message.author, command, subcommand, ctx.args)
|
|
|
|
|
|
|
|
|
2018-08-11 21:07:33 +00:00
|
|
|
@bot.event
|
|
|
|
async def on_command_error(error, ctx):
|
2018-08-29 18:37:06 +00:00
|
|
|
error_str = ''
|
2018-08-11 21:07:33 +00:00
|
|
|
if hasattr(ctx, 'cog'):
|
|
|
|
if "Admin_Commands" in ctx.cog.__str__():
|
|
|
|
return
|
2018-08-29 18:37:06 +00:00
|
|
|
if hasattr(error, 'original'):
|
|
|
|
if isinstance(error.original, NoPermissionError):
|
|
|
|
error_str = 'You don\'t have permission for that cool command.'
|
|
|
|
elif isinstance(error.original, UsernameLookupFailed):
|
|
|
|
error_str = 'Your user name was not found, either Mojang is having a fucky wucky ' \
|
|
|
|
'or your nickname is not set correctly. *stares at the Mods*'
|
|
|
|
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 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()
|
2018-08-11 21:07:33 +00:00
|
|
|
elif isinstance(error, commands.CommandOnCooldown):
|
|
|
|
return
|
|
|
|
elif isinstance(error, commands.UserInputError):
|
2018-08-19 16:37:59 +00:00
|
|
|
error_str = 'Invalid syntax for **{}** you ding dong:' \
|
2018-08-11 21:07:33 +00:00
|
|
|
.format(ctx.invoked_with, ctx.invoked_with)
|
2018-08-12 15:32:35 +00:00
|
|
|
|
|
|
|
pages = bot.formatter.format_help_for(ctx, ctx.command)
|
|
|
|
for page in pages:
|
|
|
|
error_str = error_str + '\n' + page
|
2018-08-29 18:37:06 +00:00
|
|
|
elif isinstance(error, commands.CommandNotFound):
|
|
|
|
return
|
2018-08-12 15:32:35 +00:00
|
|
|
|
2018-08-29 18:37:06 +00:00
|
|
|
if error_str is None:
|
2018-08-19 16:37:59 +00:00
|
|
|
await send_error_message('Geoffrey encountered unhandled exception: {}. Context:'.format(error, ctx.args))
|
|
|
|
|
2018-08-12 03:21:21 +00:00
|
|
|
logger.error("Geoffrey encountered unhandled exception: %s", error)
|
2018-08-19 16:37:59 +00:00
|
|
|
error_str = bad_error_message.format(ctx.invoked_with)
|
2018-08-11 21:07:33 +00:00
|
|
|
|
|
|
|
await bot.send_message(ctx.message.channel, '{} **Error Running Command:** {}'.format(ctx.message.author.mention,
|
|
|
|
error_str))
|
|
|
|
|
|
|
|
|
2018-08-19 16:37:59 +00:00
|
|
|
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)
|
|
|
|
|
|
|
|
|
2018-08-11 21:07:33 +00:00
|
|
|
async def username_update():
|
|
|
|
await bot.wait_until_ready()
|
|
|
|
while not bot.is_closed:
|
|
|
|
session = bot_commands.interface.database.Session()
|
|
|
|
try:
|
2018-08-12 15:32:35 +00:00
|
|
|
logger.info("Updating MC usernames...")
|
2018-08-11 21:07:33 +00:00
|
|
|
session = bot_commands.interface.database.Session()
|
|
|
|
player_list = session.query(Player).all()
|
|
|
|
for player in player_list:
|
|
|
|
player.name = grab_playername(player.mc_uuid)
|
|
|
|
|
|
|
|
session.commit()
|
2018-08-12 15:32:35 +00:00
|
|
|
logger.info("Username update done.")
|
2018-08-11 21:07:33 +00:00
|
|
|
|
|
|
|
except UsernameLookupFailed:
|
2018-08-12 03:21:21 +00:00
|
|
|
logger.info("Username lookup error.")
|
2018-08-11 21:07:33 +00:00
|
|
|
session.rollback()
|
2018-08-19 14:57:19 +00:00
|
|
|
except OperationalError:
|
2018-08-19 16:37:59 +00:00
|
|
|
await send_error_message('Error connecting to the MySQL server, is it offline?')
|
2018-08-19 14:57:19 +00:00
|
|
|
logger.info("MySQL connection error")
|
2018-08-11 21:07:33 +00:00
|
|
|
finally:
|
|
|
|
session.close()
|
2018-08-12 15:32:35 +00:00
|
|
|
await asyncio.sleep(600)
|
2018-08-11 21:07:33 +00:00
|
|
|
|
2018-08-29 15:08:21 +00:00
|
|
|
def setup_logging():
|
|
|
|
|
|
|
|
discord_logger = logging.getLogger('discord')
|
|
|
|
discord_logger.setLevel(logging.INFO)
|
|
|
|
sql_logger = logging.getLogger('sqlalchemy.engine')
|
|
|
|
sql_logger.setLevel(logging.INFO)
|
|
|
|
bot_info_logger = logging.getLogger('geoffrey.bot')
|
|
|
|
bot_info_logger.setLevel(logging.INFO)
|
|
|
|
|
|
|
|
handler = handlers.TimedRotatingFileHandler(filename='Geoffrey.log', when='D',
|
|
|
|
interval=bot_config.rotation_duration, backupCount=bot_config.count,
|
|
|
|
encoding='utf-8')
|
|
|
|
|
|
|
|
handler.setFormatter(logging.Formatter('%(asctime)s:%(levelname)s:%(name)s: %(message)s'))
|
|
|
|
|
|
|
|
console = logging.StreamHandler(stdout)
|
|
|
|
|
|
|
|
console.setFormatter(logging.Formatter('%(asctime)s:%(levelname)s:%(name)s: %(message)s'))
|
|
|
|
|
|
|
|
discord_logger.addHandler(handler)
|
|
|
|
sql_logger.addHandler(handler)
|
|
|
|
bot_info_logger.addHandler(handler)
|
|
|
|
bot_info_logger.addHandler(console)
|
2018-08-11 21:07:33 +00:00
|
|
|
|
2018-08-29 18:37:06 +00:00
|
|
|
|
2018-08-11 21:07:33 +00:00
|
|
|
def start_bot():
|
|
|
|
try:
|
2018-08-29 15:08:21 +00:00
|
|
|
setup_logging()
|
2018-08-19 16:37:59 +00:00
|
|
|
Commands()
|
2018-08-14 23:56:07 +00:00
|
|
|
for extension in extensions:
|
|
|
|
try:
|
|
|
|
bot.load_extension(extension)
|
|
|
|
except Exception as e:
|
|
|
|
logger.info('Failed to load extension {}'.format(extension))
|
|
|
|
raise e
|
2018-08-11 21:07:33 +00:00
|
|
|
bot.loop.create_task(username_update())
|
2018-08-12 15:32:35 +00:00
|
|
|
logger.info('Logging into Discord...')
|
2018-08-11 21:07:33 +00:00
|
|
|
bot.run(bot_config.token)
|
2018-08-12 15:32:35 +00:00
|
|
|
except KeyboardInterrupt:
|
|
|
|
logger.info("Bot received keyboard interrupt")
|
|
|
|
except Exception as e:
|
|
|
|
logger.info('Bot encountered the following unhandled exception %s', e)
|
2018-08-11 23:02:50 +00:00
|
|
|
finally:
|
2018-08-12 15:32:35 +00:00
|
|
|
bot.loop.stop()
|
2018-08-12 03:21:21 +00:00
|
|
|
logger.info("Bot shutting down...")
|