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 //------------------------------------------------------------------------------