1
0

main.py 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145
  1. import logging, os
  2. import discord
  3. from discord.ext import commands
  4. import asyncpg, asyncio
  5. # Called when the database does not seem to exist.
  6. def sql_db_does_not_exist():
  7. logging.error("Database does not exist. Doublecheck if it has been created, and the user has access.")
  8. quit()
  9. # Called when SQL authentication fails.
  10. def sql_authentication_error():
  11. logging.error("Database authentication failed. Doublecheck username & password, and if the user has been created.")
  12. quit()
  13. # Called on settings issue.
  14. def hint_quit(): # Hint how to edit the settings and quit
  15. logging.info("")
  16. logging.info(" edit local_settings.py")
  17. logging.info("")
  18. quit()
  19. # Called when settings file is not present.
  20. def missing_config(): # Copy or create settings file if missing
  21. logging.basicConfig(level=logging.DEBUG)
  22. if not os.path.exists("local_settings.py"):
  23. logging.error("Settings file not found.")
  24. logging.info("Copying local_settings_example.py to local_settings.py")
  25. try:
  26. os.system("cp local_settings_example.py local_settings.py")
  27. except FileNotFoundError:
  28. logging.info("local_settings_example.py not found, creating local_settings.py")
  29. with open("local_settings.py", "w") as settings_file:
  30. settings_file.writelines(
  31. [
  32. "import logging",
  33. "LOG_LEVEL = logging.INFO # Options: CRITICAL, ERROR, WARNING, INFO, and DEBUG",
  34. "",
  35. "DATABASE_NAME = \"\"",
  36. "DATABASE_USER = \"\"",
  37. "DATABASE_HOST = \"\"",
  38. "DATABASE_PASSWORD = \"\"",
  39. "",
  40. "WEB_HOST = \"\"",
  41. "WEB_SCHEME = \"\"",
  42. "",
  43. "DISCORD_TOKEN = \"\"",
  44. "COMMAND_PREFIX = \"\"",
  45. ]
  46. )
  47. logging.error("Settings undefined.")
  48. logging.info("Configure the settings:")
  49. hint_quit()
  50. # Issue with specific setting
  51. def correct_setting(setting): # Hint to correct specific setting and quit
  52. logging.info("Correct the %s in local_settings.py", setting)
  53. hint_quit()
  54. # Attempt to import the local settings and quit gracefully on failure
  55. try:
  56. import local_settings as settings # Environment dependant settings stored in local_settings.py, untracked by .gitinore
  57. except ModuleNotFoundError: # Local settings module import failure
  58. missing_config() # Prepare for configuration and inform operator
  59. async def main():
  60. # Set loglevel
  61. try:
  62. logging.basicConfig(level=settings.LOG_LEVEL)
  63. except AttributeError:
  64. missing_config()
  65. # Define robot
  66. intents = discord.Intents.default()
  67. intents.message_content = True
  68. intents.invites = True
  69. intents.members = True
  70. # Try being a bot
  71. try:
  72. bot = commands.Bot(
  73. command_prefix="/",
  74. description="Charlie's Angels bot",
  75. intents=intents,
  76. case_insensitive=True,
  77. )
  78. except AttributeError:
  79. missing_config()
  80. # Extensions
  81. default_extensions = [ # Define cogs
  82. "commands.admin",
  83. "commands.games",
  84. "commands.general",
  85. "commands.angels",
  86. "events.general", # Causes an errror on any slash command, even commands from other cogs
  87. "events.angels",
  88. ]
  89. for ext in default_extensions:
  90. logging.info(f"Loading extension: {ext}")
  91. await bot.load_extension(ext) # Load cog
  92. # Database connection
  93. async def create_db_pool(): # Connect to database
  94. try:
  95. bot.pg = await asyncpg.create_pool(
  96. database=settings.DATABASE_NAME,
  97. user=settings.DATABASE_USER,
  98. host=settings.DATABASE_HOST,
  99. password=settings.DATABASE_PASSWORD,
  100. )
  101. except AttributeError:
  102. missing_config()
  103. except asyncpg.exceptions.InvalidPasswordError:
  104. sql_authentication_error()
  105. except asyncpg.exceptions.InvalidCatalogNameError:
  106. sql_db_does_not_exist()
  107. # Create database pool
  108. await create_db_pool()
  109. # Create database tables if they do not exist
  110. from query.initialise_database import init_db, check_db
  111. try:
  112. await check_db(bot.pg) # TODO: Create a better check
  113. except asyncpg.exceptions.UndefinedTableError:
  114. logging.info("User table does not exists, assuming empty database. Populating database...")
  115. await init_db(bot.pg)
  116. await bot.start(settings.DISCORD_TOKEN)
  117. # Run robot
  118. try:
  119. asyncio.run(main())
  120. except AttributeError:
  121. missing_config()
  122. except discord.errors.LoginFailure:
  123. logging.error("Invalid discord token.")
  124. correct_setting("DISCORD_TOKEN")
  125. except KeyboardInterrupt:
  126. logging.info("Received keyboard interrupt, exiting...")
  127. quit()