fix(config): wire DataDir from yaml/env through to playlists service
Slice 1 of M7 #352 added Server.DataDir but left it un-populated — the playlist cover-collage writer would have used "" as the relative path root in production, writing to the current working directory. - Add Storage.DataDir to Config (yaml: storage.data_dir, env: SMARTMUSIC_STORAGE_DATA_DIR), defaulting to "./data". - server.New takes the data dir as a parameter; main.go threads it. - main.go MkdirAll's the directory at startup so the playlist cover writer doesn't fail on first use with a missing parent. - config.example.yaml documents the new section. Existing internal/server/server_test.go constructs Server directly without server.New, so no test fixture changes needed for that file.
This commit is contained in:
+11
-1
@@ -97,9 +97,19 @@ func run() error {
|
||||
lidarrReconciler := lidarrrequests.NewReconciler(pool, lidarrCfg, logger.With("component", "lidarr"))
|
||||
go lidarrReconciler.Run(ctx)
|
||||
|
||||
// Ensure DataDir exists before any service tries to write into it.
|
||||
// Best-effort: log + continue on failure; the playlist cover writer
|
||||
// will surface a clearer error at first use.
|
||||
if cfg.Storage.DataDir != "" {
|
||||
if err := os.MkdirAll(cfg.Storage.DataDir, 0o755); err != nil {
|
||||
logger.Warn("data_dir create failed; cached artifacts may not persist",
|
||||
"path", cfg.Storage.DataDir, "err", err)
|
||||
}
|
||||
}
|
||||
|
||||
srv := server.New(logger, pool, scanner, subsonic.Config{
|
||||
AllowPlaintextPassword: cfg.Subsonic.AllowPlaintextPassword,
|
||||
}, cfg.Events, cfg.Recommendation)
|
||||
}, cfg.Events, cfg.Recommendation, cfg.Storage.DataDir)
|
||||
httpServer := &http.Server{
|
||||
Addr: cfg.Server.Address,
|
||||
Handler: srv.Router(),
|
||||
|
||||
@@ -11,6 +11,7 @@ import (
|
||||
|
||||
type Config struct {
|
||||
Server ServerConfig `yaml:"server"`
|
||||
Storage StorageConfig `yaml:"storage"`
|
||||
Database DatabaseConfig `yaml:"database"`
|
||||
Log LogConfig `yaml:"log"`
|
||||
Auth AuthConfig `yaml:"auth"`
|
||||
@@ -24,6 +25,18 @@ type ServerConfig struct {
|
||||
Address string `yaml:"address"`
|
||||
}
|
||||
|
||||
// StorageConfig points at on-disk locations the server uses for cached
|
||||
// runtime artifacts. Currently:
|
||||
// - DataDir hosts <DataDir>/playlist_covers/{playlist_id}.jpg (M7 #352).
|
||||
// More entries may grow here (e.g., transcode cache) without breaking
|
||||
// existing layouts.
|
||||
type StorageConfig struct {
|
||||
// DataDir is the root for cached artifacts. Default: "./data" (relative
|
||||
// to the working directory). Operators in production should set an
|
||||
// absolute path persistent across restarts.
|
||||
DataDir string `yaml:"data_dir"`
|
||||
}
|
||||
|
||||
type DatabaseConfig struct {
|
||||
URL string `yaml:"url"`
|
||||
}
|
||||
@@ -82,6 +95,7 @@ type RecommendationConfig struct {
|
||||
func Default() Config {
|
||||
return Config{
|
||||
Server: ServerConfig{Address: ":4533"},
|
||||
Storage: StorageConfig{DataDir: "./data"},
|
||||
Database: DatabaseConfig{URL: ""},
|
||||
Log: LogConfig{Level: "info", Format: "text"},
|
||||
Events: EventsConfig{
|
||||
@@ -124,6 +138,9 @@ func applyEnv(cfg *Config) {
|
||||
if v, ok := os.LookupEnv("SMARTMUSIC_SERVER_ADDRESS"); ok {
|
||||
cfg.Server.Address = v
|
||||
}
|
||||
if v, ok := os.LookupEnv("SMARTMUSIC_STORAGE_DATA_DIR"); ok {
|
||||
cfg.Storage.DataDir = v
|
||||
}
|
||||
if v, ok := os.LookupEnv("SMARTMUSIC_DATABASE_URL"); ok {
|
||||
cfg.Database.URL = v
|
||||
}
|
||||
|
||||
@@ -70,8 +70,8 @@ type Server struct {
|
||||
DataDir string
|
||||
}
|
||||
|
||||
func New(logger *slog.Logger, pool *pgxpool.Pool, scanner ScanTrigger, subCfg subsonic.Config, eventsCfg config.EventsConfig, recCfg config.RecommendationConfig) *Server {
|
||||
return &Server{Logger: logger, Pool: pool, Scanner: scanner, SubsonicCfg: subCfg, EventsCfg: eventsCfg, RecommendationCfg: recCfg}
|
||||
func New(logger *slog.Logger, pool *pgxpool.Pool, scanner ScanTrigger, subCfg subsonic.Config, eventsCfg config.EventsConfig, recCfg config.RecommendationConfig, dataDir string) *Server {
|
||||
return &Server{Logger: logger, Pool: pool, Scanner: scanner, SubsonicCfg: subCfg, EventsCfg: eventsCfg, RecommendationCfg: recCfg, DataDir: dataDir}
|
||||
}
|
||||
|
||||
func (s *Server) Router() http.Handler {
|
||||
|
||||
Reference in New Issue
Block a user