Document platform architecture and Telegram proxy local setup.

Add developer docs for CA/CP/PI flows and wire cp-workers to the host SOCKS proxy so local Telegram auth and parsing work reliably.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-08-15 22:57:07 +03:00
co-authored by Cursor
parent 5f8ed25759
commit 6dff3c1c3d
11 changed files with 1046 additions and 12 deletions
+115
View File
@@ -0,0 +1,115 @@
#!/usr/bin/env python3
"""Интерактивная авторизация Telethon → data/telegram.session.
Запуск через образ cp-workers и host-сеть (локальный xray/Happ на 127.0.0.1:10808):
docker compose stop cp-workers
docker run --rm -it --network host \\
--env-file .env \\
-e TELEGRAM_SESSION_PATH=/data/telegram.session \\
-e TELEGRAM_PROXY_HOST=127.0.0.1 \\
-v \"$PWD/data:/data\" \\
-v \"$PWD/scripts:/scripts:ro\" \\
mapmil-cp-workers \\
python /scripts/telegram_auth.py
docker compose up -d cp-workers
"""
from __future__ import annotations
import asyncio
import os
import sys
from pathlib import Path
ROOT = Path(__file__).resolve().parents[1]
WORKERS = ROOT / "centers" / "parsing" / "workers"
if WORKERS.exists() and str(WORKERS) not in sys.path:
sys.path.insert(0, str(WORKERS))
def _load_dotenv(path: Path) -> None:
if not path.is_file():
return
for line in path.read_text(encoding="utf-8").splitlines():
line = line.strip()
if not line or line.startswith("#") or "=" not in line:
continue
key, _, value = line.partition("=")
key = key.strip()
value = value.strip().strip("'").strip('"')
os.environ.setdefault(key, value)
async def main() -> int:
_load_dotenv(ROOT / ".env")
# Prefer repo-local session when running outside Docker /data mount.
if not os.environ.get("TELEGRAM_SESSION_PATH"):
local = ROOT / "data" / "telegram.session"
os.environ["TELEGRAM_SESSION_PATH"] = str(local)
from workers.sources.telegram_settings import (
create_client,
describe_connection,
get_api_credentials,
get_session_path,
)
api_id, api_hash = get_api_credentials()
session_path = get_session_path()
Path(session_path).parent.mkdir(parents=True, exist_ok=True)
print(f"Сессия: {session_path}")
print(f"Подключение: {describe_connection()}")
client = create_client(session_path, api_id, api_hash)
await client.connect()
if await client.is_user_authorized():
me = await client.get_me()
print(
f"Уже авторизовано: id={me.id} "
f"username={getattr(me, 'username', None) or '—'} "
f"phone={getattr(me, 'phone', None) or '—'}"
)
await client.disconnect()
return 0
print("Сессия не авторизована — вход в Telegram.")
phone = input("Номер телефона (+7...): ").strip()
if not phone:
print("Номер не указан.", file=sys.stderr)
await client.disconnect()
return 1
await client.send_code_request(phone)
code = input("Код из Telegram/SMS: ").strip()
try:
await client.sign_in(phone=phone, code=code)
except Exception as exc:
# 2FA
from telethon.errors import SessionPasswordNeededError
if not isinstance(exc, SessionPasswordNeededError):
raise
password = input("Пароль 2FA: ").strip()
await client.sign_in(password=password)
me = await client.get_me()
print(
f"Готово. Авторизован: id={me.id} "
f"username={getattr(me, 'username', None) or '—'} "
f"phone={getattr(me, 'phone', None) or '—'}"
)
print(f"Файл сессии: {session_path}")
await client.disconnect()
return 0
if __name__ == "__main__":
try:
raise SystemExit(asyncio.run(main()))
except KeyboardInterrupt:
print("\nОтменено.", file=sys.stderr)
raise SystemExit(130)