Воркер ведёт in-memory снимок телеметрии раздач (прогресс, скорость, ETA, рейтинг, сиды/пиры, отдано) под отдельным RWMutex, обновляя его на каждом тике поллинга сразу после построения byHash — без лишних вызовов qBittorrent и без хранения в БД (волатильно). qbt.Torrent дополнен полями телеметрии. Веб-UI читает снимок через узкий контракт LiveStatus: карточки активных загрузок показывают живой прогресс-бар (htmx-поллинг фрагмента every 3s, точечно — без сброса фильтров), на странице загрузки появилась секция «Раздача» для сидирующих задач. Начальный кадр рендерится сразу со значениями; при отсутствии данных UI деградирует штатно. Капабилити live-status (OpenSpec), web-ui дополнен. Change заархивирован. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
65 lines
5.2 KiB
Markdown
65 lines
5.2 KiB
Markdown
## 1. Телеметрия в клиенте qBittorrent
|
||
|
||
- [x] 1.1 Добавить в `qbt.Torrent` поля `Dlspeed`, `Eta`, `Ratio`, `NumSeeds`,
|
||
`NumLeechs`, `Uploaded`, `Upspeed` с json-тегами из `/torrents/info`
|
||
(`dlspeed`, `eta`, `ratio`, `num_seeds`, `num_leechs`, `uploaded`, `upspeed`)
|
||
- [x] 1.2 Обновить комментарий-доку `Torrent` (подмножество полей расширено)
|
||
|
||
## 2. Снимок телеметрии в воркере
|
||
|
||
- [x] 2.1 Добавить тип `worker.Live{Progress, DlSpeed, ETA, State, Seeding,
|
||
Ratio, Seeds, Peers, Uploaded, UpSpeed}` (курированный, без зависимости на
|
||
qbt у читателей); `Seeding` вычислять через `classify(state) == classReady`
|
||
- [x] 2.2 Добавить в `Worker` поле снимка `live map[string]Live` + отдельный
|
||
`sync.RWMutex` (не `w.mu`); инициализация в `New`
|
||
- [x] 2.3 В `Poll` собрать новую карту из полученного `torrents` — **три ключа
|
||
на торрент** (lowercase `Hash`/`InfohashV1`/`InfohashV2`, как `byHash`) — и
|
||
атомарно подменить снимок **сразу после построения `byHash`, до store-
|
||
операций** (телеметрия обновляется даже при последующем сбое reconcile)
|
||
- [x] 2.4 Реализовать `Live(infohash string) (Live, bool)` — чтение под RLock,
|
||
`ok=false` при пустом/неизвестном infohash
|
||
- [x] 2.5 Тесты: снимок обновляется после `Poll`; `Live` отдаёт данные
|
||
качающейся и сидирующей задачи (с верным `Seeding`); поиск по любому из трёх
|
||
хэшей; неизвестный/пустой infohash → `ok=false`
|
||
|
||
## 3. Транспорт: контракт и фрагмент-роуты
|
||
|
||
- [x] 3.1 Объявить интерфейс `LiveStatus` в `internal/httpapi` и добавить поле
|
||
`Live LiveStatus` в `Deps`
|
||
- [x] 3.2 Прокинуть `Live: wrk` в `httpapi.Deps` в `cmd/jellybit/serve.go`
|
||
- [x] 3.3 Добавить роуты `GET /fragments/downloads/{id}/progress` и
|
||
`GET /fragments/downloads/{id}/seeding` в `NewRouter`
|
||
- [x] 3.4 Реализовать обработчики фрагментов: `GetDownload` → infohash/состояние
|
||
+ `Live(infohash)`; рендер партиала; `ok=false` → деградация без живых значений
|
||
- [x] 3.5 **Начальный рендер со значениями:** расширить `downloadView` и
|
||
`downloadDetailView` полями телеметрии; в `handleIndex`/`handleDownload`
|
||
вызвать `Live(infohash)` для нужных задач и положить во view — одна модель для
|
||
страницы и для фрагмент-роута (без мигания при первой загрузке)
|
||
- [x] 3.6 Добавить хелперы форматирования скорости/размера/ETA: человекочитаемые
|
||
единицы (байты→КиБ/МиБ, скорость/с), sentinel'ы qBittorrent (`eta=8640000`→
|
||
«—»/«∞», `ratio<0`→«—»); зафиксировать выбор `num_seeds`/`num_leechs`
|
||
|
||
## 4. Шаблоны и живое обновление
|
||
|
||
- [x] 4.1 Партиал `partials/progress.html` (прогресс-бар + скорость + ETA);
|
||
включить его в карточку `index.html` для активных загрузок
|
||
- [x] 4.2 Навесить на прогресс-блок активной карточки `hx-get` /
|
||
`hx-trigger="every 3s"` / `hx-swap="outerHTML"`; при выходе из downloading
|
||
фрагмент не содержит атрибутов поллинга (поллинг прекращается)
|
||
- [x] 4.3 Партиал `partials/seeding.html` (рейтинг, сиды/пиры, отдано, скорость
|
||
отдачи); секция «Раздача» в `download.html` для сидирующих задач, с
|
||
htmx-поллингом и деградацией при отсутствии данных
|
||
- [x] 4.4 Проверить, что фоновое обновление не сбрасывает фильтр/поиск/прокрутку
|
||
на главной (поллинг точечный, на уровне карточки)
|
||
- [x] 4.5 При необходимости — стили прогресс-бара/раздачи в `jellybit.css`
|
||
(использовать существующие токены, без инлайн-хардкода цветов)
|
||
|
||
## 5. Проверки и ревью
|
||
|
||
- [x] 5.1 `task test` (включая новые тесты воркера и httpapi-рендера фрагментов;
|
||
в т.ч. тест «фрагмент при выходе из downloading отдаётся без htmx-атрибутов
|
||
поллинга»)
|
||
- [x] 5.2 `task lint`, `gofmt`, `openspec validate --strict`
|
||
- [x] 5.3 Ревью кода (второй чекпоинт) перед archive: соответствие спекам и
|
||
конвенциям (логирование без секретов, ошибки `%w`, отдельный RWMutex)
|