From: qydysky Date: Sun, 29 Dec 2024 13:18:27 +0000 (+0800) Subject: Add 环境变量覆盖配置项 (#137) X-Git-Tag: v0.14.27~4 X-Git-Url: http://127.0.0.1:8081/?a=commitdiff_plain;h=883412c9cfed5949beca93a6e2e4ffd6ccc111b1;p=bili_danmu%2F.git Add 环境变量覆盖配置项 (#137) --- diff --git a/CV/Var.go b/CV/Var.go index ffa9fa3..fa32cc6 100644 --- a/CV/Var.go +++ b/CV/Var.go @@ -719,6 +719,110 @@ func (t *Common) loadConf(customConf string) error { t.K_v.Store(k, v) } + // 从环境变量获取 + if v, ok := t.K_v.LoadV("从环境变量覆盖").([]any); ok && len(v) > 0 { + for i := 0; i < len(v); i++ { + if vm, ok := v[i].(map[string]any); ok { + if err := dealEnv(&t.K_v, vm); err != nil { + return err + } + } + } + } + + return nil +} + +var ( + ErrDealEnvUnknowType = errors.New("ErrDealEnvUnknowType") + ErrDealEnvEnvValueTypeNoMatch = errors.New("ErrDealEnvEnvValueTypeNoMatch") + ErrDealEnvKeyNoArray = errors.New("ErrDealEnv") + ErrDealEnvKeyNoMap = errors.New("ErrDealEnvKeyNoMap") + ErrDealEnvKeyArrayNoUInt = errors.New("ErrDealEnvKeyArrayNoUInt") +) + +// vm:{"key":"","type":"","env":""} +func dealEnv(K_v *syncmap.Map, vm map[string]any) error { + _key, ok := vm[`key`].(string) + if !ok || strings.TrimSpace(_key) == `` { + return nil + } + var val any + { + _env, ok := vm[`env`].(string) + if !ok || strings.TrimSpace(_env) == `` { + return nil + } + _val := os.Getenv(_env) + _type, ok := vm[`type`].(string) + if !ok || strings.TrimSpace(_type) == `` { + _type = "string" + } + switch _type { + case `string`: + val = _val + case `float64`: + if v, err := strconv.ParseFloat(_val, 64); err != nil { + return ErrDealEnvEnvValueTypeNoMatch + } else { + val = v + } + case `bool`: + switch strings.ToLower(_val) { + case `true`: + val = true + case `false`: + val = false + default: + return ErrDealEnvEnvValueTypeNoMatch + } + default: + return ErrDealEnvUnknowType + } + } + + _keys := strings.Split(_key, ".") + if len(_keys) == 1 { + K_v.Store(_keys[0], val) + } else { + var key = K_v.LoadV(_keys[0]) + for i := 1; i < len(_keys)-1; i++ { + if strings.Contains(_keys[i], "[") { + if tmp, ok := key.([]any); !ok { + return ErrDealEnvKeyNoArray + } else if n, err := strconv.ParseInt(_keys[i][1:len(_keys[i])-1], 0, 64); err != nil { + return ErrDealEnvKeyArrayNoUInt + } else if int(n) > len(tmp)-1 { + return nil + } else { + key = tmp[int(n)] + } + } else { + if tmp, ok := key.(map[string]any); !ok { + return ErrDealEnvKeyNoMap + } else { + key = tmp[_keys[i]] + } + } + } + if strings.Contains(_keys[len(_keys)-1], "[") { + if tmp, ok := key.([]any); !ok { + return ErrDealEnvKeyNoArray + } else if n, err := strconv.ParseInt(_keys[len(_keys)-1][1:len(_keys[len(_keys)-1])-1], 0, 64); err != nil { + return ErrDealEnvKeyArrayNoUInt + } else if int(n) > len(tmp)-1 { + return nil + } else { + tmp[n] = val + } + } else { + if tmp, ok := key.(map[string]any); !ok { + return ErrDealEnvKeyNoMap + } else { + tmp[_keys[len(_keys)-1]] = val + } + } + } return nil } diff --git a/CV/Var_test.go b/CV/Var_test.go new file mode 100644 index 0000000..877dfb9 --- /dev/null +++ b/CV/Var_test.go @@ -0,0 +1,84 @@ +package cv + +import ( + _ "embed" + "os" + "testing" + + _ "github.com/go-sql-driver/mysql" + _ "github.com/jackc/pgx/v5/stdlib" + syncmap "github.com/qydysky/part/sync" + _ "modernc.org/sqlite" +) + +func TestDealEnv(t *testing.T) { + os.Setenv("tes", "2") + os.Setenv("tes1", "true") + os.Setenv("tes2", "true") + var m syncmap.Map + m.Store("k", float64(1)) + m.Store("b", false) + m.Store("s", "s") + if e := dealEnv(&m, map[string]any{`key`: `k`, `type`: `float64`, `env`: `tes`}); e != nil { + t.Fatal(e) + } + if v, ok := m.LoadV("k").(float64); !ok || v != 2 { + t.Fatal(v) + } + if e := dealEnv(&m, map[string]any{`key`: `b`, `type`: `bool`, `env`: `tes1`}); e != nil { + t.Fatal(e) + } + if v, ok := m.LoadV("b").(bool); !ok || !v { + t.Fatal(v) + } + if e := dealEnv(&m, map[string]any{`key`: `s`, `env`: `tes2`}); e != nil { + t.Fatal(e) + } + if v, ok := m.LoadV("s").(string); !ok || v != "true" { + t.Fatal(v) + } +} + +func TestDealEnv2(t *testing.T) { + os.Setenv("tes", "2") + var m syncmap.Map + m.Store("k", map[string]any{"d": float64(1)}) + if e := dealEnv(&m, map[string]any{`key`: `k.d`, `type`: `float64`, `env`: `tes`}); e != nil { + t.Fatal(e) + } + if v, ok := m.LoadV("k").(map[string]any); !ok { + t.Fatal(v) + } else if v[`d`].(float64) != 2 { + t.Fatal() + } +} + +func TestDealEnv3(t *testing.T) { + os.Setenv("tes", "2") + var m syncmap.Map + m.Store("k", []any{float64(1)}) + if e := dealEnv(&m, map[string]any{`key`: `k.[0]`, `type`: `float64`, `env`: `tes`}); e != nil { + t.Fatal(e) + } + if v, ok := m.LoadV("k").([]any); !ok { + t.Fatal(v) + } else if v[0].(float64) != 2 { + t.Fatal() + } +} + +func TestDealEnv4(t *testing.T) { + os.Setenv("tes", "2") + var m syncmap.Map + m.Store("k", []any{map[string]any{"d": float64(1)}}) + if e := dealEnv(&m, map[string]any{`key`: `k.[0].d`, `type`: `float64`, `env`: `tes`}); e != nil { + t.Fatal(e) + } + if v, ok := m.LoadV("k").([]any); !ok { + t.Fatal(v) + } else if q, ok := v[0].(map[string]any); !ok { + t.Fatal(q) + } else if q["d"].(float64) != 2 { + t.Fatal(q["d"]) + } +} diff --git a/README.md b/README.md index 92d62f1..41316ac 100644 --- a/README.md +++ b/README.md @@ -74,6 +74,37 @@ ### 说明 本项目使用github action自动构建,构建过程详见[yml](https://github.com/qydysky/bili_danmu/blob/master/.github/workflows/go.yml) +#### 环境变量覆盖配置项 +添加配置项`从环境变量覆盖`(>v0.14.26)。将在配置文件都加载后,用以配置环境变量覆盖配置项。 + +- `key`为配置键名(例如:`Web服务地址`),为空时将忽略。 +- `type`为类型,可选`string`,`bool`,`float64`。为空(默认)为`string`。当为`int`等类型时,也填为`float64` +- `env`为env名(例如:`addr`),为空时将忽略。 + +例子: +```json +{ + "Web服务地址":"0.0.0.0:20000", + "从环境变量覆盖": [ + { + "key": "Web服务地址", + "env": "addr" + } + ] +} +``` +配置环境变量: +``` +export addr=0.0.0.0:22000 +``` +启动后,程序将监听22000端口而非20000端口 + +注意: + +- 当要配置的键为数组时,使用`a.[n]`表示第n个,n为非负整数。当数组长度小于n时,将忽略。 +- 当要配置的键为map时,使用`a.b`表示a下的b键。当b不存在时,将忽略。 +- 注意核对配置的类型是正确的,否则可能会导致配置无效。 + #### cookie自定义位置 配置文件添加配置项`cookie路径`(>v0.14.26),默认为`./cookie.txt` diff --git a/demo/config/config_K_v.json b/demo/config/config_K_v.json index 3886c90..9ded9bc 100644 --- a/demo/config/config_K_v.json +++ b/demo/config/config_K_v.json @@ -219,5 +219,12 @@ "登陆二维码-白":"OO", "登陆二维码-黑":" ", "服务器时区-help":"用于正确解析服务器响应中的时间,整数,单位秒,正数是UTC以东,默认0", - "服务器时区":0 + "服务器时区":0, + "从环境变量覆盖": [ + { + "key": "", + "type": "", + "env": "" + } + ] }