Skip to content

Commit

Permalink
Merge pull request #14 from ryouaki/v1.3.9
Browse files Browse the repository at this point in the history
更新配置文件读取模块
  • Loading branch information
ryouaki committed Oct 10, 2023
2 parents cc49327 + 550c94c commit 56e8683
Show file tree
Hide file tree
Showing 4 changed files with 236 additions and 1 deletion.
230 changes: 230 additions & 0 deletions env/env.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,230 @@
package env

import (
"fmt"
"io/ioutil"
"os"
"reflect"
"strconv"
"strings"

"github.com/go-yaml/yaml"
)

type EnvConfig struct {
env string
data *interface{}
}

var envConfig = &EnvConfig{}

// load configuration file
func LoadEnvConfig(file string, mode string) error {
var _file string

if mode != "" {
_file = strings.Replace(file, "yaml", mode+".yaml", 1)
}

data, failed := loadFile(file)

dataSrc, failedSrc := loadFile(_file)

// 如果两个文件都加载成功,则进行merge操作,
// 如果只有一个文件加载成功,则使用加载成功的文件
if data != nil && dataSrc != nil && failed == nil && failedSrc == nil {
envConfig.SetEnv(mode)
envConfig.SetData(data)
envConfig.MergeData(dataSrc)
} else if data != nil && failed == nil {
envConfig.SetEnv(mode)
envConfig.SetData(data)
} else if dataSrc != nil && failedSrc == nil {
envConfig.SetEnv(mode)
envConfig.SetData(dataSrc)
} else {
return fmt.Errorf("file [ %s ] load failed", file)
}

return nil
}

func loadFile(file string) (*interface{}, error) {
if err := hasFile(file); err != nil {
return nil, err
}
data, failed := ioutil.ReadFile(file)
if failed != nil {
return nil, failed
}

var _data = new(interface{})

failed = yaml.Unmarshal(data, _data)
if failed != nil {
return nil, failed
}

return _data, nil
}

func (p *EnvConfig) SetEnv(mode string) {
p.env = mode
}

func (p *EnvConfig) SetData(data any) {
p.data = data.(*interface{})
}

func (p *EnvConfig) MergeData(data any) interface{} {
srcData := *p.data
distData := (data.(*interface{}))

retData := mergeKeyForData(&srcData, distData)
envConfig.SetData(&retData)

return &retData
}

func (p *EnvConfig) GetRootValue() interface{} {
return *p.data
}

// Get the value from root
func GetRootValue() interface{} {
return envConfig.GetRootValue()
}

// Get the value from root for map
func GetRootMapValue() map[interface{}]interface{} {
data := envConfig.GetRootValue()
if data == nil {
return nil
}
return data.(map[interface{}]interface{})
}

// Get the value by path like below
// file.yaml
// test: test
// test2:
// test3: test333
/// GetValue("test2.test3") ===> test333
func GetValue(path string) (interface{}, error) {
val, err := getValueByPath(path)
return val, err
}

func getValueByPath(path string) (interface{}, error) {
words := strings.Split(path, ".")
data := GetRootMapValue()
if data == nil {
return nil, fmt.Errorf("No key [ %s ] found!", path)
}

len := len(words)
var val interface{}
var hasKey bool
for idx, work := range words {
val, hasKey = getValueByKey(work, data)

if !hasKey {
return nil, fmt.Errorf("No key [ %s ] found!", path)
}

if idx < len-1 {
data = val.(map[interface{}]interface{})
} else {
return val, nil
}
}
return nil, nil
}

func getValueByKey(key string, data map[interface{}]interface{}) (interface{}, bool) {
keys := strings.FieldsFunc(key, func(r rune) bool {
return string(r) == "["
})
var val interface{}
var hasKey bool
sliceLen := len(keys)

if sliceLen > 1 {
for i, k := range keys {
if strings.HasSuffix(k, "]") {
keys[i] = strings.Replace(k, "]", "", 1)
}
}

val, hasKey = data[keys[0]]

if !hasKey {
return nil, false
}

_val, isOk := val.([]interface{})

if !isOk {
return nil, false
}

for i := 1; i < sliceLen; i++ {
idx, err := strconv.Atoi(keys[i])
if err != nil || len(_val) <= idx {
return nil, false
}

newVal := _val[idx]

if i < sliceLen-1 && isArray(newVal) {
_val = newVal.([]interface{})
} else if i < sliceLen-1 {
return nil, false
} else {
return newVal, true
}
}
}

val, hasKey = data[keys[0]]

return val, hasKey
}

func isArray(param any) bool {
val := reflect.ValueOf(param)
if val.Kind() == reflect.Array || val.Kind() == reflect.Slice {
return true
}
return false
}

func kind(param any) reflect.Kind {
kind := reflect.ValueOf(param)
return kind.Kind()
}

func hasFile(file string) error {
if _, err := os.Stat(file); err != nil {
if os.IsNotExist(err) {
return err
}
}
return nil
}

func mergeKeyForData(a *interface{}, b *interface{}) interface{} {
aa := (*a).(map[interface{}]interface{})
bb := (*b).(map[interface{}]interface{})

for key, val := range bb {
newVal, hasKey := aa[key]
// 如果不存在的key或者类型不同的key直接复制过去
if !hasKey || kind(val) != kind(newVal) || kind(val) != reflect.Map {
aa[key] = val
} else {
aa[key] = mergeKeyForData(&newVal, &val)
}
}
return aa
}
Empty file added env/env.md
Empty file.
5 changes: 4 additions & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,7 @@ go 1.17

require github.com/go-redis/redis v6.15.9+incompatible

require github.com/issue9/assert v1.5.0 // indirect
require (
github.com/go-yaml/yaml v2.1.0+incompatible
github.com/issue9/assert v1.5.0 // indirect
)
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
github.com/go-redis/redis v6.15.9+incompatible h1:K0pv1D7EQUjfyoMql+r/jZqCLizCGKFlFgcHWWmHQjg=
github.com/go-redis/redis v6.15.9+incompatible/go.mod h1:NAIEuMOZ/fxfXJIrKDQDz8wamY7mA7PouImQ2Jvg6kA=
github.com/go-yaml/yaml v2.1.0+incompatible h1:RYi2hDdss1u4YE7GwixGzWwVo47T8UQwnTLB6vQiq+o=
github.com/go-yaml/yaml v2.1.0+incompatible/go.mod h1:w2MrLa16VYP0jy6N7M5kHaCkaLENm+P+Tv+MfurjSw0=
github.com/issue9/assert v1.5.0 h1:9N71cQh6lt9/3y/WnB2lP0AuCxnTwunTToajoWnVD8M=
github.com/issue9/assert v1.5.0/go.mod h1:Yktk83hAVl1SPSYtd9kjhBizuiBIqUQyj+D5SE2yjVY=

0 comments on commit 56e8683

Please sign in to comment.