Red-DiscordBot/main.py
Will 13cabfbad7 [Core] Add multiple/external cog paths support (#853)
* WIP cog path manager

* Initial working state

* Get real reloading working

* Type error thingy

* And fix the tests

* Start UI shit

* path reordering

* Add install path getter/setter and fix config syntax

* Determine bot directory at runtime

* Add UI commands for install path

* Update downloader to use install path

* Add sane install path default

* Make evaluation of cog install path lazy

* Some typing fixes

* Add another line to codeowners

* Conditionally put install path in paths

* Always put install path first

* Dont allow people to add the installdir as an additional path, guarantee install dir isn't shown with paths command

* Make shit update loaded cogs

* Add tests

* Another one
2017-08-10 23:09:49 -04:00

145 lines
4.5 KiB
Python

from pathlib import Path
from core.bot import Red, ExitCodes
from core.cog_manager import CogManagerUI
from core.global_checks import init_global_checks
from core.events import init_events
from core.sentry_setup import init_sentry_logging
from core.cli import interactive_config, confirm, parse_cli_flags, ask_sentry
from core.core_commands import Core
from core.dev_commands import Dev
import asyncio
import discord
import logging.handlers
import logging
import os
import sys
#
# Red - Discord Bot v3
#
# Made by Twentysix, improved by many
#
if discord.version_info.major < 1:
print("You are not running the rewritten version of discord.py.\n\n"
"In order to use Red v3 you MUST be running d.py version"
" >= 1.0.0.")
sys.exit(1)
def init_loggers(cli_flags):
# d.py stuff
dpy_logger = logging.getLogger("discord")
dpy_logger.setLevel(logging.WARNING)
console = logging.StreamHandler()
console.setLevel(logging.WARNING)
dpy_logger.addHandler(console)
# Red stuff
logger = logging.getLogger("red")
red_format = logging.Formatter(
'%(asctime)s %(levelname)s %(module)s %(funcName)s %(lineno)d: '
'%(message)s',
datefmt="[%d/%m/%Y %H:%M]")
stdout_handler = logging.StreamHandler(sys.stdout)
stdout_handler.setFormatter(red_format)
if cli_flags.debug:
os.environ['PYTHONASYNCIODEBUG'] = '1'
logger.setLevel(logging.DEBUG)
else:
logger.setLevel(logging.WARNING)
fhandler = logging.handlers.RotatingFileHandler(
filename='red.log', encoding='utf-8', mode='a',
maxBytes=10**7, backupCount=5)
fhandler.setFormatter(red_format)
logger.addHandler(fhandler)
logger.addHandler(stdout_handler)
# Sentry stuff
sentry_logger = logging.getLogger("red.sentry")
sentry_logger.setLevel(logging.WARNING)
return logger, sentry_logger
def determine_main_folder() -> Path:
return Path(os.path.dirname(__file__)).resolve()
if __name__ == '__main__':
cli_flags = parse_cli_flags()
log, sentry_log = init_loggers(cli_flags)
description = "Red v3 - Alpha"
bot_dir = determine_main_folder()
red = Red(cli_flags, description=description, pm_help=None,
bot_dir=bot_dir)
init_global_checks(red)
init_events(red, cli_flags)
red.add_cog(Core())
red.add_cog(CogManagerUI())
if cli_flags.dev:
red.add_cog(Dev())
token = os.environ.get("RED_TOKEN", red.db.token())
prefix = cli_flags.prefix or red.db.prefix()
if token is None or not prefix:
if cli_flags.no_prompt is False:
new_token = interactive_config(red, token_set=bool(token),
prefix_set=bool(prefix))
if new_token:
token = new_token
else:
log.critical("Token and prefix must be set in order to login.")
sys.exit(1)
if red.db.enable_sentry() is None:
ask_sentry(red)
if red.db.enable_sentry():
init_sentry_logging(sentry_log)
loop = asyncio.get_event_loop()
cleanup_tasks = True
try:
loop.run_until_complete(red.start(token, bot=not cli_flags.not_bot))
except discord.LoginFailure:
cleanup_tasks = False # No login happened, no need for this
log.critical("This token doesn't seem to be valid. If it belongs to "
"a user account, remember that the --not-bot flag "
"must be used. For self-bot functionalities instead, "
"--self-bot")
db_token = red.db.token()
if db_token and not cli_flags.no_prompt:
print("\nDo you want to reset the token? (y/n)")
if confirm("> "):
loop.run_until_complete(red.db.token.set(""))
print("Token has been reset.")
except KeyboardInterrupt:
log.info("Keyboard interrupt detected. Quitting...")
loop.run_until_complete(red.logout())
red._shutdown_mode = ExitCodes.SHUTDOWN
except Exception as e:
log.critical("Fatal exception", exc_info=e)
sentry_log.critical("Fatal Exception", exc_info=e)
loop.run_until_complete(red.logout())
finally:
if cleanup_tasks:
pending = asyncio.Task.all_tasks(loop=red.loop)
gathered = asyncio.gather(*pending, loop=red.loop)
gathered.cancel()
red.loop.run_until_complete(gathered)
gathered.exception()
sys.exit(red._shutdown_mode.value)