mirror of
https://github.com/GopeedLab/gopeed.git
synced 2026-11-04 15:49:49 +00:00
200 lines
5.3 KiB
Go
200 lines
5.3 KiB
Go
package main
|
|
|
|
import (
|
|
"encoding/json"
|
|
"flag"
|
|
"os"
|
|
"path/filepath"
|
|
"reflect"
|
|
"strconv"
|
|
"strings"
|
|
|
|
"github.com/GopeedLab/gopeed/pkg/base"
|
|
)
|
|
|
|
type args struct {
|
|
Address *string `json:"address"`
|
|
Port *int `json:"port"`
|
|
Username *string `json:"username"`
|
|
Password *string `json:"password"`
|
|
ApiToken *string `json:"apiToken"`
|
|
StorageDir *string `json:"storageDir"`
|
|
WhiteDownloadDirs []string `json:"whiteDownloadDirs"`
|
|
// DownloadConfig when the first time to start the server, it will be configured as initial value
|
|
DownloadConfig *base.DownloaderStoreConfig `json:"downloadConfig"`
|
|
|
|
configPath *string
|
|
}
|
|
|
|
func parse() *args {
|
|
cfg := &args{}
|
|
|
|
cliConfig := loadCliArgs()
|
|
loadConfigFile(cfg, *cliConfig.configPath)
|
|
loadEnvVars(cfg)
|
|
// override with non-default command line arguments
|
|
overrideWithCliArgs(cfg, cliConfig)
|
|
// set default values
|
|
setDefaults(cfg, cliConfig)
|
|
return cfg
|
|
}
|
|
|
|
// loadCliArgs parses command line arguments and returns initial config
|
|
func loadCliArgs() *args {
|
|
cfg := &args{}
|
|
cfg.Address = flag.String("A", "0.0.0.0", "Bind Address")
|
|
cfg.Port = flag.Int("P", 9999, "Bind Port")
|
|
cfg.Username = flag.String("u", "gopeed", "Web Authentication Username")
|
|
cfg.Password = flag.String("p", "", "Web Authentication Password, if no password is set, web authentication will not be enabled")
|
|
cfg.ApiToken = flag.String("T", "", "API token, it must be configured when using HTTP API in the case of enabling web authentication")
|
|
cfg.StorageDir = flag.String("d", "", "Storage directory")
|
|
whiteDownloadDirs := flag.String("w", "", "White download directories, comma-separated")
|
|
cfg.configPath = flag.String("c", "./config.json", "Config file path")
|
|
flag.Parse()
|
|
|
|
// Parse white download directories from comma-separated string
|
|
if whiteDownloadDirs != nil && *whiteDownloadDirs != "" {
|
|
dirs := strings.Split(*whiteDownloadDirs, ",")
|
|
for i := range dirs {
|
|
dirs[i] = strings.TrimSpace(dirs[i])
|
|
}
|
|
cfg.WhiteDownloadDirs = dirs
|
|
}
|
|
|
|
return cfg
|
|
}
|
|
|
|
// overrideWithCliArgs overrides config with non-empty command line arguments
|
|
func overrideWithCliArgs(cfg *args, cliConfig *args) {
|
|
flag.Visit(func(f *flag.Flag) {
|
|
switch f.Name {
|
|
case "A":
|
|
cfg.Address = cliConfig.Address
|
|
case "P":
|
|
cfg.Port = cliConfig.Port
|
|
case "u":
|
|
cfg.Username = cliConfig.Username
|
|
case "p":
|
|
cfg.Password = cliConfig.Password
|
|
case "T":
|
|
cfg.ApiToken = cliConfig.ApiToken
|
|
case "d":
|
|
cfg.StorageDir = cliConfig.StorageDir
|
|
case "w":
|
|
cfg.WhiteDownloadDirs = cliConfig.WhiteDownloadDirs
|
|
case "c":
|
|
cfg.configPath = cliConfig.configPath
|
|
}
|
|
})
|
|
}
|
|
|
|
// setDefaults sets default values for any unset configuration fields
|
|
func setDefaults(cfg *args, cliConfig *args) {
|
|
if cfg.Address == nil {
|
|
cfg.Address = cliConfig.Address
|
|
}
|
|
if cfg.Port == nil {
|
|
cfg.Port = cliConfig.Port
|
|
}
|
|
if cfg.Username == nil {
|
|
cfg.Username = cliConfig.Username
|
|
}
|
|
if cfg.Password == nil {
|
|
cfg.Password = cliConfig.Password
|
|
}
|
|
if cfg.ApiToken == nil {
|
|
cfg.ApiToken = cliConfig.ApiToken
|
|
}
|
|
if cfg.StorageDir == nil {
|
|
cfg.StorageDir = cliConfig.StorageDir
|
|
}
|
|
}
|
|
|
|
// loadConfigFile loads configuration from file
|
|
func loadConfigFile(cfg *args, configPath string) {
|
|
if !filepath.IsAbs(configPath) {
|
|
dir, err := os.Getwd()
|
|
if err != nil {
|
|
return
|
|
}
|
|
configPath = filepath.Join(dir, configPath)
|
|
}
|
|
|
|
file, err := os.ReadFile(configPath)
|
|
if err != nil {
|
|
if os.IsNotExist(err) {
|
|
return
|
|
}
|
|
return
|
|
}
|
|
|
|
if err = json.Unmarshal(file, cfg); err != nil {
|
|
return
|
|
}
|
|
}
|
|
|
|
// loadEnvVars loads configuration from environment variables with prefix GOPEED_
|
|
func loadEnvVars(cfg *args) {
|
|
v := reflect.ValueOf(cfg).Elem()
|
|
t := reflect.TypeOf(cfg).Elem()
|
|
|
|
for i := 0; i < v.NumField(); i++ {
|
|
field := v.Field(i)
|
|
fieldType := t.Field(i)
|
|
|
|
// Get json tag as environment variable suffix
|
|
jsonTag := fieldType.Tag.Get("json")
|
|
if jsonTag == "" || jsonTag == "-" {
|
|
continue
|
|
}
|
|
|
|
// Remove options like omitempty
|
|
if commaIdx := strings.Index(jsonTag, ","); commaIdx != -1 {
|
|
jsonTag = jsonTag[:commaIdx]
|
|
}
|
|
|
|
// Convert to uppercase and add GOPEED_ prefix
|
|
envKey := "GOPEED_" + strings.ToUpper(jsonTag)
|
|
envValue := os.Getenv(envKey)
|
|
|
|
if envValue == "" {
|
|
continue
|
|
}
|
|
|
|
// Set value based on field type
|
|
if field.Kind() == reflect.Ptr {
|
|
if field.IsNil() {
|
|
// Create new pointer instance
|
|
newVal := reflect.New(field.Type().Elem())
|
|
field.Set(newVal)
|
|
}
|
|
|
|
switch field.Type().Elem().Kind() {
|
|
case reflect.String:
|
|
field.Elem().SetString(envValue)
|
|
case reflect.Int:
|
|
if intVal, err := strconv.Atoi(envValue); err == nil {
|
|
field.Elem().SetInt(int64(intVal))
|
|
}
|
|
default:
|
|
// For complex types like DownloadConfig, try JSON unmarshaling
|
|
if field.Type().Elem() == reflect.TypeOf(base.DownloaderStoreConfig{}) {
|
|
var config base.DownloaderStoreConfig
|
|
if err := json.Unmarshal([]byte(envValue), &config); err == nil {
|
|
field.Set(reflect.ValueOf(&config))
|
|
}
|
|
}
|
|
}
|
|
} else if field.Kind() == reflect.Slice {
|
|
// Handle non-pointer slice types (like []string for WhiteDownloadDirs)
|
|
if field.Type().Elem().Kind() == reflect.String {
|
|
dirs := strings.Split(envValue, ",")
|
|
for i := range dirs {
|
|
dirs[i] = strings.TrimSpace(dirs[i])
|
|
}
|
|
field.Set(reflect.ValueOf(dirs))
|
|
}
|
|
}
|
|
}
|
|
}
|