Files
transcriber/tasks/items/serve-content-for-file-ranges.md
T
av 75c6f0168a учёт: закрыт переезд хранилища, заведён урожай его ревью
- storage-without-pocketbase закрыта как реализованная: приёмка сошлась по всем
  пяти критериям записи и по двенадцати приёмочным свойствам рубрики ревью
  дизайна, работа лежит коммитом c9b7765
- урожай триажа ревью развёрнут в одиннадцать записей с тегом партии
  review-2026-08-23 и расставлен по зависимости, а не в конец списка
- находка про признак живости воркера слита в stalled-pipeline-metric: у неё та
  же причина — вставший конвейер неотличим от простоя
2026-08-23 08:41:49 +03:00

49 lines
3.6 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 🧹 Отдавать файл записи через http.ServeContent
- **Тип:** chore
- **Категория:** Очередь — Стандартная семантика диапазонов нужна проигрыванию записи на экране: браузер тянет звук именно диапазонами
- **Зачем:** Отдача файла считает диапазоны байт своей рукой — около 110 строк семантики HTTP, которую стандартная библиотека делает сама, и на этих строках стоит проигрывание записи на экране.
- **Теги:** review-2026-08-23
Отдача файла записи разбирает заголовок `Range`, считает границы, ставит
`Content-Range` и код `206` своей рукой — около 110 строк семантики HTTP.
`http.ServeContent` делает то же самое: диапазоны, `If-Range`, `Last-Modified`,
`ETag`, неверный диапазон с кодом `416`.
Своя реализация стоит не тем, что длиннее, а тем, что расходится: браузер
проигрывает звук именно диапазонами, и задача `play-recording-in-app` встанет
поверх этих строк.
Нашёл проход `review-architecture` (вторая половина R2) ревью change
`2026-08-23-storage-without-pocketbase`.
## Затрагивает
- `internal/controller/http/file.go` — разбор `Range`, ответ `206` и заголовки
диапазона;
- тип содержимого ответа: он выводится из закрытого перечня форматов и остаётся
за нами, `ServeContent` его не выбирает;
- открытие копии в `internal/adapter/repo/sqlite/store.go``ServeContent`
требует `io.ReadSeeker` и время последнего изменения;
- публичный контракт HTTP: коды `200`, `206`, `416` и заголовки ответа на
запрос файла.
## Критерии приёмки
- Диапазоны считает стандартная библиотека. **Оракул:** `grep` по
`internal/controller/http` — ни одного разбора заголовка `Range` руками,
вызов `http.ServeContent` один.
- Ответы на диапазон не изменились. **Оракул:** тест контроллера — запрос без
`Range` отдаёт `200` и всю длину, запрос `bytes=0-99` отдаёт `206` с
`Content-Range`, запрос за пределом длины отдаёт `416`.
- Тип содержимого по-прежнему выбирает сервис. **Оракул:** тест на записи с
расширением `.html` — ответ несёт `application/octet-stream` и
`attachment`, а не тип из имени.
- Чужой файл остаётся недостижимым. **Оракул:** прежний тест владения —
чужая и несуществующая запись отвечают байт в байт одинаково.
## Рамки
Раскладку каталога данных и имена копий не трогаем: она объявлена необратимой.
Ответ на запрос чужого файла не меняется ни кодом, ни телом.