Skip to content

Commit

Permalink
Migrate to YAML (#165)
Browse files Browse the repository at this point in the history
  • Loading branch information
No767 authored Apr 20, 2024
1 parent 348bd23 commit 8c826d3
Show file tree
Hide file tree
Showing 20 changed files with 162 additions and 263 deletions.
4 changes: 4 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
# ENV files
**/.env

# Configuration Files
**/.yml
**/.yaml

# Cache files
**/__pycache__
**/*.py[cod]
Expand Down
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,9 @@ ENV/
env.bak/
venv.bak/

# Configuration file
config.yml

# Spyder project settings
.spyderproject
.spyproject
Expand Down
22 changes: 8 additions & 14 deletions bot/catherinebot.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,23 +6,20 @@
import discord
from aiohttp import ClientSession
from catherinecore import Catherine
from dotenv import load_dotenv
from libs.utils import CatherineLogger, KeyboardInterruptHandler, read_env
from libs.utils.config import CatherineConfig
from libs.utils.handler import KeyboardInterruptHandler
from libs.utils.logger import CatherineLogger

if os.name == "nt":
from winloop import run
else:
from uvloop import run

load_dotenv()
config_path = Path(__file__).parent / "config.yml"
config = CatherineConfig(config_path)

ENV_PATH = Path(__file__).parent / ".env"

TOKEN = os.environ["TOKEN"]
DEV_MODE = os.getenv("DEV_MODE") in ("True", "TRUE")
IPC_SECRET_KEY = os.environ["IPC_SECRET_KEY"]
IPC_HOST = os.environ["IPC_HOST"]
POSTGRES_URI = os.environ["POSTGRES_URI"]
TOKEN = config["bot"]["token"]
POSTGRES_URI = config["postgres"]["uri"]

intents = discord.Intents.default()
intents.members = True
Expand All @@ -33,13 +30,10 @@ async def main() -> None:
dsn=POSTGRES_URI, min_size=25, max_size=25, command_timeout=60
) as pool:
async with Catherine(
config=read_env(ENV_PATH),
ipc_secret_key=IPC_SECRET_KEY,
ipc_host=IPC_HOST,
config=config,
intents=intents,
session=session,
pool=pool,
dev_mode=DEV_MODE,
) as bot:
bot.loop.add_signal_handler(signal.SIGTERM, KeyboardInterruptHandler(bot))
bot.loop.add_signal_handler(signal.SIGINT, KeyboardInterruptHandler(bot))
Expand Down
94 changes: 21 additions & 73 deletions bot/catherinecore.py
Original file line number Diff line number Diff line change
@@ -1,19 +1,19 @@
import logging
from pathlib import Path
from typing import Dict, Optional

import asyncpg
import discord
from aiohttp import ClientSession
from cogs import EXTENSIONS, VERSION
from discord.ext import commands, ipcx
from discord.ext import commands
from libs.cog_utils.prometheus_metrics import (
Metrics,
create_gauges,
create_guild_gauges,
fill_gauges,
)
from libs.ui.pronouns import ApprovePronounsExampleView
from libs.utils.config import CatherineConfig
from libs.utils.reloader import Reloader
from libs.utils.tree import CatherineCommandTree
from prometheus_async.aio.web import start_http_server
Expand All @@ -22,13 +22,10 @@
class Catherine(commands.Bot):
def __init__(
self,
config: Dict[str, Optional[str]],
ipc_secret_key: str,
ipc_host: str,
config: CatherineConfig,
intents: discord.Intents,
session: ClientSession,
pool: asyncpg.Pool,
dev_mode: bool = False,
*args,
**kwargs,
) -> None:
Expand All @@ -44,56 +41,15 @@ def __init__(
*args,
**kwargs,
)
self.dev_mode = dev_mode
self.logger: logging.Logger = logging.getLogger("catherine")
self.ipc = ipcx.Server(self, host=ipc_host, secret_key=ipc_secret_key)
self.reloader = Reloader(self, Path(__file__).parent)
self.metrics: Metrics = create_gauges()
self._ipc_host = ipc_host
self._metrics_port = 6789
self._config = config
self._session = session
self._pool = pool

@property
def config(self) -> Dict[str, Optional[str]]:
"""Global configuration dictionary read from .env files
This is used to access API keys, and many others from the bot.
Returns:
Dict[str, str]: A dictionary of configuration values
"""
return self._config

@property
def session(self) -> ClientSession:
"""A global web session used throughout the lifetime of the bot
Returns:
ClientSession: AIOHTTP's ClientSession
"""
return self._session

@property
def pool(self) -> asyncpg.Pool:
"""A global object managed throughout the lifetime of Kumiko
Holds the asyncpg pool for connections
Returns:
asyncpg.Pool: asyncpg connection pool
"""
return self._pool

@property
def version(self) -> str:
"""The version of Catherine
Returns:
str: The version of Catherine
"""
return str(VERSION)
self.session = session
self.pool = pool
self.version = str(VERSION)
self._dev_mode = config.bot.get("dev_mode", False)
self._reloader = Reloader(self, Path(__file__).parent)
self._prometheus = config.bot.get("prometheus", {})
self._prometheus_enabled = self._prometheus.get("enabled", False)

# Basically silence all prefixed errors
async def on_command_error(
Expand All @@ -110,34 +66,26 @@ async def setup_hook(self) -> None:

await self.load_extension("jishaku")

await self.ipc.start()
await start_http_server(addr=self._ipc_host, port=6789)
self.logger.info(
"Prometheus Server started on %s:%s", self._ipc_host, self._metrics_port
)
if self._prometheus_enabled:
prom_host = self._prometheus.get("host", "127.0.0.1")
prom_port = self._prometheus.get("port", 6789)

await start_http_server(addr=prom_host, port=prom_port)
self.logger.info("Prometheus Server started on %s:%s", prom_host, prom_port)

fill_gauges(self)
fill_gauges(self)

if self.dev_mode:
self.reloader.start()
if self._dev_mode:
self._reloader.start()

async def on_ready(self):
if not hasattr(self, "uptime") and not hasattr(self, "guild_metrics_created"):
if not hasattr(self, "uptime"):
self.uptime = discord.utils.utcnow()
elif self._prometheus_enabled and not hasattr(self, "guild_metrics_created"):
self.guild_metrics_created = create_guild_gauges(self)

curr_user = None if self.user is None else self.user.name
self.logger.info(f"{curr_user} is fully ready!")

async def on_ipc_ready(self):
self.logger.info(
"Standard IPC Server started on %s:%s", self.ipc.host, self.ipc.port
)
self.logger.info(
"Multicast IPC server started on %s:%s",
self.ipc.host,
self.ipc.multicast_port,
)

async def on_reloader_ready(self):
self.logger.info("Dev mode is enabled. Loaded Reloader")
18 changes: 0 additions & 18 deletions bot/cogs/ipc.py

This file was deleted.

8 changes: 1 addition & 7 deletions bot/libs/cog_utils/tonetags/utils.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
import re
from typing import List, Union

from better_profanity import profanity

from .structs import SimilarTonetags


Expand All @@ -20,11 +18,7 @@ def parse_tonetag(tonetag: str) -> str:

def validate_tonetag(tonetag: str) -> bool:
"""Validates a tonetag"""
return (
len(tonetag) < 4
and re.fullmatch(r"^[a-zA-Z]*$", tonetag) is not None
and profanity.contains_profanity(tonetag) is False
)
return len(tonetag) < 4 and re.fullmatch(r"^[a-zA-Z]*$", tonetag) is not None


def format_similar_tonetags(rows: Union[List[SimilarTonetags], None]) -> str:
Expand Down
2 changes: 1 addition & 1 deletion bot/libs/utils/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,5 +12,5 @@
from .reloader import Reloader as Reloader
from .time import human_timedelta as human_timedelta
from .tree import CatherineCommandTree as CatherineCommandTree
from .utils import is_docker as is_docker, read_env as read_env
from .utils import is_docker as is_docker
from .view import CatherineView as CatherineView
52 changes: 52 additions & 0 deletions bot/libs/utils/config.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
from pathlib import Path
from typing import Any, Generic, Optional, TypeVar, Union, overload

import yaml

_T = TypeVar("_T")


class CatherineConfig(Generic[_T]):
def __init__(self, path: Path):
self.path = path
self._config: dict[str, Union[_T, Any]] = {}
self.load_from_file()

def load_from_file(self) -> None:
try:
with open(self.path, "r") as f:
self._config: dict[str, Union[_T, Any]] = yaml.safe_load(f.read())
except FileNotFoundError:
self._config = {}

@property
def bot(self) -> _T:
return self._config["bot"]

@property
def postgres(self) -> _T:
return self._config["postgres"]

@overload
def get(self, key: Any) -> Optional[Union[_T, Any]]:
...

@overload
def get(self, key: Any, default: Any) -> Union[_T, Any]:
...

def get(self, key: Any, default: Any = None) -> Optional[Union[_T, Any]]:
"""Retrieves a config entry."""
return self._config.get(str(key), default)

def __contains__(self, item: Any) -> bool:
return str(item) in self._config

def __getitem__(self, item: Any) -> Union[_T, Any]:
return self._config[str(item)]

def __len__(self) -> int:
return len(self._config)

def all(self) -> dict[str, Union[_T, Any]]:
return self._config
10 changes: 0 additions & 10 deletions bot/libs/utils/utils.py
Original file line number Diff line number Diff line change
@@ -1,18 +1,8 @@
import os
from pathlib import Path
from typing import Dict, Optional

from dotenv import dotenv_values


def is_docker() -> bool:
path = "/proc/self/cgroup"
return os.path.exists("/.dockerenv") or (
os.path.isfile(path) and any("docker" in line for line in open(path))
)


def read_env(path: Path, read_from_file: bool = True) -> Dict[str, Optional[str]]:
if is_docker() or read_from_file is False:
return {**os.environ}
return {**dotenv_values(path)}
14 changes: 14 additions & 0 deletions config-example.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# Catherine-Chan's main configuration
bot:
token: "BOT TOKEN HERE"
dev_mode: False

prometheus:
enabled: False
host: "127.0.0.1"
port: 6789

# Postgres Configuration
postgres:
revision: "rev5"
uri: "postgres://username:password@127.0.0.1:5432/postgres"
4 changes: 2 additions & 2 deletions docs/requirements.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
sphinx==7.3.7
sphinx>=7.3.7
furo>=2023.8.19
sphinx-copybutton>=0.5.2
sphinxext-opengraph>=0.8.2
sphinxext-opengraph>=0.8.2
1 change: 0 additions & 1 deletion docs/source/guides/dev/requirements.rst
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ Before you get started, please ensure you have the following installed:

- `Git <https://git-scm.com>`_
- `Python 3 <https://python.org>`_
- `Poetry <https://python-poetry.org>`_
- `Docker <https://docker.com>`_
- Discord Account + App

Expand Down
Loading

0 comments on commit 8c826d3

Please sign in to comment.