Сервис для загрузки больших файлов с делением на чанки, чтобы можно было загружать в режиме ограниченного и нестабильного интернета
  • Go 66.3%
  • TypeScript 31%
  • JavaScript 1.6%
  • Shell 1%
  • Dockerfile 0.1%
Find a file
2026-07-03 11:30:33 +03:00
client-go feat: Go SDK 2026-06-27 10:41:45 +03:00
client-ts Fix: Добавление константы для унификации дальнейшей калибровки 2026-07-03 11:30:33 +03:00
cmd feat: Go SDK 2026-06-27 10:41:45 +03:00
data feat: Go SDK 2026-06-27 10:41:45 +03:00
docs feat: Дробление чанков если мы получаем 413/507, а так же уменьшение maxChunkSize чтобы больше в это не упираться 2026-07-01 15:02:23 +03:00
internal fix: Перемещение файла 2026-07-02 09:14:49 +03:00
packaging fix: CI 2026-06-27 15:27:12 +03:00
tests feat: Go SDK 2026-06-27 10:41:45 +03:00
.dockerignore ci: пакеты 2026-06-27 10:49:36 +03:00
.gitignore fix: Изменение порта на 3000 по дефолту 2026-07-01 09:34:22 +03:00
.woodpecker.yml fix: Исправление ids и добавление debug в клиент 2026-07-02 10:02:19 +03:00
docker-compose.yml fix: Изменение порта на 3000 по дефолту 2026-07-01 09:34:22 +03:00
Dockerfile doc: Roadmap 2026-06-27 10:14:07 +03:00
Dockerfile.ci fix: Исправление ids и добавление debug в клиент 2026-07-02 10:02:19 +03:00
go.mod fix: Обновление модулей 2026-06-27 18:29:43 +03:00
go.sum fix: Обновление модулей 2026-06-27 18:29:43 +03:00
LICENSE first commit 2026-06-26 15:04:46 +03:00
README.md feat: Добавление CORS 2026-07-01 11:47:30 +03:00

chunker-upload

Сервис чанковой загрузки файлов с адаптацией к качеству сети.
Многоарендная архитектура с авторизацией TokenApp, тремя storage-бэкендами и вебхуками.

Быстрый старт

go run ./cmd/chunker-upload --addr :3000 --storage-backend inmemory
curl -X POST http://localhost:3000/myapp/init \
  -H 'Authorization: Bearer my-token' \
  -H 'Content-Type: application/json' \
  -d '{"app_id":"myapp","file_name":"photo.jpg","file_size":10485760}'

Полный пример — cmd/chunker-demo/main.go (init → upload чанков → finish → webhook).

Конфигурация

Все параметры настраиваются через CLI-флаги, переменные окружения или YAML-файл (--config config.yaml / CONFIG_FILE).

Параметр CLI Env Default Описание
Адрес --addr ADDR :3000 HTTP адрес для привязки
Storage backend --storage-backend STORAGE_BACKEND inmemory inmemory / sqlite / redis
SQLite путь --database-path DATABASE_PATH ./data/chunker.db Путь к файлу БД
Redis адрес --redis-addr REDIS_ADDR localhost:6379 Адрес Redis/Valkey
Redis пароль --redis-password REDIS_PASSWORD "" Пароль Redis/Valkey
Redis БД --redis-db REDIS_DB 0 Номер БД Redis
Директория uploads --upload-dir UPLOAD_DIR ./data/uploads Временные файлы загрузки
Директория completed --completed-dir COMPLETED_DIR ./data/completed Готовые файлы
CORS origins --cors-origins CORS_ORIGINS * Разрешённые Origin (* для всех, или через запятую)
Публичный URL --public-url PUBLIC_URL Внешний адрес чанкера (напр. https://chunker.example.com)
Audit-лог --audit-log AUDIT_LOG ./data/audit.jsonl JSONL-лог операций
Config файл --config CONFIG_FILE YAML/JSON файл конфигурации

TokenApp настраивается только в YAML-файле (секция token_apps):

token_apps:
  - app_id: "myapp"
    token: "secret-token"
    base_path: "/myapp"
    webhook_url: "https://app.example.com/webhook"
    ttl_upload: 24h
    ttl_completed: 72h
    webhook_max_attempts: 5
    webhook_initial_interval: 10s
    webhook_max_interval: 5m

Приоритет: CLI → Env → Config file → Defaults.

Архитектура

HTTP-клиент (TS / Go SDK)  ──►  chunker-upload (Go)  ──►  Storage (InMemory / SQLite / Redis)
                                      │
                                      └──► FileStore (uploads/ → completed/)
                                      └──► Webhook (POST на URL по завершении)
                                      └──► Prometheus /metrics
Компонент Описание
cmd/chunker-upload/ Точка входа сервера
cmd/chunker-demo/ Демо (init → upload → finish → webhook)
cmd/e2e-server/ Вспомогательный сервер для E2E тестов
internal/handler/ HTTP-роуты (init, upload, finish, status, file, /metrics)
internal/storage/ MetadataStorage: InMemory, SQLite (modernc.org/sqlite), Redis
internal/filestore/ WriteAt-запись, SHA-256, перемещение файлов
internal/webhook/ Асинхронные уведомления с retry и dead-letter
internal/cleanup/ Фоновая очистка по TTL
internal/metrics/ 9 Prometheus-метрик
internal/config/ CLI + env + YAML конфигурация
client-ts/ TypeScript SDK (@ymnuk/chunker-upload-client)
client-go/ Go SDK (зеркало TS-клиента)
packaging/ systemd unit, nfpm-конфиг для deb/rpm/apk

API

Метод Путь Аутентификация Описание
POST /{basePath}/init Bearer token Создать сессию загрузки
PUT /{basePath}/upload/{id} Отправить чанк (CRC32, идемпотентность)
PUT /{basePath}/finish/{id} Завершить (SHA-256, move, webhook)
GET /{basePath}/status?id=... Bearer token Статус сессии (получено байт, пропуски)
GET /{basePath}/file/{id} Bearer token Скачать завершённый файл
GET /metrics Prometheus-метрики

Жизненный цикл файла

Клиент (SDK)               chunker-upload                   Storage (metadata)        FileStore (disk)
    │                             │                                │                        │
    │  POST /{basePath}/init      │                                │                        │
    │  Authorization: Bearer ◄────┤── CreateSession() ───────────► │                        │
    │◄──── {upload_id, public_url}│                                │                        │
    │                             │                                │                        │
    │  PUT /{basePath}/upload/{id}                                 │                        │
    │  X-Chunk-Offset, X-Chunk-Size                                │                        │
    │  X-Chunk-Crc32, X-Chunk-Id  │                                │                        │
    │ ├──── чанк 1 ──────────────►│── SaveChunk() ───────────────► │                        │
    │ │                           │── WriteChunk() ────────────────────────────────────────►│
    │ ├──── чанк 2 ──────────────►│── SaveChunk() ───────────────► │                        │
    │ │                           │── WriteChunk() ────────────────────────────────────────►│
    │ ├──── чанк N ──────────────►│── SaveChunk() ───────────────► │                        │
    │ │                           │── WriteChunk() ────────────────────────────────────────►│
    │                             │                                │                        │
    │ PUT /{basePath}/finish/{id} │                                │                        │
    │  {"hash": "<SHA-256>"}      │                                │                        │
    │                             │── ComputeHash() ───────────────────────────────────────►│
    │                             │── MoveToCompleted() ───────────────────────────────────►│
    │                             │── UpdateSession(status=completed) ───►                  │
    │                             │── POST webhook (Session JSON) ───► Приложение           │
    │◄──── {ok}                   │                                │                        │
    │                             │                                │                        │
    │                             │                                │                        │
    │  Приложение (по вебхуку знает upload_id)                     │                        │
    │                             │                                │                        │
    │  GET /{basePath}/file/{id}  │                                │                        │
    │  Authorization: Bearer ◄────┤── GetSession() ───────────────►│                        │
    │  (проверка: статус completed,                                │                        │
    │   BasePath совпадает,                                        │                        │
    │   файл есть на диске)       │                                │                        │
    │◄──── body (.final file)     │── ServeFile() ─────────────────────────────────────────►│

Детальная спецификация — docs/openapi.yaml.

Storage-бэкенды

Переключение через --storage-backend / STORAGE_BACKEND.

Бэкенд Когда использовать Плюсы Минусы
inmemory Разработка, тесты Нет зависимостей Всё теряется при перезапуске
sqlite Одиночный сервер, малый/средний объём Персистентность, zero-ops Не масштабируется горизонтально
redis Кластер, высокая нагрузка Скорость, горизонтальное масштабирование Нужен внешний Redis/Valkey

Клиентские SDK

TypeScript (client-ts/)

npm install @ymnuk/chunker-upload-client
  • UploadManager с параллельной отправкой, resume, адаптивным чанкингом
  • 6 фильтров (EWMA, Kalman, HullMA, Median, SMA, CUSUM) + Mean Shift кластеризация
  • Retry с экспоненциальной задержкой
  • Адаптер для Angular

Go (client-go/)

import chunkeruploadclient "git.ymnuktech.ru/ymnuk/chunker-upload/client-go"

transport := chunkeruploadclient.NewHTTPTransport("https://upload.example.com")
uploader := chunkeruploadclient.NewUploader(transport)
result, err := uploader.Upload(ctx, "myapp", uploadID, "file.bin", reader, fileSize, token)

Полное зеркало TS-клиента: Transport, Uploader, Chunker, NetworkMonitor, Ensemble, Retry.

Установка

Docker

docker run -p 3000:3000 \
  -v data:/data \
  -e STORAGE_BACKEND=sqlite \
  git.ymnuktech.ru/ymnuk/chunker-upload:latest

Пакеты (deb / rpm / apk)

См. docs/ci-cd.md — пакеты создаются в CI и содержат systemd unit, sysusers, tmpfiles.

Документация

Все разделы — docs/README.md:

Лицензия

MIT