升级版本并改用内部账号存储
This commit is contained in:
@@ -15,15 +15,43 @@ import (
|
||||
)
|
||||
|
||||
// DefaultAppPaths 收集运行时路径,支持环境变量覆盖。
|
||||
// 所有相对路径会基于当前工作目录解析为绝对路径,避免打包后工作目录不同导致路径错位。
|
||||
// 默认数据存放在当前用户的应用配置目录,而非工作目录,避免 macOS 应用包目录无写权限。
|
||||
func DefaultAppPaths() types.AppPaths {
|
||||
return types.AppPaths{
|
||||
ConfigFile: resolvePath(envOrDefault("DOUYU_CONFIG", constants.DefaultConfigFile)),
|
||||
AccountFile: resolvePath(envOrDefault("DOUYU_USERS", constants.DefaultAccountFile)),
|
||||
LogDir: resolvePath(envOrDefault("DOUYU_LOG_DIR", constants.DefaultLogDir)),
|
||||
SuccessDir: resolvePath(envOrDefault("DOUYU_SUCCESS_DIR", constants.DefaultSuccessDir)),
|
||||
FontFiles: imgpkg.CollectFontCandidates(),
|
||||
dataDir := resolvePath(envOrDefault("DOUYU_DATA_DIR", defaultAppDataDir()))
|
||||
configFile := filepath.Join(dataDir, constants.DefaultConfigFile)
|
||||
accountFile := filepath.Join(dataDir, constants.DefaultAccountFile)
|
||||
legacyConfigFile := resolvePath(constants.LegacyDefaultConfigFile)
|
||||
legacyAccountFile := resolvePath(constants.LegacyDefaultAccountFile)
|
||||
|
||||
if value := os.Getenv("DOUYU_CONFIG"); value != "" {
|
||||
configFile = resolvePath(value)
|
||||
legacyConfigFile = ""
|
||||
}
|
||||
if value := os.Getenv("DOUYU_USERS"); value != "" {
|
||||
accountFile = resolvePath(value)
|
||||
legacyAccountFile = ""
|
||||
}
|
||||
|
||||
return types.AppPaths{
|
||||
DataDir: dataDir,
|
||||
ConfigFile: configFile,
|
||||
AccountFile: accountFile,
|
||||
LegacyConfigFile: legacyConfigFile,
|
||||
LegacyAccountFile: legacyAccountFile,
|
||||
LogDir: resolvePath(envOrDefault("DOUYU_LOG_DIR", filepath.Join(dataDir, constants.DefaultLogDir))),
|
||||
SuccessDir: resolvePath(envOrDefault("DOUYU_SUCCESS_DIR", filepath.Join(dataDir, constants.DefaultSuccessDir))),
|
||||
FontFiles: imgpkg.CollectFontCandidates(),
|
||||
}
|
||||
}
|
||||
|
||||
func defaultAppDataDir() string {
|
||||
if dir, err := os.UserConfigDir(); err == nil && dir != "" {
|
||||
return filepath.Join(dir, constants.DefaultAppDataDirName)
|
||||
}
|
||||
if home, err := os.UserHomeDir(); err == nil && home != "" {
|
||||
return filepath.Join(home, "."+constants.DefaultAppDataDirName)
|
||||
}
|
||||
return "." + constants.DefaultAppDataDirName
|
||||
}
|
||||
|
||||
// resolvePath 将相对路径解析为绝对路径。
|
||||
@@ -44,6 +72,38 @@ func envOrDefault(key, fallback string) string {
|
||||
return fallback
|
||||
}
|
||||
|
||||
// MigrateLegacyFile 在目标文件不存在时复制旧版本数据,不删除旧文件。
|
||||
// 返回值表示是否完成了迁移。
|
||||
func MigrateLegacyFile(target, legacy string) (bool, error) {
|
||||
if target == "" || legacy == "" || samePath(target, legacy) {
|
||||
return false, nil
|
||||
}
|
||||
if _, err := os.Stat(target); err == nil {
|
||||
return false, nil
|
||||
} else if !errors.Is(err, os.ErrNotExist) {
|
||||
return false, err
|
||||
}
|
||||
|
||||
content, err := os.ReadFile(legacy)
|
||||
if errors.Is(err, os.ErrNotExist) {
|
||||
return false, nil
|
||||
}
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
if err := os.MkdirAll(filepath.Dir(target), 0700); err != nil {
|
||||
return false, err
|
||||
}
|
||||
if err := os.WriteFile(target, content, 0600); err != nil {
|
||||
return false, err
|
||||
}
|
||||
return true, nil
|
||||
}
|
||||
|
||||
func samePath(left, right string) bool {
|
||||
return filepath.Clean(left) == filepath.Clean(right)
|
||||
}
|
||||
|
||||
// LoadTraceConfig 读取 trace 开关;默认关闭,避免保存敏感调试数据。
|
||||
func LoadTraceConfig() types.TraceConfig {
|
||||
return types.TraceConfig{
|
||||
@@ -160,5 +220,8 @@ func SaveConfig(path string, cfg types.Config) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return os.WriteFile(path, data, 0644)
|
||||
if err := os.MkdirAll(filepath.Dir(path), 0700); err != nil {
|
||||
return err
|
||||
}
|
||||
return os.WriteFile(path, data, 0600)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,80 @@
|
||||
package config
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestMigrateLegacyFile(t *testing.T) {
|
||||
dir := t.TempDir()
|
||||
legacy := filepath.Join(dir, "legacy", "config.json")
|
||||
target := filepath.Join(dir, "internal", "config.json")
|
||||
content := []byte(`{"activity":"xiaodian"}`)
|
||||
|
||||
if err := os.MkdirAll(filepath.Dir(legacy), 0700); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := os.WriteFile(legacy, content, 0600); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
migrated, err := MigrateLegacyFile(target, legacy)
|
||||
if err != nil {
|
||||
t.Fatalf("迁移失败: %v", err)
|
||||
}
|
||||
if !migrated {
|
||||
t.Fatal("应迁移旧文件")
|
||||
}
|
||||
got, err := os.ReadFile(target)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if string(got) != string(content) {
|
||||
t.Fatalf("迁移内容 = %q, want %q", got, content)
|
||||
}
|
||||
if _, err := os.Stat(legacy); err != nil {
|
||||
t.Fatalf("旧文件不应被删除: %v", err)
|
||||
}
|
||||
|
||||
if err := os.WriteFile(legacy, []byte(`{"activity":"other"}`), 0600); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
migrated, err = MigrateLegacyFile(target, legacy)
|
||||
if err != nil {
|
||||
t.Fatalf("重复迁移失败: %v", err)
|
||||
}
|
||||
if migrated {
|
||||
t.Fatal("目标已存在时不应覆盖迁移")
|
||||
}
|
||||
got, err = os.ReadFile(target)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if string(got) != string(content) {
|
||||
t.Fatalf("目标文件被意外覆盖: %q", got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDefaultAppPathsUseInternalDataDir(t *testing.T) {
|
||||
dir := t.TempDir()
|
||||
t.Setenv("DOUYU_DATA_DIR", dir)
|
||||
t.Setenv("DOUYU_CONFIG", "")
|
||||
t.Setenv("DOUYU_USERS", "")
|
||||
t.Setenv("DOUYU_LOG_DIR", "")
|
||||
t.Setenv("DOUYU_SUCCESS_DIR", "")
|
||||
|
||||
paths := DefaultAppPaths()
|
||||
if paths.DataDir != dir {
|
||||
t.Fatalf("DataDir = %q, want %q", paths.DataDir, dir)
|
||||
}
|
||||
if paths.ConfigFile != filepath.Join(dir, "config.json") {
|
||||
t.Fatalf("ConfigFile = %q", paths.ConfigFile)
|
||||
}
|
||||
if paths.AccountFile != filepath.Join(dir, "accounts.txt") {
|
||||
t.Fatalf("AccountFile = %q", paths.AccountFile)
|
||||
}
|
||||
if paths.LogDir != filepath.Join(dir, "logs") || paths.SuccessDir != filepath.Join(dir, "success_images") {
|
||||
t.Fatalf("应用数据子目录异常: logs=%q success=%q", paths.LogDir, paths.SuccessDir)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user