From 3d5ee555bbc4943d30367166fae2e385f15fd8f3 Mon Sep 17 00:00:00 2001 From: liwei Date: Fri, 9 Aug 2024 12:40:45 +0800 Subject: [PATCH] fix: web config file not loaded when is relative path --- cmd/server.go | 32 ++- cmd/web/flags.go | 8 +- cmd/web/main.go | 1 + pkg/base/model.go | 24 +- pkg/base/model_test.go | 264 ++++++++++++++++++ pkg/rest/model/server.go | 14 +- .../modules/setting/views/setting_view.dart | 2 +- 7 files changed, 324 insertions(+), 21 deletions(-) create mode 100644 pkg/base/model_test.go diff --git a/cmd/server.go b/cmd/server.go index 1816d933c..667e01a83 100644 --- a/cmd/server.go +++ b/cmd/server.go @@ -27,19 +27,29 @@ func Start(cfg *model.StartConfig) { panic(err) } if downloadCfg.FirstLoad { + // Set default download config + if cfg.DownloadConfig != nil { + cfg.DownloadConfig.Merge(downloadCfg) + // TODO Use PatchConfig + rest.Downloader.PutConfig(cfg.DownloadConfig) + downloadCfg = cfg.DownloadConfig + } + + downloadDir := downloadCfg.DownloadDir // Set default download dir, in docker, it will be ${exe}/Downloads, else it will be ${user}/Downloads - var downloadDir string - if base.InDocker == "true" { - downloadDir = filepath.Join(filepath.Dir(cfg.StorageDir), "Downloads") - } else { - userDir, err := os.UserHomeDir() - if err == nil { - downloadDir = filepath.Join(userDir, "Downloads") + if downloadDir == "" { + if base.InDocker == "true" { + downloadDir = filepath.Join(filepath.Dir(cfg.StorageDir), "Downloads") + } else { + userDir, err := os.UserHomeDir() + if err == nil { + downloadDir = filepath.Join(userDir, "Downloads") + } + } + if downloadDir != "" { + downloadCfg.DownloadDir = downloadDir + rest.Downloader.PutConfig(downloadCfg) } - } - if downloadDir != "" { - downloadCfg.DownloadDir = downloadDir - rest.Downloader.PutConfig(downloadCfg) } } watchExit() diff --git a/cmd/web/flags.go b/cmd/web/flags.go index 36f74002b..3d0537b56 100644 --- a/cmd/web/flags.go +++ b/cmd/web/flags.go @@ -4,6 +4,7 @@ import ( "encoding/json" "flag" "fmt" + "github.com/GopeedLab/gopeed/pkg/base" "os" "path/filepath" ) @@ -15,6 +16,8 @@ type args struct { Password *string `json:"password"` ApiToken *string `json:"apiToken"` StorageDir *string `json:"storageDir"` + // DownloadConfig when the first time to start the server, it will be configured as initial value + DownloadConfig *base.DownloaderStoreConfig `json:"downloadConfig"` configPath *string } @@ -25,7 +28,7 @@ func parse() *args { cliArgs.Port = flag.Int("P", 9999, "Bind Port") cliArgs.Username = flag.String("u", "gopeed", "HTTP Basic Auth Username") cliArgs.Password = flag.String("p", "", "HTTP Basic Auth Pwd") - cliArgs.ApiToken = flag.String("T", "", "API token, that can only be used when basic authentication is enabled.") + cliArgs.ApiToken = flag.String("T", "", "API token, it must be configured when using HTTP API in the case of enabling basic authentication") cliArgs.StorageDir = flag.String("d", "", "Storage directory") cliArgs.configPath = flag.String("c", "./config.json", "Config file path") flag.Parse() @@ -57,8 +60,9 @@ func loadConfig(path string) *args { var args args if !filepath.IsAbs(path) { - dir, err := filepath.Abs(filepath.Dir(os.Args[0])) + dir, err := os.Getwd() if err != nil { + fmt.Println("config dir get failed, reason:" + err.Error()) return &args } path = filepath.Join(dir, path) diff --git a/cmd/web/main.go b/cmd/web/main.go index 76a15d035..d62655709 100644 --- a/cmd/web/main.go +++ b/cmd/web/main.go @@ -48,6 +48,7 @@ func main() { Storage: model.StorageBolt, StorageDir: filepath.Join(dir, "storage"), ApiToken: *args.ApiToken, + DownloadConfig: args.DownloadConfig, ProductionMode: true, WebEnable: true, WebFS: sub, diff --git a/pkg/base/model.go b/pkg/base/model.go index 984639e78..9d5bd5fc2 100644 --- a/pkg/base/model.go +++ b/pkg/base/model.go @@ -147,11 +147,33 @@ func (cfg *DownloaderStoreConfig) Init() *DownloaderStoreConfig { if cfg.MaxRunning == 0 { cfg.MaxRunning = 5 } + if cfg.ProtocolConfig == nil { + cfg.ProtocolConfig = make(map[string]any) + } if cfg.Proxy == nil { cfg.Proxy = &DownloaderProxyConfig{} } + return cfg +} + +func (cfg *DownloaderStoreConfig) Merge(beforeCfg *DownloaderStoreConfig) *DownloaderStoreConfig { + if beforeCfg == nil { + return cfg + } + if cfg.DownloadDir == "" { + cfg.DownloadDir = beforeCfg.DownloadDir + } + if cfg.MaxRunning == 0 { + cfg.MaxRunning = beforeCfg.MaxRunning + } if cfg.ProtocolConfig == nil { - cfg.ProtocolConfig = make(map[string]any) + cfg.ProtocolConfig = beforeCfg.ProtocolConfig + } + if cfg.Extra == nil { + cfg.Extra = beforeCfg.Extra + } + if cfg.Proxy == nil { + cfg.Proxy = beforeCfg.Proxy } return cfg } diff --git a/pkg/base/model_test.go b/pkg/base/model_test.go new file mode 100644 index 000000000..f218162ea --- /dev/null +++ b/pkg/base/model_test.go @@ -0,0 +1,264 @@ +package base + +import ( + "reflect" + "testing" +) + +func TestDownloaderStoreConfig_Init(t *testing.T) { + tests := []struct { + name string + fields *DownloaderStoreConfig + want *DownloaderStoreConfig + }{ + { + "Init", + &DownloaderStoreConfig{}, + &DownloaderStoreConfig{ + MaxRunning: 5, + ProtocolConfig: map[string]any{}, + Proxy: &DownloaderProxyConfig{}, + }, + }, + { + "Init MaxRunning", + &DownloaderStoreConfig{ + MaxRunning: 10, + }, + &DownloaderStoreConfig{ + MaxRunning: 10, + ProtocolConfig: map[string]any{}, + Proxy: &DownloaderProxyConfig{}, + }, + }, + { + "Init ProtocolConfig", + &DownloaderStoreConfig{ + ProtocolConfig: map[string]any{ + "key": "value", + }, + }, + &DownloaderStoreConfig{ + MaxRunning: 5, + ProtocolConfig: map[string]any{ + "key": "value", + }, + Proxy: &DownloaderProxyConfig{}, + }, + }, + { + "Init Proxy", + &DownloaderStoreConfig{ + Proxy: &DownloaderProxyConfig{ + Enable: true, + }, + }, + &DownloaderStoreConfig{ + MaxRunning: 5, + ProtocolConfig: map[string]any{}, + Proxy: &DownloaderProxyConfig{ + Enable: true, + }, + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + cfg := &DownloaderStoreConfig{ + FirstLoad: tt.fields.FirstLoad, + DownloadDir: tt.fields.DownloadDir, + MaxRunning: tt.fields.MaxRunning, + ProtocolConfig: tt.fields.ProtocolConfig, + Extra: tt.fields.Extra, + Proxy: tt.fields.Proxy, + } + if got := cfg.Init(); !reflect.DeepEqual(got, tt.want) { + t.Errorf("Init() = %v, want %v", got, tt.want) + } + }) + } +} + +func TestDownloaderStoreConfig_Merge(t *testing.T) { + type args struct { + beforeCfg *DownloaderStoreConfig + } + tests := []struct { + name string + fields *DownloaderStoreConfig + args args + want *DownloaderStoreConfig + }{ + { + "Merge Nil", + &DownloaderStoreConfig{}, + args{ + beforeCfg: nil, + }, + &DownloaderStoreConfig{}, + }, + { + "Merge DownloadDir No Override", + &DownloaderStoreConfig{ + DownloadDir: "before", + }, + args{ + beforeCfg: &DownloaderStoreConfig{ + DownloadDir: "after", + }, + }, + &DownloaderStoreConfig{ + DownloadDir: "before", + }, + }, + { + "Merge DownloadDir Override", + &DownloaderStoreConfig{}, + args{ + beforeCfg: &DownloaderStoreConfig{ + DownloadDir: "after", + }, + }, + &DownloaderStoreConfig{ + DownloadDir: "after", + }, + }, + { + "Merge MaxRunning No Override", + &DownloaderStoreConfig{ + MaxRunning: 1, + }, + args{ + beforeCfg: &DownloaderStoreConfig{ + MaxRunning: 10, + }, + }, + &DownloaderStoreConfig{ + MaxRunning: 1, + }, + }, + { + "Merge MaxRunning Override", + &DownloaderStoreConfig{}, + args{ + beforeCfg: &DownloaderStoreConfig{ + MaxRunning: 10, + }, + }, + &DownloaderStoreConfig{ + MaxRunning: 10, + }, + }, + { + "Merge ProtocolConfig No Override", + &DownloaderStoreConfig{ + ProtocolConfig: map[string]any{}, + }, + args{ + beforeCfg: &DownloaderStoreConfig{ + ProtocolConfig: map[string]any{ + "key": "after", + }, + }, + }, + &DownloaderStoreConfig{ + ProtocolConfig: map[string]any{}, + }, + }, + { + "Merge ProtocolConfig Override", + &DownloaderStoreConfig{}, + args{ + beforeCfg: &DownloaderStoreConfig{ + ProtocolConfig: map[string]any{ + "key": "after", + }, + }, + }, + &DownloaderStoreConfig{ + ProtocolConfig: map[string]any{ + "key": "after", + }, + }, + }, + { + "Merge Extra No Override", + &DownloaderStoreConfig{ + Extra: map[string]any{}, + }, + args{ + beforeCfg: &DownloaderStoreConfig{ + Extra: map[string]any{ + "key": "after", + }, + }, + }, + &DownloaderStoreConfig{ + Extra: map[string]any{}, + }, + }, + { + "Merge Extra Override", + &DownloaderStoreConfig{}, + args{ + beforeCfg: &DownloaderStoreConfig{ + Extra: map[string]any{ + "key": "after", + }, + }, + }, + &DownloaderStoreConfig{ + Extra: map[string]any{ + "key": "after", + }, + }, + }, + { + "Merge Proxy No Override", + &DownloaderStoreConfig{ + Proxy: &DownloaderProxyConfig{}, + }, + args{ + beforeCfg: &DownloaderStoreConfig{ + Proxy: &DownloaderProxyConfig{ + Scheme: "http", + }, + }, + }, + &DownloaderStoreConfig{ + Proxy: &DownloaderProxyConfig{}, + }, + }, + { + "Merge Proxy Override", + &DownloaderStoreConfig{}, + args{ + beforeCfg: &DownloaderStoreConfig{ + Proxy: &DownloaderProxyConfig{ + Scheme: "http", + }, + }, + }, + &DownloaderStoreConfig{ + Proxy: &DownloaderProxyConfig{ + Scheme: "http", + }, + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + cfg := &DownloaderStoreConfig{ + FirstLoad: tt.fields.FirstLoad, + DownloadDir: tt.fields.DownloadDir, + MaxRunning: tt.fields.MaxRunning, + ProtocolConfig: tt.fields.ProtocolConfig, + Extra: tt.fields.Extra, + Proxy: tt.fields.Proxy, + } + if got := cfg.Merge(tt.args.beforeCfg); !reflect.DeepEqual(got, tt.want) { + t.Errorf("Merge() = %v, want %v", got, tt.want) + } + }) + } +} diff --git a/pkg/rest/model/server.go b/pkg/rest/model/server.go index 9f8b363c5..03bda4496 100644 --- a/pkg/rest/model/server.go +++ b/pkg/rest/model/server.go @@ -2,6 +2,7 @@ package model import ( "encoding/base64" + "github.com/GopeedLab/gopeed/pkg/base" "io/fs" ) @@ -13,12 +14,13 @@ const ( ) type StartConfig struct { - Network string `json:"network"` - Address string `json:"address"` - RefreshInterval int `json:"refreshInterval"` - Storage Storage `json:"storage"` - StorageDir string `json:"storageDir"` - ApiToken string `json:"apiToken"` + Network string `json:"network"` + Address string `json:"address"` + RefreshInterval int `json:"refreshInterval"` + Storage Storage `json:"storage"` + StorageDir string `json:"storageDir"` + ApiToken string `json:"apiToken"` + DownloadConfig *base.DownloaderStoreConfig `json:"downloadConfig"` ProductionMode bool diff --git a/ui/flutter/lib/app/modules/setting/views/setting_view.dart b/ui/flutter/lib/app/modules/setting/views/setting_view.dart index 837ae8beb..22c7c4760 100644 --- a/ui/flutter/lib/app/modules/setting/views/setting_view.dart +++ b/ui/flutter/lib/app/modules/setting/views/setting_view.dart @@ -337,7 +337,7 @@ class SettingView extends GetView { ); }); final buildBtSeedConfig = _buildConfigItem('seedConfig', - () => 'seedKeep'.tr + (btConfig.seedKeep ? 'on'.tr : 'off'.tr), + () => '${'seedKeep'.tr}(${btConfig.seedKeep ? 'on'.tr : 'off'.tr})', (Key key) { final seedRatioController = TextEditingController(text: btConfig.seedRatio.toString());