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  }