deplex API

REST API для загрузки и раздачи игровых билдов Dustore. База — https://api.dustore.ru. Все ответы — JSON (кроме бинарного установщика).

API обслуживает две стороны: разработчика (CLI deplex заливает билды — эти эндпоинты требуют токен) и игрока (скачивание игры — публичные эндпоинты). Билд хранится чанками: файлы режутся на куски, каждый шифруется и заливается один раз (дедупликация).

Авторизация

Эндпоинты разработчика требуют заголовок:

Authorization: Bearer dplx_live_xxxxxxxxxxxx

Токен создаётся в консоли разработчика (Студия → «Deploy-токены»), привязан к студии и наследует её права. В БД хранится только его sha256. Токен можно отозвать в любой момент.

Публичные эндпоинты (/v1/games/{id}/manifest, /v1/games/{id}/installer) токена не требуют — билды не секретны.

Формат ошибок

Любая ошибка — единый конверт с говорящим кодом и HTTP-статусом:

{
  "error": {
    "code": "quota_exceeded",
    "message": "не влезает: нужно 5242880 Б, свободно 1048576 Б"
  }
}
КодHTTPКогда
unauthorized401нет Bearer-токена
token_invalid401токен не найден, отозван или истёк
forbidden403ресурс принадлежит другой студии
project_not_found404игра не найдена у студии
quota_exceeded409билд не влезает в квоту (10 ГБ)
chunks_missing409не все чанки залиты — повторить update
no_build404у игры нет готового билда

Проверить токен

POST/v1/auth/verify

Проверяет токен и возвращает identity студии + сводку квоты. Используется командой deplex auth.

Ответ 200

{
  "user":   { "id": 1, "name": "TheCreator" },
  "studio": { "id": 1, "name": "CrazyProjectsLab" },
  "role": -1,
  "role_label": "Владелец",
  "usage": { "bytes_used": 0, "bytes_quota": 10737418240 }
}

Список игр

GET/v1/projects

Игры студии текущего токена + инфо о последнем билде.

Ответ 200

{
  "projects": [
    { "id": 1, "name": "DUSTORE", "last_build": "2026-07-29 (v1.0)", "size": 1288490188 },
    { "id": 11, "name": "Temple Run", "last_build": "", "size": 0 }
  ]
}

Квота

GET/v1/usage

Занятое место студии и лимит (в байтах). Квота единая на все пути загрузки.

{ "bytes_used": 1288490188, "bytes_quota": 10737418240 }

Ключ проекта (DEK)

POST/v1/projects/{gameId}/key

Выдаёт открытый ключ шифрования проекта (base64). Генерится при первом обращении, хранится в БД только в обёрнутом виде. Клиент держит его в памяти и шифрует чанки.

{ "dek": "b3zK…(base64, 32 байта)…", "dek_id": "dek_1_v1" }

Старт билда

POST/v1/projects/{gameId}/builds

Запрос

{ "version_label": "1.0" }   // необязательно

Ответ 201

{ "build_id": "01KYQF…(ULID)", "project_id": 1, "status": "draft" }

Presign чанков

POST/v1/chunks/presign

По списку чанков: отсекает уже залитые (дедуп), проверяет квоту и выдаёт presigned PUT-URL на новые. Клиент льёт зашифрованные чанки напрямую в S3 по этим ссылкам.

Запрос

{
  "build_id": "01KYQF…",
  "chunks": [
    { "id": "3a7b…(sha256)", "size": 8388636, "size_plain": 8388608 }
  ]
}

Ответ 200

{
  "existing": ["c19f…"],                 // уже в хранилище — не грузить
  "upload": [
    { "id": "3a7b…",
      "url": "https://s3.regru.cloud/…?X-Amz-…",
      "method": "PUT",
      "headers": { "Content-Type": "application/octet-stream" },
      "expires_at": "2026-07-30T15:03:00Z" }
  ],
  "quota": { "after_bytes_used": 1449551462, "bytes_quota": 10737418240 }
}

Commit билда

POST/v1/builds/{buildId}/commit

Фиксирует билд: сохраняет манифест, обновляет refcount чанков, чистит осиротевшие (GC, кроме последних K билдов), пересчитывает квоту и проставляет ссылку на установщик.

Запрос

{
  "manifest": {
    "manifest_version": 1, "project_id": 1, "build_id": "01KYQF…",
    "files": [
      { "path": "Game.exe", "size": 50528256, "sha256": "9f2c…",
        "mode": 493, "mtime": 1690000000, "chunks": ["3a7b…", "c19f…"] }
    ]
  },
  "notes": "релиз 1.0"
}

Ответ 200

{
  "build_id": "01KYQF…", "status": "committed",
  "gc_deleted_chunks": 42, "gc_freed_bytes": 60817408,
  "usage": { "bytes_used": 1449551462, "bytes_quota": 10737418240 }
}

Манифест игры

GET/v1/games/{gameId}/manifestпублично

Манифест последнего билда + ключ расшифровки + presigned GET-ссылки на все уникальные чанки. По этому ответу лаунчер/установщик собирает игру.

Ответ 200

{
  "build_id": "01KYQF…",
  "manifest": { "files": [ { "path": "Game.exe", "size": 50528256,
                          "sha256": "9f2c…", "chunks": ["3a7b…"] } ] },
  "dek": "b3zK…(base64)…",
  "chunks": { "3a7b…": "https://s3.regru.cloud/…?X-Amz-…" },
  "exec": "Game.exe"
}
Целостность двойная: GCM-tag ловит порчу чанка, а sha256 из манифеста — ошибку сборки файла.

Установщик

GET/v1/games/{gameId}/installer?os=windowsпублично

Отдаёт one-file установщик (application/octet-stream): готовый stub-бинарник с дописанным футером под конкретную игру. Игрок запускает — установщик сам скачивает и собирает игру.

ПараметрЗначенияПо умолчанию
oswindows, linux, macos, macos-armwindows

Ответ — файл Install-<Игра>.exe (заголовок Content-Disposition: attachment).

deplex API · о deplex · Dustore