-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy path__main__.py
135 lines (112 loc) · 3.85 KB
/
__main__.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
from __future__ import annotations
try:
# `?tag truststore` in discord.py server.
# Why Windows is so bad with SSL?
import truststore
except ImportError:
pass
else:
truststore.inject_into_ssl()
import asyncio
import logging
import platform
import sys
import traceback
from pathlib import Path
from typing import Any
import aiohttp
import asyncpg
import click
import discord
import orjson
from bot import AluBot, setup_logging
from config import config
from utils import const
try:
import uvloop # type: ignore[reportMissingImports] # not available on Windows
except ImportError:
pass
else:
asyncio.set_event_loop_policy(uvloop.EventLoopPolicy())
async def create_pool() -> asyncpg.Pool[asyncpg.Record]:
"""Create a database connection pool."""
def _encode_jsonb(value: Any) -> str:
return orjson.dumps(value).decode("utf-8")
def _decode_jsonb(value: str) -> Any:
return orjson.loads(value)
async def init(con: asyncpg.Connection[asyncpg.Record]) -> None:
await con.set_type_codec(
"jsonb",
schema="pg_catalog",
encoder=_encode_jsonb,
decoder=_decode_jsonb,
format="text",
)
postgres_url = config["POSTGRES"]["VPS"] if platform.system() == "Linux" else config["POSTGRES"]["HOME"]
return await asyncpg.create_pool(
postgres_url,
init=init,
command_timeout=60,
min_size=20,
max_size=20,
statement_cache_size=0,
) # type: ignore[reportReturnType]
async def start_the_bot(*, test: bool) -> None:
"""Helper function to start the bot."""
log = logging.getLogger()
try:
pool = await create_pool()
except Exception:
msg = "Could not set up PostgreSQL. Exiting."
click.echo(msg, file=sys.stderr)
log.exception(msg)
if platform.system() != "Windows":
session = aiohttp.ClientSession()
webhook = discord.Webhook.from_url(
url=config["WEBHOOKS"]["SPAM"],
session=session,
)
embed = discord.Embed(color=const.Color.error, description=msg)
await webhook.send(content=const.Role.error.mention, embed=embed)
await session.close()
return
else:
async with (
aiohttp.ClientSession() as session,
pool as pool,
AluBot(test=test, session=session, pool=pool) as alubot,
):
await alubot.start()
@click.group(invoke_without_command=True, options_metavar="[options]")
@click.pass_context
@click.option("--test", "-t", is_flag=True)
def main(click_ctx: click.Context, *, test: bool) -> None:
"""Launches the bot."""
if click_ctx.invoked_subcommand is None:
with setup_logging(test=test):
try:
asyncio.run(start_the_bot(test=test))
except KeyboardInterrupt:
print("Aborted! The bot was interrupted with `KeyboardInterrupt`!") # noqa: T201
@main.group(short_help="database stuff", options_metavar="[options]")
def db() -> None:
"""Group for cli database related commands."""
@db.command()
def create() -> None:
"""Creates the database tables."""
try:
async def run_create() -> None:
connection = await asyncpg.connect(config["POSTGRES"]["HOME"])
async with connection.transaction():
for f in Path("sql").iterdir():
if f.is_file() and f.suffix == ".sql" and not f.name.startswith("_"):
sql = f.read_text("utf-8")
await connection.execute(sql)
asyncio.run(run_create())
except Exception: # noqa: BLE001
traceback.print_exc()
click.secho("failed to apply SQL due to error", fg="red")
else:
click.secho("Applied SQL tables", fg="green")
if __name__ == "__main__":
main()