college-bot-v1/main.py
2023-12-05 16:43:21 +00:00

140 lines
4.8 KiB
Python

import asyncio
import sys
import logging
import textwrap
from datetime import datetime, timedelta, timezone
from rich.logging import RichHandler
import config
import discord
from discord.ext import commands
from utils import JimmyBanException, JimmyBans, console, get_or_none
from utils.client import bot
logging.basicConfig(
filename=getattr(config, "LOG_FILE", "jimmy.log"),
filemode=getattr(config, "LOG_MODE", "a"),
format="%(asctime)s:%(level)s:%(name)s: %(message)s",
datefmt="%Y-%m-%d:%H:%M",
level=getattr(config, "LOG_LEVEL", logging.INFO)
)
# echo to stdout
handler = RichHandler(getattr(config, "LOG_LEVEL", logging.INFO), console=console, markup=True)
logging.getLogger().addHandler(handler)
@bot.listen()
async def on_connect():
bot.log.info("[green]Connected to discord!")
@bot.listen("on_application_command_error")
async def on_application_command_error(ctx: discord.ApplicationContext, error: Exception):
if isinstance(error, commands.CommandOnCooldown):
now = discord.utils.utcnow()
now += timedelta(seconds=error.retry_after)
return await ctx.respond(
f"\N{stopwatch} This command is on cooldown. You can use this command again "
f"{discord.utils.format_dt(now, 'R')}.",
delete_after=error.retry_after,
)
elif isinstance(error, commands.MaxConcurrencyReached):
return await ctx.respond(
f"\N{warning sign} This command is already running. Please wait for it to finish.",
ephemeral=True,
)
elif isinstance(error, JimmyBanException):
return await ctx.respond(str(error))
elif isinstance(error, commands.CommandError):
if error.args and error.args[0] == "User not connected to a voice channel.":
return
if ctx.user.id == 1019233057519177778:
await ctx.respond("Uh oh! I did a fucky wucky >.< I'll make sure to let important peoplez know straight away!!")
else:
text = "Application Command Error: `%r`" % error
await ctx.respond(textwrap.shorten(text, 2000))
raise error
@bot.listen("on_command_error")
async def on_command_error(ctx: commands.Context, error: Exception):
if isinstance(error, commands.CommandNotFound):
return
elif isinstance(error, JimmyBanException):
return await ctx.reply(str(error))
await ctx.reply(textwrap.shorten("Command Error: `%r`" % error, 2000))
raise error
@bot.listen("on_application_command")
async def on_application_command(ctx: discord.ApplicationContext):
bot.log.info(
"{0.author} ({0.author.id}) used application command /{0.command.qualified_name} in "
"[blue]#{0.channel}[/], {0.guild}".format(ctx)
)
@bot.event
async def on_ready():
bot.log.info("(READY) Logged in as", bot.user)
if getattr(config, "CONNECT_MODE", None) == 1:
bot.log.critical("Bot is now ready and exit target 1 is set, shutting down.")
await bot.close()
sys.exit(0)
@bot.slash_command()
async def ping(ctx: discord.ApplicationContext):
# noinspection SpellCheckingInspection
"""Checks the bot's response time"""
gateway = round(ctx.bot.latency * 1000, 2)
return await ctx.respond(f"\N{white heavy check mark} Pong! `{gateway}ms`.")
@bot.check_once
async def check_not_banned(ctx: discord.ApplicationContext | commands.Context):
if await bot.is_owner(ctx.author) or ctx.command.name in ("block", "unblock", "timetable", "verify", "kys"):
return True
user = ctx.author
ban: JimmyBans = await get_or_none(JimmyBans, user_id=user.id)
if ban:
dt = datetime.fromtimestamp(ban.until, timezone.utc)
if dt < discord.utils.utcnow():
await ban.delete()
else:
raise JimmyBanException(dt, ban.reason)
return True
if __name__ == "__main__":
bot.log.info("Starting...")
bot.started_at = discord.utils.utcnow()
if getattr(config, "WEB_SERVER", True):
bot.log.info("Web server is enabled (WEB_SERVER=True in config.py), initialising.")
import uvicorn
from web.server import app
app.state.bot = bot
http_config = uvicorn.Config(
app,
host=getattr(config, "HTTP_HOST", "127.0.0.1"),
port=getattr(config, "HTTP_PORT", 3762),
**getattr(config, "UVICORN_CONFIG", {}),
)
bot.log.info("Web server will listen on %s:%s", http_config.host, http_config.port)
server = uvicorn.Server(http_config)
bot.log.info("Starting web server...")
loop = bot.loop
http_server_task = loop.create_task(server.serve())
bot.web = {
"server": server,
"config": http_config,
"task": http_server_task,
}
bot.log.info("Beginning main loop.")
bot.run(config.token)