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

     1  package message
     2  
     3  import (
     4  	"encoding/json"
     5  	"fmt"
     6  
     7  	"github.com/Jeffail/benthos/v3/lib/message/metadata"
     8  	"github.com/Jeffail/benthos/v3/lib/types"
     9  )
    10  
    11  //------------------------------------------------------------------------------
    12  
    13  // SetAllMetadata sets the metadata of all message parts to match a provided
    14  // metadata implementation.
    15  func SetAllMetadata(m types.Message, meta types.Metadata) {
    16  	lazy := metadata.LazyCopy(meta)
    17  	m.Iter(func(i int, p types.Part) error {
    18  		p.SetMetadata(lazy)
    19  		return nil
    20  	})
    21  }
    22  
    23  // GetAllBytes returns a 2D byte slice representing the raw byte content of the
    24  // parts of a message.
    25  func GetAllBytes(m types.Message) [][]byte {
    26  	if m.Len() == 0 {
    27  		return nil
    28  	}
    29  	parts := make([][]byte, m.Len())
    30  	m.Iter(func(i int, p types.Part) error {
    31  		parts[i] = p.Get()
    32  		return nil
    33  	})
    34  	return parts
    35  }
    36  
    37  // GetAllBytesLen returns total length of message content in bytes
    38  func GetAllBytesLen(m types.Message) int {
    39  	if m.Len() == 0 {
    40  		return 0
    41  	}
    42  	length := 0
    43  	m.Iter(func(i int, p types.Part) error {
    44  		length += len(p.Get())
    45  		return nil
    46  	})
    47  	return length
    48  }
    49  
    50  //------------------------------------------------------------------------------
    51  
    52  // MetaPartCopy creates a new empty message part by copying any meta fields
    53  // (metadata, context, etc) from a reference part.
    54  func MetaPartCopy(p types.Part) types.Part {
    55  	newPart := WithContext(GetContext(p), NewPart(nil))
    56  	newPart.SetMetadata(p.Metadata().Copy())
    57  	return newPart
    58  }
    59  
    60  //------------------------------------------------------------------------------
    61  
    62  func cloneMap(oldMap map[string]interface{}) (map[string]interface{}, error) {
    63  	var err error
    64  	newMap := make(map[string]interface{}, len(oldMap))
    65  	for k, v := range oldMap {
    66  		if newMap[k], err = cloneGeneric(v); err != nil {
    67  			return nil, err
    68  		}
    69  	}
    70  	return newMap, nil
    71  }
    72  
    73  func cloneCheekyMap(oldMap map[interface{}]interface{}) (map[interface{}]interface{}, error) {
    74  	var err error
    75  	newMap := make(map[interface{}]interface{}, len(oldMap))
    76  	for k, v := range oldMap {
    77  		if newMap[k], err = cloneGeneric(v); err != nil {
    78  			return nil, err
    79  		}
    80  	}
    81  	return newMap, nil
    82  }
    83  
    84  func cloneSlice(oldSlice []interface{}) ([]interface{}, error) {
    85  	var err error
    86  	newSlice := make([]interface{}, len(oldSlice))
    87  	for i, v := range oldSlice {
    88  		if newSlice[i], err = cloneGeneric(v); err != nil {
    89  			return nil, err
    90  		}
    91  	}
    92  	return newSlice, nil
    93  }
    94  
    95  // cloneGeneric is a utility function that recursively copies a generic
    96  // structure usually resulting from a JSON parse.
    97  func cloneGeneric(root interface{}) (interface{}, error) {
    98  	switch t := root.(type) {
    99  	case map[string]interface{}:
   100  		return cloneMap(t)
   101  	case map[interface{}]interface{}:
   102  		return cloneCheekyMap(t)
   103  	case []interface{}:
   104  		return cloneSlice(t)
   105  	case string, []byte, json.Number, uint64, int, int64, float64, bool, json.RawMessage:
   106  		return t, nil
   107  	default:
   108  		// Oops, this means we have 'dirty' types within the JSON object. Our
   109  		// only way to fallback is to marshal/unmarshal the structure, gross!
   110  		if b, err := json.Marshal(root); err == nil {
   111  			var rootCopy interface{}
   112  			if err = json.Unmarshal(b, &rootCopy); err == nil {
   113  				return rootCopy, nil
   114  			}
   115  		}
   116  		return nil, fmt.Errorf("unrecognised type: %T", t)
   117  	}
   118  }
   119  
   120  // CopyJSON recursively creates a deep copy of a JSON structure extracted from a
   121  // message part.
   122  func CopyJSON(root interface{}) (interface{}, error) {
   123  	return cloneGeneric(root)
   124  }
   125  
   126  //------------------------------------------------------------------------------