diff --git a/README.md b/README.md index 6e94255..78b1d67 100644 --- a/README.md +++ b/README.md @@ -39,6 +39,15 @@ docker run -d --name boinc-telegram-bot \ - `/start` или `/status` — сводный дашборд. - Кнопки: «Обновить», «Активные», «Очередь», «Готовы к отправке». +## CI/CD +- Gitea Actions (`.gitea/workflows/publish-images.yml`) собирает образ на пуше в `main` и пушит в `cr.danosito.com/dan/boinc-report-bot` с тегами `latest` и `${{ gitea.sha }}`. Используются `vars.REGISTRY_USER` и `vars.REGISTRY_PASSWORD`. + +## Деплой через docker compose +- Пример compose в `deploy/docker-compose.yml` (host network для доступа к локальному BOINC). +- Создайте `.env` рядом с compose с `TELEGRAM_TOKEN` и, при необходимости, `BOINC_PASSWORD`. +- Для обхода блокировок Telegram указаны прокси-переменные (`HTTP_PROXY`, `HTTPS_PROXY`, `ALL_PROXY`) на локальный http-proxy `http://127.0.0.1:10809` (контейнер `xray`). Если прокси другой, скорректируйте значения или перенесите их в `.env`. +- Запуск: `docker compose -f deploy/docker-compose.yml up -d`. + ## Что под капотом - Python + `python-telegram-bot`. - Получение статуса через `boinccmd --get_tasks` (RPC на BOINC). diff --git a/bot/main.py b/bot/main.py index 5acb5c8..a7c59f4 100644 --- a/bot/main.py +++ b/bot/main.py @@ -41,14 +41,33 @@ def build_keyboard() -> InlineKeyboardMarkup: async def render_view(view: View, client: BoincClient) -> str: + MAX_ITEMS = 20 snapshot = await client.fetch_snapshot() if view == "dashboard": return format_dashboard(snapshot) if view == "active": - return format_tasks_section("Активные задачи", snapshot.active) + extra = len(snapshot.active) - MAX_ITEMS + text = format_tasks_section("Активные задачи", snapshot.active[:MAX_ITEMS]) + if extra > 0: + text += f"\n... и еще {extra} задач(и)" + return text if view == "queued": - return format_tasks_section("Ожидают запуска", snapshot.queued) - return format_tasks_section("Готовы к отправке", snapshot.completed) + extra = len(snapshot.queued) - MAX_ITEMS + text = format_tasks_section("Ожидают запуска", snapshot.queued[:MAX_ITEMS]) + if extra > 0: + text += f"\n... и еще {extra} задач(и)" + return text + extra = len(snapshot.completed) - MAX_ITEMS + text = format_tasks_section("Готовы к отправке", snapshot.completed[:MAX_ITEMS]) + if extra > 0: + text += f"\n... и еще {extra} задач(и)" + return text + + +def clamp_message(text: str, limit: int = 3900) -> str: + if len(text) <= limit: + return text + return text[: limit - 80] + "\n...сообщение укорочено, отфильтруйте список" async def start_handler(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None: @@ -63,7 +82,7 @@ async def callback_handler(update: Update, context: ContextTypes.DEFAULT_TYPE) - client: BoincClient = context.bot_data["boinc_client"] view: View = query.data if query.data in {"dashboard", "active", "queued", "completed"} else "dashboard" try: - text = await render_view(view, client) + text = clamp_message(await render_view(view, client)) except Exception as exc: # broad catch to show meaningful message in chat logger.exception("Error rendering view %s", view) text = f"Не удалось получить данные: {exc}" diff --git a/deploy/docker-compose.yml b/deploy/docker-compose.yml index ab5aaf1..9602dba 100644 --- a/deploy/docker-compose.yml +++ b/deploy/docker-compose.yml @@ -8,4 +8,8 @@ services: environment: - BOINC_HOST=127.0.0.1 - BOINC_PORT=31416 + - HTTP_PROXY=http://127.0.0.1:10809 + - HTTPS_PROXY=http://127.0.0.1:10809 + - ALL_PROXY=http://127.0.0.1:10809 + - NO_PROXY=localhost,127.0.0.1 command: ["python", "-m", "bot.main"]