- /wave/options, POST /wave/sessions (activity, mood, seed), /next with reactions, PATCH to switch the context on the fly, DELETE - the recommender is called with an 800 ms budget; on failure the api serves a fallback wave of likes, favourite artists and random available tracks with the same dislike / recent / served filters - every served track is an impression with its source and model; wave events (context_type wave) set its outcome, reactions win - library status shows the analysis queue and 7-day wave metrics: listen-through, early skip and like rate Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
76 lines
4.1 KiB
Go
76 lines
4.1 KiB
Go
// Package config читает конфигурацию сервиса из переменных окружения.
|
||
package config
|
||
|
||
import (
|
||
"fmt"
|
||
"time"
|
||
|
||
"github.com/caarlos0/env/v11"
|
||
)
|
||
|
||
// API — конфигурация публичного сервиса api.
|
||
type API struct {
|
||
HTTPAddr string `env:"HTTP_ADDR" envDefault:":8080"`
|
||
DatabaseURL string `env:"DATABASE_URL,required"`
|
||
RedisURL string `env:"REDIS_URL,required"`
|
||
LogLevel string `env:"LOG_LEVEL" envDefault:"info"`
|
||
MigrateOnStart bool `env:"MIGRATE_ON_START" envDefault:"true"`
|
||
ShutdownTimeout time.Duration `env:"SHUTDOWN_TIMEOUT" envDefault:"15s"`
|
||
|
||
SupportedLocales []string `env:"SUPPORTED_LOCALES" envDefault:"ru,en" envSeparator:","`
|
||
MinAndroidVersionCode int `env:"MIN_ANDROID_VERSION_CODE" envDefault:"0"`
|
||
|
||
// JWTPrivateKey — Ed25519 (base64: 32-байтовый seed или 64-байтовый ключ). Пусто — случайный ключ
|
||
// на время жизни процесса: после перезапуска всем придётся обновить access-токен (refresh остаётся).
|
||
JWTPrivateKey string `env:"JWT_PRIVATE_KEY"`
|
||
// JWTPreviousKeys — прежние ключи через запятую: токены, подписанные ими, ещё принимаются.
|
||
JWTPreviousKeys []string `env:"JWT_PREVIOUS_KEYS" envSeparator:","`
|
||
AccessTokenTTL time.Duration `env:"ACCESS_TOKEN_TTL" envDefault:"15m"`
|
||
// CookieSecure — флаг Secure у refresh-cookie. Отключать только для разработки по http не на localhost.
|
||
CookieSecure bool `env:"COOKIE_SECURE" envDefault:"true"`
|
||
|
||
BootstrapAdminUsername string `env:"BOOTSTRAP_ADMIN_USERNAME" envDefault:"admin"`
|
||
BootstrapAdminPassword string `env:"BOOTSTRAP_ADMIN_PASSWORD"`
|
||
|
||
// LibraryRoot — точки монтирования NFS-хранилищ (общий каталог с storage-agent).
|
||
LibraryRoot string `env:"LIBRARY_ROOT" envDefault:"/library"`
|
||
// LibraryHostRoot — LIBRARY_HOST внутри контейнера: local-хранилища — его подпапки.
|
||
LibraryHostRoot string `env:"LIBRARY_HOST_ROOT" envDefault:"/library-host"`
|
||
StorageAgentURL string `env:"STORAGE_AGENT_URL" envDefault:"http://storage-agent:8090"`
|
||
InternalToken string `env:"INTERNAL_TOKEN"`
|
||
FFprobePath string `env:"FFPROBE_PATH" envDefault:"ffprobe"`
|
||
|
||
// SigningKey — ключ подписи ссылок на обложки и стрим (base64, ≥ 16 байт). Пусто — случайный до перезапуска.
|
||
SigningKey string `env:"STREAM_SIGNING_KEY"`
|
||
CacheDir string `env:"CACHE_DIR" envDefault:"/cache"`
|
||
FFmpegPath string `env:"FFMPEG_PATH" envDefault:"ffmpeg"`
|
||
// XAccel — файлы отдаёт nginx по X-Accel-Redirect; false — для запуска api без nginx.
|
||
XAccel bool `env:"X_ACCEL" envDefault:"true"`
|
||
// TranscodeConcurrency — параллельных ffmpeg; 0 — половина ядер.
|
||
TranscodeConcurrency int `env:"TRANSCODE_CONCURRENCY" envDefault:"0"`
|
||
TranscodeCacheLimitGB int `env:"TRANSCODE_CACHE_LIMIT_GB" envDefault:"50"`
|
||
|
||
RecommenderURL string `env:"RECOMMENDER_URL" envDefault:"http://recommender:8000"`
|
||
|
||
MeiliURL string `env:"MEILI_URL" envDefault:"http://meilisearch:7700"`
|
||
MeiliMasterKey string `env:"MEILI_MASTER_KEY"`
|
||
}
|
||
|
||
// StorageAgent — конфигурация внутреннего сервиса storage-agent.
|
||
type StorageAgent struct {
|
||
HTTPAddr string `env:"HTTP_ADDR" envDefault:":8090"`
|
||
InternalToken string `env:"INTERNAL_TOKEN,required,notEmpty"`
|
||
LibraryRoot string `env:"LIBRARY_ROOT" envDefault:"/library"`
|
||
LogLevel string `env:"LOG_LEVEL" envDefault:"info"`
|
||
ShutdownTimeout time.Duration `env:"SHUTDOWN_TIMEOUT" envDefault:"15s"`
|
||
}
|
||
|
||
// Load заполняет структуру конфигурации T из окружения.
|
||
func Load[T any]() (T, error) {
|
||
var cfg T
|
||
if err := env.Parse(&cfg); err != nil {
|
||
return cfg, fmt.Errorf("config: %w", err)
|
||
}
|
||
return cfg, nil
|
||
}
|