Ztorrent/TODO.md

5.1 KiB
Raw Blame History

ZTorrent — TODO & Контекст улучшений

Цель: довести ztorrent до уровня qBittorrent по функциональности и скорости. Ведётся автоматически — отражает актуальное состояние реализации.


Архитектура проекта

internal/
  torrent/
    engine.go          — основной движок: загрузка торрента, воркеры, координация
    peerwire.go        — BitTorrent wire protocol: handshake, download piece, messages
    piecescheduler.go  — выбор кусков (rarest-first), endgame mode
    debug.go           — debugf helper
  tracker/
    tracker.go         — HTTP + UDP announce
  torrentfile/
    torrentfile.go     — парсинг .torrent (bencode)
  app/
    controller.go      — тонкая обёртка над Engine для UI
ui/
  ui.go               — Bubble Tea TUI (welcome, loading, dashboard)
  styles.go           — цветовая палитра

P0 — Критичные ГОТОВО

  • Resume downloadcreateOrOpenPartFile() без O_TRUNC + SHA-1 верификация
  • Keep-alivekeepaliveLoop() горутина, 90с, msgCancel=8
  • Endgame modepieceDone broadcast + SendCancel() при дублировании

P1 — Производительность ГОТОВО

  • Adaptive pipeline — depth 464, пересчёт каждые 4 блока по RTT+BW
  • IPv6 compact peersparsePeers6() в tracker.go
  • Rate limitingrateLimitedConn, SetDownloadLimit/SetUploadLimit
  • Bitmap resume data.part.bitmap JSON, asyncSaveBitmap() в heartbeat

Баги ПОФИКШЕНО

  • announce пустой — BEP 12 fallback: берём первый URL из announce-list > torrentfile.goprimaryAnnounce fallback в Open()

  • peerBackoff O(n) → O(1) через peerIdx map[string]int > Добавлен Engine.peerIdx, peerByKey() helper > Все peer-методы: setPeerState, setPeerError, peerBackoff, recordPieceComplete

  • Скорость без EWMA → сглаживание α=0.3 в updateSpeedLocked() > downloadSpeed = 0.3*sample + 0.7*prev

  • Reannounce блокирует heartbeat → запускается в отдельной горутине > heartbeatTicker.Cgo func() { refreshPeersFromTrackers() }() > Таймаут уменьшен с 20с до 15с

Фича РЕАЛИЗОВАНО

  • Incoming connections — TCP listener на :6881 > listenIncoming() + handleIncoming() в engine.go > Handshake верификация (info_hash), регистрация в peerIdx > Входящие пиры подхватываются startWorkers на следующем heartbeat тике

P2 — Долгосрочные (не начато)

  • DHT (BEP 5) — Kademlia DHT для поиска пиров без трекера > Новый пакет internal/dht/ — реализовано!

  • Магнет-ссылки (BEP 9)magnet:?xt=..., ut_metadata extension > Новый пакет internal/magnet/ — средняя сложность

  • Seeding / upload (tit-for-tat) — раздача после завершения > peerwire.go → обработка msgRequest, отправка msgPiece

  • PEX (BEP 11) — Peer Exchange между пирами > Extension handshake + ut_pex message


Технические решения

peerIdx — O(1) peer lookup

Engine.peers    []PeerStatus         // слайс со всеми пирами
Engine.peerIdx  map[string]int       // "host:port" → индекс в слайсе

buildPeerIdx(peers)                  // строится при LoadTorrent и reannounce
peerByKey(key) *PeerStatus           // O(1) под e.mu

EWMA сглаживание скорости

updateSpeedLocked():
  sample = delta_bytes / elapsed_sec
  speed  = 0.3*sample + 0.7*prev_speed   // α=0.3

Incoming connections flow

runDownload()
  └── go listenIncoming(ctx, tf)
        └── net.Listen(":6881")
        └── for { conn = Accept() → go handleIncoming(conn) }
              ├── ReadFull → verify wireProtocol + infoHash
              ├── Write reply handshake
              └── register peer in peerIdx
                    → подхватывается startWorkers на следующем heartbeat

Resume flow

createOrOpenPartFile():
  ├── если .part существует + .bitmap → verifyPieces() (быстро)
  ├── если .part существует, нет bitmap → verifyAllPieces() (SHA-1 scan)
  └── если .part нет → создаём новый, Truncate(size)

heartbeat:
  asyncSaveBitmap() → .part.bitmap

завершение:
  os.Remove(.part) + os.Remove(.part.bitmap)