diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..d7bc9bd --- /dev/null +++ b/Dockerfile @@ -0,0 +1,28 @@ +FROM python:3.11-bookworm as builder + +RUN pip install poetry==1.7.1 + +ENV POETRY_NO_INTERACTION=1 \ + POETRY_VIRTUALENVS_IN_PROJECT=1 \ + POETRY_VIRTUALENVS_CREATE=1 \ + POETRY_CACHE_DIR=/tmp/poetry_cache + +WORKDIR /app + +COPY pyproject.toml poetry.lock ./ +RUN touch README.md + +RUN --mount=type=cache,target=$POETRY_CACHE_DIR poetry install --without dev --no-root + +FROM python:3.11-slim-bookworm as runtime + +ENV VIRTUAL_ENV=/app/.venv \ + PATH="/app/.venv/bin:$PATH" + +RUN mkdir /data + +COPY --from=builder ${VIRTUAL_ENV} ${VIRTUAL_ENV} + +COPY src/rollbot ./rollbot + +ENTRYPOINT ["python", "-m", "rollbot"] diff --git a/poetry.lock b/poetry.lock index 168e627..3d51767 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,4 +1,4 @@ -# This file is automatically @generated by Poetry 1.7.0 and should not be changed by hand. +# This file is automatically @generated by Poetry 1.7.1 and should not be changed by hand. [[package]] name = "aiodns" @@ -637,13 +637,13 @@ files = [ [[package]] name = "idna" -version = "3.4" +version = "3.6" description = "Internationalized Domain Names in Applications (IDNA)" optional = false python-versions = ">=3.5" files = [ - {file = "idna-3.4-py3-none-any.whl", hash = "sha256:90b77e79eaa3eba6de819a0c442c0b4ceefc341a7a2ab77d7562bf49f425c5c2"}, - {file = "idna-3.4.tar.gz", hash = "sha256:814f528e8dead7d329833b91c5faa87d60bf71824cd12a7530b5526063d02cb4"}, + {file = "idna-3.6-py3-none-any.whl", hash = "sha256:c05567e9c24a6b9faaa835c4821bad0590fbb9d5779e7caa6e1cc4978e7eb24f"}, + {file = "idna-3.6.tar.gz", hash = "sha256:9ecdbbd083b06798ae1e86adcbfe8ab1479cf864e4ee30fe4e46a003d12491ca"}, ] [[package]] @@ -1217,21 +1217,6 @@ files = [ [package.dependencies] six = ">=1.5" -[[package]] -name = "redis" -version = "5.0.1" -description = "Python client for Redis database and key-value store" -optional = false -python-versions = ">=3.7" -files = [ - {file = "redis-5.0.1-py3-none-any.whl", hash = "sha256:ed4802971884ae19d640775ba3b03aa2e7bd5e8fb8dfaed2decce4d0fc48391f"}, - {file = "redis-5.0.1.tar.gz", hash = "sha256:0dab495cd5753069d3bc650a0dde8a8f9edde16fc5691b689a566eda58100d0f"}, -] - -[package.extras] -hiredis = ["hiredis (>=1.0.0)"] -ocsp = ["cryptography (>=36.0.1)", "pyopenssl (==20.0.1)", "requests (>=2.26.0)"] - [[package]] name = "ruff" version = "0.1.6" @@ -1374,5 +1359,5 @@ multidict = ">=4.0" [metadata] lock-version = "2.0" -python-versions = "==3.11.6" -content-hash = "ad8ef5e0854c5c365ed25fce2c7ae1ce27015f53e60790a674daa84efcf1eeb0" +python-versions = "~3.11" +content-hash = "0c562421af40bfe00ea4c507399ab4aacf1ff08c394c828f6ab29d32376c3ed5" diff --git a/pyproject.toml b/pyproject.toml index cf698e8..7503f8a 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -9,12 +9,11 @@ packages = [ ] [tool.poetry.dependencies] -python = "==3.11.6" -py-cord = {extras = ["speed"], version="*"} -numpy = "^1.22.1" -matplotlib = "^3.5.1" -lark = "*" -redis = "^5" +python = "~3.11" +py-cord = {extras = ["speed"], version="^2"} +numpy = "^1" +matplotlib = "^3" +lark = "^1" [tool.poetry.group.dev.dependencies] ruff = "^0.1.6" diff --git a/src/rollbot/__main__.py b/src/rollbot/__main__.py new file mode 100644 index 0000000..9b8f214 --- /dev/null +++ b/src/rollbot/__main__.py @@ -0,0 +1,18 @@ +import logging +import os + +from rollbot.bot import bot +from rollbot.db import SQLiteDB +from rollbot.varenv import var_env_provider + + +logging.basicConfig( + level=logging.INFO, + format="[%(levelname)s] %(asctime)s - %(message)s", +) +token = os.environ["DISCORD_TOKEN"] +db = SQLiteDB(os.environ["SQLITE_PATH"]) +var_env_provider.set_db(db) + +bot.run(token) +db.close() diff --git a/src/rollbot/config.py b/src/rollbot/config.py deleted file mode 100644 index 6441cb2..0000000 --- a/src/rollbot/config.py +++ /dev/null @@ -1,30 +0,0 @@ -import logging -import json -import os - -from .db import make_db -from .varenv import var_env_provider - - -class Config: - def __init__(self, config: str | dict[str, str]): - if isinstance(config, str): - with open(config) as f: - config = json.load(f) - - if "discord_token" in config: - self.token = config["discord_token"] - elif "discord_token_env_var" in config: - self.token = os.environ[config["discord_token_env_var"]] - else: - logging.error("Config could not aquire a discord token!") - self.token = "" - - if "redis_url" in config: - self.db = make_db(config["redis_url"]) - elif "redis_url_env_var" in config: - self.db = make_db(os.environ[config["redis_url_env_var"]]) - else: - self.db = None - - var_env_provider.set_db(self.db) diff --git a/src/rollbot/db.py b/src/rollbot/db.py index b48b02f..6ce523b 100644 --- a/src/rollbot/db.py +++ b/src/rollbot/db.py @@ -1,7 +1,38 @@ -import redis -from urllib.parse import urlparse +import sqlite3 +import json -def make_db(url): - url = urlparse(url) - return redis.Redis(host=url.hostname, port=url.port, password=url.password) +class SQLiteDB: + def __init__(self, database_url: str): + self.conn = sqlite3.connect(database_url) + self.cursor = self.conn.cursor() + + # Create a table for key-value pairs if it doesn't exist + self.cursor.execute( + """ + CREATE TABLE IF NOT EXISTS key_value ( + key TEXT PRIMARY KEY, + value TEXT + ) + """ + ) + self.conn.commit() + + def get(self, key: str) -> dict[str, str]: + self.cursor.execute("SELECT value FROM key_value WHERE key = ?", (key,)) + result = self.cursor.fetchone() + if result is not None: + return json.loads(result[0]) + else: + return {} + + def set(self, key: str, value: dict[str, str]) -> None: + serialized_value = json.dumps(value) + self.cursor.execute( + "INSERT OR REPLACE INTO key_value (key, value) VALUES (?, ?)", + (key, serialized_value), + ) + self.conn.commit() + + def close(self): + self.conn.close() diff --git a/src/rollbot/varenv/__init__.py b/src/rollbot/varenv/__init__.py index cedd8cf..616184b 100644 --- a/src/rollbot/varenv/__init__.py +++ b/src/rollbot/varenv/__init__.py @@ -1,9 +1,8 @@ -from typing import Optional, Dict, Any -import json +from rollbot.db import SQLiteDB class VarEnv: - def __init__(self, name: str, items: Dict[str, str] = None): + def __init__(self, name: str, items: dict[str, str] = None) -> None: self.dirty = False self.name = name self.items = items or {} @@ -15,13 +14,13 @@ def set(self, key: str, value: str) -> None: self.items[key] = value self.dirty = True - def get(self, key: str) -> Optional[str]: + def get(self, key: str) -> str | None: return self.items.get(key) class VarEnvProvider: def __init__(self): - self.db: Any = None + self.db: SQLiteDB | None = None def set_db(self, db): self.db = db @@ -29,14 +28,14 @@ def set_db(self, db): def get(self, name: str) -> VarEnv: if not self.db: return VarEnv(name) - data = self.db.get(f"VarEnv[{name}]") + data = self.db.get(name) if not data: return VarEnv(name) - return VarEnv(name, json.loads(data)) + return VarEnv(name, data) - def update(self, varenv: VarEnv): + def update(self, varenv: VarEnv) -> None: if varenv.dirty and self.db is not None: - self.db.set(f"VarEnv[{varenv.name}]", json.dumps(varenv.items)) + self.db.set(varenv.name, varenv.items) var_env_provider = VarEnvProvider()