Skip to content

0064. Raw-файлы по пути одним запросом ​

Статус: accepted. Owner: Ian Panaev. Дата: 2026-10-04. Аддитивное расширение /api/v1, SDK и CLI поверх истории путей (assets).

Контекст ​

Основные потребители — сборочные конвейеры игр (Unity, Unreal) и программ разных стеков: сборки, установщики exe, архивы, логи. Хранение по пути с историей ревизий уже есть (PUT …/asset). Но положить файл можно было только за три шага: создать загрузку, передать байты, привязать путь. Для curl, PowerShell и сборочных скриптов без SDK это неудобно, а в CLI загрузки по пути не было вовсе. Анализ форматов выделил «generic/raw» как основу, которой не хватает; npm, Maven, PyPI, S3-фасад и WebDAV отложены или отклонены.

Решение ​

HTTP. PUT /api/v1/repositories/{repository}/raw/{path} сохраняет тело запроса как новую ревизию пути; GET|HEAD того же адреса отдаёт текущую ревизию (Range, ETag, X-Arkvory-Artifact-Id).

  • Путь — как у assets: сегменты через /, без пустых, ., .., обратной косой черты и двоеточия, до 1024 символов.
  • Тело любого типа хранится как байты (JSON-файл не разбирается). Без Content-Type тоже работает, как отправляет curl -T.
  • Если есть X-Checksum-Sha256 и Content-Length, байты идут прямо в хранилище артефактов за один проход, и хранилище проверяет сумму и размер. Несовпадение — 422 integrity_mismatch, путь не меняется.
  • Без суммы или без длины (chunked) байты сначала пишутся во временный файл <data>/raw-staging с подсчётом SHA-256. Это второй проход и до двух объёмов файла на диске. Запас свободного места хранилища проверяется каждые 64 MiB. Остатки после сбоя убирает обслуживание пишущего шлюза через сутки.
  • Если путь уже указывает на те же байты (SHA-256 и размер), ничего не сохраняется: 200, created: false, ревизия прежняя. Повтор шага CI безопасен (retry: idempotent). При известной сумме тело в этом случае не читается, а соединение закрывается.
  • Новые байты — 201, новая ревизия, артефакт назван по последнему сегменту пути.
  • If-None-Match: * — сохранить, только если пути ещё нет, иначе 409 already_exists.
  • Двое пишут в один путь: позже пришедший получает 409 revision_mismatch (CAS ревизии пути). Его артефакт остаётся без пути, пока его не удалит retention.
  • Права: запись — upload.create/write/complete, asset.read/write, artifact.read (файловые ключи — write); чтение — content.read. Шлюз чтения принимает только GET и HEAD.

SDK. Пространство имён client.raw: putRawFile(repository, path, blob, {sha256, createOnly}) — один запрос; downloadRawFile(repository, path, range?). В клиенте репозитория — assets.put и assets.download.

CLI.

  • arkvoryctl put FILE PATH — загрузка частями с чекпойнтом (как upload), затем следующая ревизия пути. Если по пути уже те же байты, ничего не загружается. Изменённый кем-то путь даёт revision_mismatch и не перезаписывается.
  • arkvoryctl get PATH OUTPUT — текущая ревизия через проверяемое скачивание с докачкой.

Для файлов в десятки ГБ правильный путь — CLI или SDK с загрузкой частями: одиночный PUT не продолжается после обрыва.

Последствия ​

  • Удаления пути нет, как и у assets: история хранится. Листинг каталога не добавлен: GET …/assets/page?prefix= уже отдаёт пути по префиксу.
  • В зеркала raw-файлы попадают как assets: изменения путей уже в ленте.
  • Отклонены: фасад S3 (большая поверхность и опасная частичная совместимость), WebDAV (артефакты неизменяемы, а WebDAV ждёт перезаписи и блокировок), отдельный формат Helm (Helm 3 хранит чарты в OCI-реестре, ADR 0063). npm, Maven, PyPI, NuGet, APT/YUM — только при появлении конкретного потребителя.
  • Следующие форматы для игровых проектов — Git LFS с блокировками и реестр пакетов Unity (UPM по протоколу npm). Каждый получит отдельное решение.

Проверки ​

  • tests/integration/raw-files.test.mjs, настоящий curl -T:
    • загрузка без суммы и с ней, повтор без новой ревизии, неверная сумма;
    • скачивание целиком, Range, HEAD, If-None-Match: *, история пути;
    • JSON-файл как байты, chunked-тело, права чтения и записи, недопустимые пути, 404;
    • SDK одним запросом;
    • arkvoryctl put дважды (второй раз без загрузки) и get.
  • tests/api-contract.test.mjs и tests/sdk-compatibility.test.mjs: новые операции и пространство имён raw добавлены аддитивно.

Arkvory · ProAnimaStudio