From e1f8e493d2d52d547251537980e2ec78f074791b Mon Sep 17 00:00:00 2001 From: "CJACK." <155826701+CJackHwang@users.noreply.github.com> Date: Wed, 29 Apr 2026 14:12:20 +0800 Subject: [PATCH] fix: add legacy /app/config.json fallback for container upgrades --- docs/DEPLOY.en.md | 1 + docs/DEPLOY.md | 1 + internal/config/paths.go | 8 ++++++++ internal/config/store.go | 11 ++++++++--- 4 files changed, 18 insertions(+), 3 deletions(-) diff --git a/docs/DEPLOY.en.md b/docs/DEPLOY.en.md index e4d0734..4c1df13 100644 --- a/docs/DEPLOY.en.md +++ b/docs/DEPLOY.en.md @@ -131,6 +131,7 @@ docker-compose logs -f The default `docker-compose.yml` directly uses `ghcr.io/cjackhwang/ds2api:latest` and maps host port `6011` to container port `5001`. If you want `5001` exposed directly, set `DS2API_HOST_PORT=5001` (or adjust the `ports` mapping). The compose template also defaults to `DS2API_CONFIG_PATH=/data/config.json` with `./config.json:/data/config.json` mounted, so deployments avoid read-only `/app` persistence issues by default. +Compatibility note: when `DS2API_CONFIG_PATH` is unset and runtime base dir is `/app`, newer versions prefer `/data/config.json`; if that file is missing but legacy `/app/config.json` exists, DS2API automatically falls back to the legacy path to avoid post-upgrade config loss. If you want a pinned version instead of `latest`, you can also pull a specific tag directly: diff --git a/docs/DEPLOY.md b/docs/DEPLOY.md index e2efe61..47dfd4b 100644 --- a/docs/DEPLOY.md +++ b/docs/DEPLOY.md @@ -131,6 +131,7 @@ docker-compose logs -f 默认 `docker-compose.yml` 直接使用 `ghcr.io/cjackhwang/ds2api:latest`,并把宿主机 `6011` 映射到容器内的 `5001`。如果你希望直接对外暴露 `5001`,请设置 `DS2API_HOST_PORT=5001`(或者手动调整 `ports` 配置)。 Compose 模板还会默认设置 `DS2API_CONFIG_PATH=/data/config.json` 并挂载 `./config.json:/data/config.json`,优先避免 `/app` 只读带来的配置持久化问题。 +兼容说明:若未设置 `DS2API_CONFIG_PATH` 且运行目录是 `/app`,新版本会优先使用 `/data/config.json`;当该文件不存在但检测到历史 `/app/config.json` 时,会自动回退读取旧路径,避免升级后“配置丢失”。 如需固定版本,也可以直接拉取指定 tag: diff --git a/internal/config/paths.go b/internal/config/paths.go index 5df2759..7f5baaa 100644 --- a/internal/config/paths.go +++ b/internal/config/paths.go @@ -38,6 +38,14 @@ func ConfigPath() string { return ResolvePath("DS2API_CONFIG_PATH", "config.json") } +func legacyContainerConfigPath() string { + return "/app/config.json" +} + +func shouldTryLegacyContainerConfigPath() bool { + return strings.TrimSpace(os.Getenv("DS2API_CONFIG_PATH")) == "" && BaseDir() == "/app" +} + func RawStreamSampleRoot() string { return ResolvePath("DS2API_RAW_STREAM_SAMPLE_ROOT", "tests/raw_stream_samples") } diff --git a/internal/config/store.go b/internal/config/store.go index a54e012..0af367f 100644 --- a/internal/config/store.go +++ b/internal/config/store.go @@ -87,12 +87,17 @@ func loadConfig() (Config, bool, error) { } return cfg, true, err } - cfg, err := loadConfigFromFile(ConfigPath()) if err != nil { + if shouldTryLegacyContainerConfigPath() { + legacyPath := legacyContainerConfigPath() + if legacyCfg, legacyErr := loadConfigFromFile(legacyPath); legacyErr == nil { + Logger.Info("[config] loaded legacy container config path", "path", legacyPath) + return legacyCfg, false, nil + } + } if IsVercel() { - // Vercel one-click deploy may start without a writable/present config file. - // Keep an in-memory config so users can bootstrap via WebUI then sync env. + // Vercel may start without writable/present config; keep in-memory bootstrap config. return Config{}, true, nil } return Config{}, false, err