mirror of
https://gitverse.ru/kpa39l/vesti.git
synced 2026-09-29 09:55:03 +00:00
Initial import: vesti.nixg.ru — новостной апрув-проект (web, crawler, classifier, publisher, openspec)
This commit is contained in:
@@ -0,0 +1,104 @@
|
||||
# Design: publisher-service
|
||||
|
||||
## Approach
|
||||
|
||||
Выносим публикацию в Telegram из веб-процесса в изолированный FastAPI-микросервис.
|
||||
Сервис — единственная точка, которая знает токен бота (прокси), каналы и Bot API.
|
||||
Остальные компоненты (веб, в будущем cron/боты) вызывают его по HTTP.
|
||||
|
||||
Схема:
|
||||
```
|
||||
vesti-web (:8400) ──POST /api/v1/publish──▶ publisher-service (:8410) ──Bot API (SOCKS5 127.0.0.1:1080)──▶ Telegram
|
||||
approve (человек) │ VESTI_BOT_TOKEN, VESTI_BOT_CHANNELS
|
||||
▼
|
||||
Telegram: @dedinit_vesti (+ другие каналы)
|
||||
```
|
||||
|
||||
## Files
|
||||
|
||||
```bash
|
||||
# Новый сервис
|
||||
services/publisher/
|
||||
├── app/
|
||||
│ ├── __init__.py
|
||||
│ ├── main.py # FastAPI: POST /api/v1/publish, GET /healthz
|
||||
│ ├── config.py # env: VESTI_BOT_TOKEN, TG_PROXY, VESTI_BOT_CHANNELS, LISTEN_PORT
|
||||
│ ├── telegram.py # Bot API клиент (httpx + SOCKS5): send, get_views
|
||||
│ └── channels.py # разбор списка каналов (VESTI_BOT_CHANNELS)
|
||||
├── requirements.txt # fastapi, uvicorn, httpx[socks], pydantic, python-dotenv
|
||||
├── Dockerfile # python:slim, non-root, read-only fs
|
||||
├── docker-compose.yml # сервис, порт 8410, healthcheck, env из .env
|
||||
├── .env.example # без секретов
|
||||
└── README.md # API, порты, запуск, безопасность
|
||||
|
||||
# Изменения
|
||||
web/app.py # approve → HTTP POST в publisher-service (вместо import publisher.bot)
|
||||
.env.example # + VESTI_BOT_CHANNELS, TG_PROXY
|
||||
STATUS.md / TODO.md / WALKTHROUGH.md # статус
|
||||
```
|
||||
|
||||
## Data / Config
|
||||
|
||||
```bash
|
||||
# .env (реальные значения; НЕ коммитить)
|
||||
VESTI_BOT_TOKEN=<токен @dedinit_controller_bot> # уже в .env
|
||||
TG_PROXY=socks5://127.0.0.1:1080 # уже есть
|
||||
VESTI_BOT_CHANNELS=@dedinit_vesti # список каналов, разделитель запятая
|
||||
PUBLISHER_PORT=8410
|
||||
```
|
||||
|
||||
## API
|
||||
|
||||
### POST /api/v1/publish
|
||||
```json
|
||||
{
|
||||
"card": {"text": "...", "media": "/path/to/photo.jpg", "direction": "linux", "lang": "ru"},
|
||||
"channels": ["@dedinit_vesti"] // опционально; default = VESTI_BOT_CHANNELS
|
||||
}
|
||||
```
|
||||
Ответ 200:
|
||||
```json
|
||||
{
|
||||
"ok": true,
|
||||
"results": {
|
||||
"@dedinit_vesti": {"message_id": 123, "media_message_id": 122, "views": 0}
|
||||
},
|
||||
"dry_run": false
|
||||
}
|
||||
```
|
||||
Ошибки: 400 (невалидный card), 502 (Bot API / прокси недоступен), 403 (бот не админ).
|
||||
|
||||
### GET /healthz
|
||||
```json
|
||||
{"status": "ok", "bot": "@dedinit_controller_bot", "proxy": "socks5://127.0.0.1:1080", "channels": ["@dedinit_vesti"]}
|
||||
```
|
||||
Healthcheck: `curl -f http://127.0.0.1:8410/healthz`.
|
||||
|
||||
## Commands
|
||||
|
||||
```bash
|
||||
cd /opt/vesti
|
||||
# dev (без Docker):
|
||||
.venv/bin/pip install -r services/publisher/requirements.txt
|
||||
.venv/bin/uvicorn services.publisher.app.main:app --host 127.0.0.1 --port 8410
|
||||
curl -s http://127.0.0.1:8410/healthz
|
||||
|
||||
# prod (Docker):
|
||||
docker compose -f services/publisher/docker-compose.yml up -d --build
|
||||
curl -s http://127.0.0.1:8410/healthz
|
||||
curl -s -X POST http://127.0.0.1:8410/api/v1/publish \
|
||||
-H 'Content-Type: application/json' \
|
||||
-d '{"card": {"text": "<b>Тест</b>", "direction": "linux", "lang": "ru"}}'
|
||||
|
||||
# переключение веба:
|
||||
# в web/app.py заменить `from publisher.bot import publish_multi` на HTTP-клиент
|
||||
# (или переменная окружения PUBLISHER_URL=http://127.0.0.1:8410)
|
||||
```
|
||||
|
||||
## Verification
|
||||
|
||||
- [ ] `openspec validate publisher-service` → 0 ошибок
|
||||
- [ ] `curl :8410/healthz` → ok, бот, прокси, каналы
|
||||
- [ ] POST /api/v1/publish с тестовой карточкой → message_id в @dedinit_vesti
|
||||
- [ ] Бот не админ / прокси упал → понятная ошибка (4xx/502), веб показывает
|
||||
- [ ] approve в вебе → реальное сообщение в канале (микросервис вызван по HTTP)
|
||||
Reference in New Issue
Block a user