github.com/machinefi/w3bstream@v1.6.5-rc9.0.20240426031326-b8c7c4876e72/pkg/depends/conf/env/env_encoder.go (about) 1 package env 2 3 import ( 4 "go/ast" 5 "reflect" 6 7 "github.com/machinefi/w3bstream/pkg/depends/base/types" 8 "github.com/machinefi/w3bstream/pkg/depends/x/reflectx" 9 "github.com/machinefi/w3bstream/pkg/depends/x/textx" 10 ) 11 12 type Encoder struct { 13 vars *Vars 14 sets map[string]map[string]bool 15 } 16 17 func NewEncoder(vars *Vars) *Encoder { return &Encoder{vars: vars} } 18 19 func (e *Encoder) Encode(v interface{}) ([]byte, error) { 20 w := NewPathWalker() 21 rv, ok := v.(reflect.Value) 22 if !ok { 23 rv = reflect.ValueOf(v) 24 } 25 if err := e.scan(w, rv); err != nil { 26 return nil, err 27 } 28 return e.vars.Bytes(), nil 29 } 30 31 func (e *Encoder) SecurityEncode(v interface{}) ([]byte, error) { 32 w := NewPathWalker() 33 rv, ok := v.(reflect.Value) 34 if !ok { 35 rv = reflect.ValueOf(v) 36 } 37 if err := e.scan(w, rv); err != nil { 38 return nil, err 39 } 40 return e.vars.MaskBytes(), nil 41 } 42 43 func (e *Encoder) flag(key string, flags map[string]bool) { 44 if e.sets == nil { 45 e.sets = make(map[string]map[string]bool) 46 } 47 e.sets[key] = flags 48 } 49 50 func (e *Encoder) scan(w *PathWalker, rv reflect.Value) error { 51 kind := rv.Kind() 52 53 setter := func(rv reflect.Value) error { 54 key := w.String() 55 v := &Var{Name: key} 56 if e.sets != nil { 57 if flags, ok := e.sets[key]; ok { 58 v.SetMeta(flags) 59 } else { 60 name := StringifyPath(w.path[0 : len(w.path)-1]...) 61 if flags, ok := e.sets[name]; ok { 62 v.SetMeta(flags) 63 } 64 } 65 } 66 if s, ok := rv.Interface().(types.SecurityString); ok { 67 v.Mask = s.SecurityString() 68 } 69 text, err := textx.MarshalText(rv) 70 if err != nil { 71 return err 72 } 73 v.Value = string(text) 74 e.vars.Set(v) 75 return nil 76 } 77 78 switch kind { 79 case reflect.Ptr: 80 if rv.IsNil() { 81 return nil 82 } 83 return e.scan(w, rv.Elem()) 84 case reflect.Func, reflect.Interface, reflect.Chan, reflect.Map: // skip 85 default: 86 rt := rv.Type() 87 if _, ok := rv.Interface().(types.TextMarshaler); ok { 88 return setter(rv) 89 } 90 switch kind { 91 case reflect.Array, reflect.Slice: 92 for i := 0; i < rv.Len(); i++ { 93 w.Enter(i) 94 if err := e.scan(w, rv.Index(i)); err != nil { 95 return err 96 } 97 w.Exit() 98 } 99 case reflect.Struct: 100 for i := 0; i < rv.NumField(); i++ { 101 var flags map[string]bool 102 ft := rt.Field(i) 103 name := ft.Name 104 105 if !ast.IsExported(name) { 106 continue 107 } 108 if tag, ok := ft.Tag.Lookup("env"); ok { 109 key, _flags := reflectx.TagValueAndFlags(tag) 110 if key == "-" { 111 continue 112 } 113 if key != "" { 114 name = key 115 } 116 flags = _flags 117 } 118 inline := flags == nil && ft.Anonymous && 119 reflectx.DeRef(ft.Type).Kind() == reflect.Struct 120 if !inline { 121 w.Enter(name) 122 } 123 if flags != nil { 124 e.flag(w.String(), flags) 125 } 126 if err := e.scan(w, rv.Field(i)); err != nil { 127 return err 128 } 129 if !inline { 130 w.Exit() 131 } 132 } 133 default: 134 return setter(rv) 135 } 136 } 137 return nil 138 }