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

     1  package message
     2  
     3  import (
     4  	"bytes"
     5  	"encoding/json"
     6  	"errors"
     7  	"io"
     8  	"os"
     9  
    10  	"github.com/Jeffail/benthos/v3/lib/message/metadata"
    11  	"github.com/Jeffail/benthos/v3/lib/types"
    12  )
    13  
    14  var useNumber = true
    15  
    16  func init() {
    17  	if os.Getenv("BENTHOS_USE_NUMBER") == "false" {
    18  		useNumber = false
    19  	}
    20  }
    21  
    22  //------------------------------------------------------------------------------
    23  
    24  // Part is an implementation of types.Part, containing the contents and metadata
    25  // of a message part.
    26  type Part struct {
    27  	data      []byte
    28  	metadata  types.Metadata
    29  	jsonCache interface{}
    30  }
    31  
    32  // NewPart initializes a new message part.
    33  func NewPart(data []byte) *Part {
    34  	return &Part{
    35  		data: data,
    36  	}
    37  }
    38  
    39  //------------------------------------------------------------------------------
    40  
    41  // Copy creates a shallow copy of the message part.
    42  func (p *Part) Copy() types.Part {
    43  	var clonedMeta types.Metadata
    44  	if p.metadata != nil {
    45  		clonedMeta = p.metadata.Copy()
    46  	}
    47  	return &Part{
    48  		data:      p.data,
    49  		metadata:  clonedMeta,
    50  		jsonCache: p.jsonCache,
    51  	}
    52  }
    53  
    54  // DeepCopy creates a new deep copy of the message part.
    55  func (p *Part) DeepCopy() types.Part {
    56  	var clonedMeta types.Metadata
    57  	if p.metadata != nil {
    58  		clonedMeta = p.metadata.Copy()
    59  	}
    60  	var clonedJSON interface{}
    61  	if p.jsonCache != nil {
    62  		var err error
    63  		if clonedJSON, err = cloneGeneric(p.jsonCache); err != nil {
    64  			clonedJSON = nil
    65  		}
    66  	}
    67  	var np []byte
    68  	if p.data != nil {
    69  		np = make([]byte, len(p.data))
    70  		copy(np, p.data)
    71  	}
    72  	return &Part{
    73  		data:      np,
    74  		metadata:  clonedMeta,
    75  		jsonCache: clonedJSON,
    76  	}
    77  }
    78  
    79  //------------------------------------------------------------------------------
    80  
    81  // Get returns the body of the message part.
    82  func (p *Part) Get() []byte {
    83  	if p.data == nil && p.jsonCache != nil {
    84  		var buf bytes.Buffer
    85  		enc := json.NewEncoder(&buf)
    86  		enc.SetEscapeHTML(false)
    87  		err := enc.Encode(p.jsonCache)
    88  		if err != nil {
    89  			return nil
    90  		}
    91  		if buf.Len() > 1 {
    92  			p.data = buf.Bytes()[:buf.Len()-1]
    93  		}
    94  	}
    95  	return p.data
    96  }
    97  
    98  // Metadata returns the metadata of the message part.
    99  func (p *Part) Metadata() types.Metadata {
   100  	if p.metadata == nil {
   101  		p.metadata = metadata.New(nil)
   102  	}
   103  	return p.metadata
   104  }
   105  
   106  // JSON attempts to parse the message part as a JSON document and returns the
   107  // result.
   108  func (p *Part) JSON() (interface{}, error) {
   109  	if p.jsonCache != nil {
   110  		return p.jsonCache, nil
   111  	}
   112  	if p.data == nil {
   113  		return nil, ErrMessagePartNotExist
   114  	}
   115  
   116  	dec := json.NewDecoder(bytes.NewReader(p.data))
   117  	if useNumber {
   118  		dec.UseNumber()
   119  	}
   120  
   121  	err := dec.Decode(&p.jsonCache)
   122  	if err != nil {
   123  		return nil, err
   124  	}
   125  
   126  	var dummy json.RawMessage
   127  	if err = dec.Decode(&dummy); err == io.EOF {
   128  		return p.jsonCache, nil
   129  	}
   130  
   131  	p.jsonCache = nil
   132  	if err = dec.Decode(&dummy); err == nil || err == io.EOF {
   133  		err = errors.New("message contains multiple valid documents")
   134  	}
   135  	return nil, err
   136  }
   137  
   138  // Set the value of the message part.
   139  func (p *Part) Set(data []byte) types.Part {
   140  	p.data = data
   141  	p.jsonCache = nil
   142  	return p
   143  }
   144  
   145  // SetMetadata sets the metadata of a message part.
   146  func (p *Part) SetMetadata(meta types.Metadata) types.Part {
   147  	p.metadata = meta
   148  	return p
   149  }
   150  
   151  // SetJSON attempts to marshal a JSON document into a byte slice and stores the
   152  // result as the contents of the message part.
   153  func (p *Part) SetJSON(jObj interface{}) error {
   154  	p.data = nil
   155  	if jObj == nil {
   156  		p.data = []byte(`null`)
   157  	}
   158  	p.jsonCache = jObj
   159  	return nil
   160  }
   161  
   162  //------------------------------------------------------------------------------
   163  
   164  // IsEmpty returns true if the message part is empty.
   165  func (p *Part) IsEmpty() bool {
   166  	return len(p.data) == 0 && p.jsonCache == nil
   167  }
   168  
   169  //------------------------------------------------------------------------------