college-bot-v1/utils/client.py

124 lines
4.1 KiB
Python
Raw Normal View History

2023-02-23 10:29:30 +00:00
import asyncio
2023-12-05 16:43:29 +00:00
import logging
2023-02-23 10:29:30 +00:00
import sys
2023-11-04 17:18:39 +00:00
from asyncio import Lock
from datetime import datetime, timezone
2023-05-06 11:29:44 +01:00
from pathlib import Path
2023-11-04 17:18:39 +00:00
from typing import TYPE_CHECKING, Dict, Optional, Union
2023-02-23 10:29:30 +00:00
2023-11-04 17:18:39 +00:00
import discord
2023-02-22 15:17:53 +00:00
from discord.ext import commands
2023-11-04 17:18:39 +00:00
2023-12-05 21:12:33 +00:00
import config
2023-02-23 10:29:30 +00:00
if TYPE_CHECKING:
from asyncio import Task
2023-02-22 15:17:53 +00:00
2023-11-04 17:18:39 +00:00
from uvicorn import Config, Server
2023-02-22 15:17:53 +00:00
2023-11-04 17:18:39 +00:00
__all__ = ("Bot", "bot")
2023-02-22 15:17:53 +00:00
# noinspection PyAbstractClass
class Bot(commands.Bot):
2023-02-23 10:29:30 +00:00
if TYPE_CHECKING:
web: Optional[Dict[str, Union[Server, Config, Task]]]
2023-05-04 18:03:28 +01:00
def __init__(self, intents: discord.Intents, guilds: list[int], extensions: list[str], prefixes: list[str]):
2023-02-22 15:17:53 +00:00
from .console import console
2023-11-04 17:18:39 +00:00
from .db import registry
2023-02-22 15:17:53 +00:00
super().__init__(
2023-05-04 18:03:28 +01:00
command_prefix=commands.when_mentioned_or(*prefixes),
2023-02-22 15:17:53 +00:00
debug_guilds=guilds,
2023-12-05 16:43:29 +00:00
allowed_mentions=discord.AllowedMentions(everyone=False, users=True, roles=False, replied_user=True),
2023-02-22 15:17:53 +00:00
intents=intents,
2023-05-04 18:03:28 +01:00
max_messages=5000,
case_insensitive=True,
2023-02-22 15:17:53 +00:00
)
self.loop.run_until_complete(registry.create_all())
self.training_lock = Lock()
2023-12-05 16:43:29 +00:00
self.started_at = discord.utils.utcnow()
2023-02-22 15:17:53 +00:00
self.console = console
2023-12-05 16:43:29 +00:00
self.log = log = logging.getLogger("jimmy.client")
self.debug = log.debug
self.info = log.info
self.warning = self.warn = log.warning
self.error = self.log.error
self.critical = self.log.critical
2023-02-22 15:17:53 +00:00
for ext in extensions:
try:
self.load_extension(ext)
2023-05-02 19:38:39 +01:00
except discord.ExtensionNotFound:
2023-12-05 16:43:29 +00:00
log.error(f"[red]Failed to load extension {ext}: Extension not found.")
2023-05-02 19:38:39 +01:00
except (discord.ExtensionFailed, OSError) as e:
2023-12-05 16:43:29 +00:00
log.error(f"[red]Failed to load extension {ext}: {e}", exc_info=True)
2023-02-22 15:17:53 +00:00
else:
2023-12-05 16:43:29 +00:00
log.info(f"Loaded extension [green]{ext}")
2023-02-22 15:17:53 +00:00
if getattr(config, "CONNECT_MODE", None) == 2:
2023-12-05 21:12:33 +00:00
2023-02-22 15:17:53 +00:00
async def connect(self, *, reconnect: bool = True) -> None:
2023-12-05 16:43:29 +00:00
self.log.critical("Exit target 2 reached, shutting down (not connecting to discord).")
2023-02-22 15:17:53 +00:00
return
2023-02-23 16:06:35 +00:00
async def on_error(self, event: str, *args, **kwargs):
e_type, e, tb = sys.exc_info()
2023-05-05 20:08:47 +01:00
if isinstance(e, discord.NotFound) and e.code == 10062: # invalid interaction
2023-12-05 16:43:29 +00:00
self.log.warning(f"Invalid interaction received, ignoring. {e!r}")
2023-05-05 20:08:47 +01:00
return
2023-11-04 17:18:39 +00:00
if isinstance(e, discord.CheckFailure) and "The global check once functions failed." in str(e):
2023-02-23 16:06:35 +00:00
return
await super().on_error(event, *args, **kwargs)
2023-02-23 10:29:30 +00:00
async def close(self) -> None:
2023-02-24 08:40:25 +00:00
await self.http.close()
2023-02-23 10:29:30 +00:00
if getattr(self, "web", None) is not None:
2023-12-05 16:43:29 +00:00
self.log.info("Closing web server...")
try:
await asyncio.wait_for(self.web["server"].shutdown(), timeout=5)
2023-03-22 15:57:10 +00:00
self.web["task"].cancel()
self.console.log("Web server closed.")
try:
2023-12-05 16:43:29 +00:00
await asyncio.wait_for(self.web["task"], timeout=5)
except (asyncio.CancelledError, asyncio.TimeoutError):
2023-03-22 15:57:10 +00:00
pass
del self.web["server"]
del self.web["config"]
del self.web["task"]
del self.web
2023-12-05 16:43:29 +00:00
except asyncio.TimeoutError:
pass
2023-02-23 10:29:30 +00:00
try:
2023-02-23 14:12:59 +00:00
await super().close()
2023-02-23 10:29:30 +00:00
except asyncio.TimeoutError:
2023-12-05 16:43:29 +00:00
self.log.critical("Timed out while closing, forcing shutdown.")
2023-02-23 10:29:30 +00:00
sys.exit(1)
2023-12-05 16:43:29 +00:00
self.log.info("Finished shutting down.")
2023-02-23 10:29:30 +00:00
2023-02-22 15:17:53 +00:00
try:
from config import intents as _intents
except ImportError:
_intents = discord.Intents.all()
try:
from config import extensions as _extensions
except ImportError:
_extensions = [
"jishaku",
]
2023-05-06 11:29:44 +01:00
for file in Path("cogs").glob("*.py"):
if file.name.startswith(("_", ".")):
continue
_extensions.append(f"cogs.{file.stem}")
2023-02-22 15:17:53 +00:00
2023-05-04 18:03:28 +01:00
try:
from config import prefixes as _prefixes
except ImportError:
_prefixes = ("h!", "r!")
2023-02-22 15:17:53 +00:00
2023-05-04 18:03:28 +01:00
bot = Bot(_intents, config.guilds, _extensions, list(_prefixes))