github.com/Jeffail/benthos/v3@v3.65.0/lib/util/config/sanitised.go (about)

     1  package config
     2  
     3  import (
     4  	"bytes"
     5  	"encoding/json"
     6  	"sort"
     7  
     8  	"gopkg.in/yaml.v3"
     9  )
    10  
    11  //------------------------------------------------------------------------------
    12  
    13  // SanitizeComponent performs a generic sanitation on a component config, where
    14  // a type field describes the type of the component, and the only other fields
    15  // returned in the sanitized result are under the namespace of the type.
    16  func SanitizeComponent(conf interface{}) (Sanitised, error) {
    17  	cBytes, err := yaml.Marshal(conf)
    18  	if err != nil {
    19  		return nil, err
    20  	}
    21  
    22  	hashMap := map[string]interface{}{}
    23  	if err := yaml.Unmarshal(cBytes, &hashMap); err != nil {
    24  		return nil, err
    25  	}
    26  
    27  	return Sanitised(hashMap), nil
    28  }
    29  
    30  //------------------------------------------------------------------------------
    31  
    32  // Sanitised is a general map[string]interface{} type that tries to marshal into
    33  // both YAML and JSON in a way that ensure the 'type' field is always first.
    34  type Sanitised map[string]interface{}
    35  
    36  // SanitForYAML a map to be embedded within a parent object for YAML
    37  // marshalling.
    38  type SanitForYAML map[string]interface{}
    39  
    40  // MarshalYAML return the config as YAML with the 'type' field first.
    41  func (s Sanitised) MarshalYAML() (interface{}, error) {
    42  	dynObj := SanitForYAML{}
    43  
    44  	var typeVal interface{}
    45  	for k, v := range s {
    46  		if k == "type" {
    47  			typeVal = v
    48  		} else {
    49  			dynObj[k] = v
    50  		}
    51  	}
    52  
    53  	return struct {
    54  		Type         interface{} `yaml:"type"`
    55  		SanitForYAML `yaml:",inline"`
    56  	}{
    57  		Type:         typeVal,
    58  		SanitForYAML: dynObj,
    59  	}, nil
    60  }
    61  
    62  // MarshalJSON return the config as a JSON blob with the 'type' field first.
    63  func (s Sanitised) MarshalJSON() ([]byte, error) {
    64  	var keys []string
    65  	var typeVal interface{}
    66  
    67  	for k, v := range s {
    68  		if k == "type" {
    69  			typeVal = v
    70  		} else {
    71  			keys = append(keys, k)
    72  		}
    73  	}
    74  
    75  	sort.Strings(keys)
    76  
    77  	var buf bytes.Buffer
    78  	buf.WriteByte('{')
    79  
    80  	if typeVal != nil {
    81  		typeBytes, err := json.Marshal(typeVal)
    82  		if err != nil {
    83  			return nil, err
    84  		}
    85  
    86  		buf.WriteString(`"type":`)
    87  		buf.Write(typeBytes)
    88  
    89  		if len(keys) > 0 {
    90  			buf.WriteByte(',')
    91  		}
    92  	}
    93  
    94  	for i, k := range keys {
    95  		valBytes, err := json.Marshal(s[k])
    96  		if err != nil {
    97  			return nil, err
    98  		}
    99  
   100  		buf.WriteByte('"')
   101  		buf.WriteString(k)
   102  		buf.WriteString(`":`)
   103  		buf.Write(valBytes)
   104  
   105  		if i < len(keys)-1 {
   106  			buf.WriteByte(',')
   107  		}
   108  	}
   109  
   110  	buf.WriteByte('}')
   111  	return buf.Bytes(), nil
   112  }
   113  
   114  //------------------------------------------------------------------------------