# Обзор архитектуры системы Этот документ — единый и актуальный источник информации по платформе: архитектура, протоколы, данные, конфигурация, сценарии, эксплуатация. Заменяет собой разрозненные и устаревшие документы. ## Содержание - Компоненты и топология - Децентрализованный слой (членство, оценка размера сети, репликации, метрики) - Загрузка и конвертация контента - Просмотр и покупка контента (UI/UX требования) - API (ключевые эндпойнты и полезная нагрузка) - Ключи и схемы данных (DHT) - Конфигурация и значения по умолчанию - Наблюдаемость и метрики - Диаграммы последовательностей (Mermaid) - Сборка и тестирование --- ## Компоненты и топология - Backend API: сервис на Sanic (Python) с бота́ми Telegram; база данных PostgreSQL (SQLAlchemy + Alembic). - Хранилище: локальная ФС (uploads/derivatives); IPFS (kubo) для ретривания/пининга; tusd (resumable upload). - Конвертеры: воркеры (ffmpeg) в контейнерах — `convert_v3`, `convert_process`. - Frontend: SPA (Vite + TypeScript), отдается nginx-контейнером. - Децентрализованный слой: встроенный DHT (в процессе) — членство, лизы реплик, метрики контента. ```mermaid flowchart LR Client -- TWA/HTTP --> Frontend Frontend -- REST --> API[Backend API] API -- tus hooks --> tusd API -- SQL --> Postgres API -- IPC --> Workers[Converters] API -- IPFS --> IPFS API -- DHT --> DHT[(In-Process DHT)] DHT -- CRDT Merge --> DHT ``` --- ## Децентрализованный слой ### Идентификаторы и версии - NodeID = blake3(Ed25519 публичного ключа) — шестнадцатеричная строка (256 бит). - ContentID = blake3(зашифрованного блоба) — неизменяемый идентификатор контента. - schema_version = v1 — фиксируется во всех DHT-ключах/записях. ### Членство (membership) - Рукопожатие `/api/v1/network.handshake` — запрос подписан Ed25519; верифицируется на стороне получателя. Без корректной подписи — 400 BAD_SIGNATURE. - Полезная нагрузка включает: сведения о ноде (версия, возможности, IPFS), метрики, массив известных публичных нод, квитанции достижимости (reachability_receipts: issuer, target, ASN, timestamp, signature). - Состояние членства — CRDT LWW-Set (добавления/удаления) с TTL (`DHT_MEMBERSHIP_TTL=600` сек), плюс HyperLogLog для оценки мощности (N_local). - Фильтрация «островов»: ноды с `reachability_ratio < q` (по умолчанию `q=0.6`) исключаются при вычислении N_estimate и выборе реплик. - Итоговая оценка `N_estimate = max(валидных N_local от пиров)`. ```mermaid sequenceDiagram participant A as Узел A participant B as Узел B A->>B: POST /network.handshake {nonce, ts, node, receipts, signature} B->>B: верификация ts/nonce, подписи B->>B: upsert member; merge(receipts) B-->>A: {node, known_public_nodes, n_estimate, server_signature} A->>A: merge; N_estimate = max(N_local, полученные) ``` ### Репликации и лизы - Выбор префикса: `p = max(0, round(log2(N_estimate / R_target)))`, где `R_target ≥ 3` (по умолчанию 3). - Ответственные ноды: чьи первые `p` бит NodeID совпадают с первыми `p` бит ContentID. - Лидер — минимальный NodeID среди ответственных. - Лидер выдаёт `replica_leases` (TTL=600 сек), соблюдая разнообразие: не менее 3 разных первых октетов IP и, если доступно, 3 разных ASN. - Ранжирование кандидатов — rendezvous score `blake3(ContentID || NodeID)`. - Сердцебиение (heartbeat) держателей — каждые 60 сек; 3 пропуска → признать down и переназначить ≤180 сек. - Недобор/перебор фиксируются в `conflict_log` и прометеус‑метриках. ```mermaid stateDiagram-v2 [*] --> Discover Discover: Рукопожатия + квитанции Discover --> Active: TTL & кворм ASN Active --> Leader: Выбор лидера префикса p Leader --> Leased: Выдача лизов (diversity) Leased --> Monitoring: Heartbeat 60s Monitoring --> Reassign: 3 пропуска Reassign --> Leased ``` ### Метрики (окна) - На событии просмотра формируются дельты CRDT: - PN‑Counter — количество просмотров; - HyperLogLog — уникальные ViewID (ViewID = blake3(ContentID || соль_устройства)); - G‑Counter — watch_time, bytes_out, количество завершений. - Окно по часу (`DHT_METRIC_WINDOW_SEC`), ключ `MetricKey = blake3(ContentID || WindowID)`. - Мерджи коммутативные, детерминированные. --- ## Загрузка и конвертация контента 1) Клиент грузит в `tusd` (resumable). Бэкенд получает HTTP‑hooks `/api/v1/upload.tus-hook`. 2) Создается запись в БД для зашифрованного контента, воркеры размещают производные: - для медиа — preview/low/high; - для бинарей — оригинал (доступен только при наличии лицензии). 3) `/api/v1/content.view` возвращает `display_options` и агрегированное состояние конвертации/загрузки. ```mermaid sequenceDiagram participant C as Клиент participant T as tusd participant B as Бэкенд participant W as Воркеры participant DB as PostgreSQL C->>T: upload T->>B: hooks (pre/post-finish) B->>DB: create content B->>W: очередь конвертации W->>DB: derive/previews C->>B: GET /content.view B->>DB: resolve derivatives B-->>C: display_options + status ``` --- ## Просмотр и покупка (UI/UX) - `/api/v1/content.view/` определяет доступные отображения: - бинарный контент без превью — оригинал только при наличии лицензии; - аудио/видео — для неавторизованных preview/low, для имеющих доступ — decrypted_low/high. - В процессе конвертации фронтенд показывает статус «processing», без фальшивых ссылок. - Обложка (cover): - фиксированный квадратный слот; изображение «вписывается» без растягивания/искажения; - пустые области не заполняются чёрным — фон совпадает с фоном страницы. - Кнопки «Купить за TON/Stars»: всегда в одной строке (без горизонтального/вертикального скролла контента на малых экранах). ```mermaid flowchart LR View[content.view] --> Resolve[Определение деривативов] Resolve --> Ready{Готово?} Ready -- Нет --> Info[Статус: processing/pending] Ready -- Да --> Options Options -- Бинарь + нет лицензии --> HideOriginal[Скрыть оригинал] Options -- Медиа + нет лицензии --> PreviewLow[preview/low] Options -- Есть лицензия --> Decrypted[decrypted low/high|original] ``` --- ## API (ключевые) - `GET /api/system.version` — актуальность сервиса. - `POST /api/v1/network.handshake` — обмен членством (обязательная Ed25519‑подпись запроса). Пример запроса: ```json { "version": "3.0.0", "schema_version": "v1", "public_key": "", "node_id": "", "public_host": "https://node.example", "node_type": "public|private", "metrics": {"uptime_sec": 123, "content_count": 42}, "capabilities": {"accepts_inbound": true, "is_bootstrap": false}, "ipfs": {"multiaddrs": ["/ip4/.../tcp/4001"], "peer_id": "..."}, "known_public_nodes": [], "reachability_receipts": [], "timestamp": 1710000000, "nonce": "", "signature": "" } ``` - `GET /api/v1/content.view/` — `display_options`, `status`, `conversion`. - `GET /api/v1.5/storage/` — отдача файла. - `GET /metrics` — экспозиция метрик Prometheus (либо fallback‑дамп счётчиков). --- ## Ключи и схемы DHT - `MetaKey(content_id)` — метаданные репликаций: - `replica_leases`: карта `{lease_id -> {node_id, issued_at, expires_at, asn, ip_first_octet, heartbeat_at, score}}`; - `leader`: NodeID лидера; `revision`: номер ревизии; - `conflict_log`: массив событий `UNDER/OVER/LEASE_EXPIRED` и т.п. - `MembershipKey(node_id)` — членство: - `members`: LWW‑Set; `receipts`: LWW‑Set; - `hll`: HyperLogLog; `reports`: карты локальных оценок N; - `logical_counter`: логический счётчик для LWW‑доминации. - `MetricKey(content_id, window_id)` — метрики окна: - `views`: PN‑Counter; `unique`: HLL; `watch_time`, `bytes_out`, `completions`: G‑Counters. Все записи подписываются и сливаются детерминированно: CRDT‑логика + LWW‑доминация (`logical_counter`, `timestamp`, `node_id`). --- ## Конфигурация и значения по умолчанию - Сеть/рукопожатия: `NODE_PRIVACY`, `PUBLIC_HOST`, `HANDSHAKE_INTERVAL_SEC`, `NETWORK_TLS_VERIFY`, IPFS‑пиры/бустрапы. - DHT: - `DHT_MIN_RECEIPTS=5`, `DHT_MIN_REACHABILITY=0.6`, `DHT_MEMBERSHIP_TTL=600`; - `DHT_REPLICATION_TARGET=3`, `DHT_LEASE_TTL=600`, - `DHT_HEARTBEAT_INTERVAL=60`, `DHT_HEARTBEAT_MISS_THRESHOLD=3`; - `DHT_MIN_ASN=3`, `DHT_MIN_IP_OCTETS=3`, - `DHT_METRIC_WINDOW_SEC=3600`. - Конвертация: квоты `CONVERT_*`, `MAX_CONTENT_SIZE_MB`. Примечание: PoW‑допуски и Kademlia k‑buckets на текущем этапе не активированы в коде — заложены в дизайн и могут быть реализованы отдельно. --- ## Наблюдаемость и метрики Prometheus: - `dht_replication_under_total`, `dht_replication_over_total`, `dht_leader_changes_total`; - `dht_merge_conflicts_total`; - `dht_view_count_total`, `dht_unique_view_estimate`, `dht_watch_time_seconds`. Логи: структурированные ошибки HTTP (с id), `conflict_log` по репликациям, события регистрации нод. --- ## Диаграммы последовательностей (сводные) ### Обновление N_estimate ```mermaid sequenceDiagram participant Peer participant Membership participant DHT Peer->>Membership: handshake(payload, receipts) Membership->>Membership: merge LWW/receipts Membership->>Membership: update HLL и N_local Membership->>DHT: persist MembershipKey Membership->>Membership: N_estimate = max(valid reports) ``` ### Выбор лидера и выдача лизов ```mermaid sequenceDiagram participant L as Leader participant R as Responsible L->>L: p = round(log2(N_est/R)) L->>R: rank by rendezvous(ContentID, NodeID) L->>L: assign leases (diversity) R-->>L: heartbeat/60s L->>L: reassign on 3 misses ``` ### Публикация метрик окна ```mermaid sequenceDiagram participant C as Client participant API as Backend participant M as Metrics participant D as DHT C->>API: GET content.view?watch_time,bytes_out API->>M: record_view(delta) M->>D: merge MetricKey(ContentID, window) API-->>Prom: /metrics ``` --- ## Сборка и тестирование ```bash # Старт окружения (пример для /home/configs) docker compose -f /home/configs/docker-compose.yml --env-file /home/configs/.env up -d --build # Тесты слоя DHT cd uploader-bot python3 -m unittest discover -s tests/dht ```