Merge pull request #4 from overspend1/codex/fix-dockerfile-and-compose-for-meme-wrangler-w3lgdz
fix: route compose db connections to postgres service
This commit was merged in pull request #4.
This commit is contained in:
@@ -6,5 +6,7 @@ CHANNEL_ID=
|
||||
POSTGRES_DB=meme_wrangler
|
||||
POSTGRES_USER=meme
|
||||
POSTGRES_PASSWORD=meme
|
||||
POSTGRES_HOST=postgres
|
||||
POSTGRES_PORT=5432
|
||||
MEMEBOT_BACKUP_DIR=/app/backups
|
||||
# MEMEBOT_BACKUP_PASSWORD_HASH=
|
||||
|
||||
@@ -49,6 +49,8 @@ CHANNEL_ID=@yourchannel
|
||||
POSTGRES_DB=meme_wrangler
|
||||
POSTGRES_USER=meme
|
||||
POSTGRES_PASSWORD=meme
|
||||
POSTGRES_HOST=postgres
|
||||
POSTGRES_PORT=5432
|
||||
# Optional: adjust which env file Compose should read (defaults to .ENV)
|
||||
# COMPOSE_ENV_FILE=staging.env
|
||||
# Optional: hash (SHA-256) for replacing the baked-in backup secret
|
||||
@@ -57,6 +59,8 @@ POSTGRES_PASSWORD=meme
|
||||
# DATABASE_URL=postgresql://meme:meme@postgres:5432/meme_wrangler
|
||||
```
|
||||
|
||||
Leave `POSTGRES_HOST=postgres` when running through Docker Compose or Portainer; it's the internal service name that the bot rewrites into any localhost-style URLs so the container connects to the bundled PostgreSQL instance. Override it only if your database lives elsewhere.
|
||||
|
||||
### 2. Build and Run with Docker Compose (Easiest)
|
||||
|
||||
```bash
|
||||
|
||||
@@ -13,7 +13,7 @@ The easiest way to run the bot is using Docker:
|
||||
cp .ENV.example .ENV
|
||||
nano .ENV # Edit with your bot credentials
|
||||
```
|
||||
The compose file now looks for `.ENV` by default so Portainer and other orchestrators can supply secrets without additional flags. Copy `.ENV.example` to `.ENV`, then populate `TELEGRAM_BOT_TOKEN`, `OWNER_ID`, `CHANNEL_ID`, and the Postgres settings. You can still point the stack at a different file by exporting `COMPOSE_ENV_FILE` (e.g. `COMPOSE_ENV_FILE=staging.env docker compose up -d`). Backups are protected by a built-in SHA-256 hash; optionally define `MEMEBOT_BACKUP_PASSWORD_HASH` to replace it.
|
||||
The compose file now looks for `.ENV` by default so Portainer and other orchestrators can supply secrets without additional flags. Copy `.ENV.example` to `.ENV`, then populate `TELEGRAM_BOT_TOKEN`, `OWNER_ID`, `CHANNEL_ID`, and the Postgres settings. Leave `POSTGRES_HOST=postgres` (and `POSTGRES_PORT=5432` unless your database listens elsewhere) when you run inside Docker. The bot rewrites any localhost URLs with that host so the container connects to the bundled PostgreSQL service instead of looping back on itself. You can still point the stack at a different file by exporting `COMPOSE_ENV_FILE` (e.g. `COMPOSE_ENV_FILE=staging.env docker compose up -d`). Backups are protected by a built-in SHA-256 hash; optionally define `MEMEBOT_BACKUP_PASSWORD_HASH` to replace it.
|
||||
|
||||
2. **Run with Docker Compose:**
|
||||
```bash
|
||||
@@ -53,6 +53,9 @@ export TELEGRAM_BOT_TOKEN=123:ABC
|
||||
export OWNER_ID=123456789
|
||||
export CHANNEL_ID=@yourchannel # or -1001234567890
|
||||
export DATABASE_URL=postgresql://meme:meme@localhost:5432/meme_wrangler
|
||||
# Optional pieces that mirror the Docker variables
|
||||
# export POSTGRES_HOST=localhost
|
||||
# export POSTGRES_PORT=5432
|
||||
# Optional: where JSON backups are written
|
||||
# export MEMEBOT_BACKUP_DIR=/path/to/backups
|
||||
# export MEMEBOT_BACKUP_PASSWORD_HASH=<sha256 hash of your backup secret>
|
||||
|
||||
59
bot.py
59
bot.py
@@ -10,6 +10,7 @@ import io
|
||||
import json
|
||||
import logging
|
||||
import os
|
||||
from urllib.parse import urlparse, urlunparse
|
||||
from datetime import datetime, time, timedelta
|
||||
from pathlib import Path
|
||||
from types import SimpleNamespace
|
||||
@@ -89,7 +90,63 @@ def _ensure_ist(dt: datetime) -> datetime:
|
||||
return _ist_localize(dt)
|
||||
return dt.astimezone(IST)
|
||||
|
||||
DATABASE_URL = os.environ.get("DATABASE_URL") or os.environ.get("MEMEBOT_DB")
|
||||
def _build_database_url() -> Optional[str]:
|
||||
"""Derive the database URL from explicit env vars or component pieces."""
|
||||
|
||||
raw_url = os.environ.get("DATABASE_URL") or os.environ.get("MEMEBOT_DB")
|
||||
if not raw_url:
|
||||
user = os.environ.get("POSTGRES_USER")
|
||||
password = os.environ.get("POSTGRES_PASSWORD")
|
||||
db_name = os.environ.get("POSTGRES_DB")
|
||||
host = os.environ.get("POSTGRES_HOST", "localhost")
|
||||
port = os.environ.get("POSTGRES_PORT", "5432")
|
||||
if user and password and db_name:
|
||||
raw_url = (
|
||||
f"postgresql://{quote(user, safe='')}:{quote(password, safe='')}"
|
||||
f"@{host}:{port}/{db_name}"
|
||||
)
|
||||
if raw_url:
|
||||
return _normalize_database_url(raw_url)
|
||||
return None
|
||||
|
||||
|
||||
def _normalize_database_url(url: str) -> str:
|
||||
"""Replace localhost hosts with the configured Postgres host for container runs."""
|
||||
|
||||
host_override = os.environ.get("POSTGRES_HOST")
|
||||
if not host_override:
|
||||
return url
|
||||
|
||||
host_override = host_override.strip()
|
||||
if not host_override or host_override in {"localhost", "127.0.0.1", "::1"}:
|
||||
return url
|
||||
|
||||
parsed = urlparse(url)
|
||||
if parsed.hostname not in {"localhost", "127.0.0.1", "::1"}:
|
||||
return url
|
||||
|
||||
if "@" in parsed.netloc:
|
||||
auth_prefix, _, _ = parsed.netloc.rpartition("@")
|
||||
auth_segment = f"{auth_prefix}@"
|
||||
else:
|
||||
auth_segment = ""
|
||||
|
||||
if parsed.port is not None:
|
||||
port_fragment = f":{parsed.port}"
|
||||
else:
|
||||
port_env = os.environ.get("POSTGRES_PORT")
|
||||
port_fragment = f":{port_env}" if port_env else ""
|
||||
|
||||
target_host = host_override
|
||||
if ":" in target_host and not target_host.startswith("["):
|
||||
target_host = f"[{target_host}]"
|
||||
|
||||
new_netloc = f"{auth_segment}{target_host}{port_fragment}"
|
||||
rebuilt = parsed._replace(netloc=new_netloc)
|
||||
return urlunparse(rebuilt)
|
||||
|
||||
|
||||
DATABASE_URL = _build_database_url()
|
||||
BOT_TOKEN = os.environ.get("TELEGRAM_BOT_TOKEN")
|
||||
OWNER_ID = int(os.environ.get("OWNER_ID", "0"))
|
||||
CHANNEL_ID = os.environ.get("CHANNEL_ID") # @channelusername or -100<id>
|
||||
|
||||
@@ -36,7 +36,9 @@ services:
|
||||
- POSTGRES_DB=${POSTGRES_DB:-meme_wrangler}
|
||||
- POSTGRES_USER=${POSTGRES_USER:-meme}
|
||||
- POSTGRES_PASSWORD=${POSTGRES_PASSWORD:-meme}
|
||||
- DATABASE_URL=${DATABASE_URL:-postgresql://${POSTGRES_USER:-meme}:${POSTGRES_PASSWORD:-meme}@postgres:5432/${POSTGRES_DB:-meme_wrangler}}
|
||||
- POSTGRES_HOST=${POSTGRES_HOST:-postgres}
|
||||
- POSTGRES_PORT=${POSTGRES_PORT:-5432}
|
||||
- DATABASE_URL=${DATABASE_URL:-postgresql://${POSTGRES_USER:-meme}:${POSTGRES_PASSWORD:-meme}@${POSTGRES_HOST:-postgres}:${POSTGRES_PORT:-5432}/${POSTGRES_DB:-meme_wrangler}}
|
||||
- MEMEBOT_BACKUP_DIR=${MEMEBOT_BACKUP_DIR:-/app/backups}
|
||||
volumes:
|
||||
- ./backups:/app/backups
|
||||
|
||||
Reference in New Issue
Block a user