github.com/Jeffail/benthos/v3@v3.65.0/lib/processor/decode.go (about)

     1  package processor
     2  
     3  import (
     4  	"bytes"
     5  	"encoding/ascii85"
     6  	"encoding/base64"
     7  	"encoding/hex"
     8  	"fmt"
     9  	"io"
    10  	"time"
    11  
    12  	"github.com/Jeffail/benthos/v3/internal/docs"
    13  	"github.com/Jeffail/benthos/v3/internal/tracing"
    14  	"github.com/Jeffail/benthos/v3/lib/log"
    15  	"github.com/Jeffail/benthos/v3/lib/metrics"
    16  	"github.com/Jeffail/benthos/v3/lib/response"
    17  	"github.com/Jeffail/benthos/v3/lib/types"
    18  	"github.com/tilinna/z85"
    19  )
    20  
    21  //------------------------------------------------------------------------------
    22  
    23  func init() {
    24  	Constructors[TypeDecode] = TypeSpec{
    25  		constructor: NewDecode,
    26  		Status:      docs.StatusDeprecated,
    27  		Footnotes: `
    28  ## Alternatives
    29  
    30  All functionality of this processor has been superseded by the
    31  [bloblang](/docs/components/processors/bloblang) processor.`,
    32  		FieldSpecs: docs.FieldSpecs{
    33  			docs.FieldCommon("scheme", "The decoding scheme to use.").HasOptions("hex", "base64", "ascii85", "z85"),
    34  			PartsFieldSpec,
    35  		},
    36  	}
    37  }
    38  
    39  //------------------------------------------------------------------------------
    40  
    41  // DecodeConfig contains configuration fields for the Decode processor.
    42  type DecodeConfig struct {
    43  	Scheme string `json:"scheme" yaml:"scheme"`
    44  	Parts  []int  `json:"parts" yaml:"parts"`
    45  }
    46  
    47  // NewDecodeConfig returns a DecodeConfig with default values.
    48  func NewDecodeConfig() DecodeConfig {
    49  	return DecodeConfig{
    50  		Scheme: "base64",
    51  		Parts:  []int{},
    52  	}
    53  }
    54  
    55  //------------------------------------------------------------------------------
    56  
    57  type decodeFunc func(bytes []byte) ([]byte, error)
    58  
    59  func base64Decode(b []byte) ([]byte, error) {
    60  	e := base64.NewDecoder(base64.StdEncoding, bytes.NewReader(b))
    61  	return io.ReadAll(e)
    62  }
    63  
    64  func hexDecode(b []byte) ([]byte, error) {
    65  	e := hex.NewDecoder(bytes.NewReader(b))
    66  	return io.ReadAll(e)
    67  }
    68  
    69  func ascii85Decode(b []byte) ([]byte, error) {
    70  	e := ascii85.NewDecoder(bytes.NewReader(b))
    71  	return io.ReadAll(e)
    72  }
    73  
    74  func z85Decode(b []byte) ([]byte, error) {
    75  	dec := make([]byte, z85.DecodedLen(len(b)))
    76  	if _, err := z85.Decode(dec, b); err != nil {
    77  		return nil, err
    78  	}
    79  	return dec, nil
    80  }
    81  
    82  func strToDecoder(str string) (decodeFunc, error) {
    83  	switch str {
    84  	case "base64":
    85  		return base64Decode, nil
    86  	case "hex":
    87  		return hexDecode, nil
    88  	case "ascii85":
    89  		return ascii85Decode, nil
    90  	case "z85":
    91  		return z85Decode, nil
    92  	}
    93  	return nil, fmt.Errorf("decode scheme not recognised: %v", str)
    94  }
    95  
    96  //------------------------------------------------------------------------------
    97  
    98  // Decode is a processor that can selectively decode parts of a message
    99  // following a chosen scheme.
   100  type Decode struct {
   101  	conf DecodeConfig
   102  	fn   decodeFunc
   103  
   104  	log   log.Modular
   105  	stats metrics.Type
   106  
   107  	mCount     metrics.StatCounter
   108  	mErr       metrics.StatCounter
   109  	mSent      metrics.StatCounter
   110  	mBatchSent metrics.StatCounter
   111  }
   112  
   113  // NewDecode returns a Decode processor.
   114  func NewDecode(
   115  	conf Config, mgr types.Manager, log log.Modular, stats metrics.Type,
   116  ) (Type, error) {
   117  	cor, err := strToDecoder(conf.Decode.Scheme)
   118  	if err != nil {
   119  		return nil, err
   120  	}
   121  	return &Decode{
   122  		conf:  conf.Decode,
   123  		fn:    cor,
   124  		log:   log,
   125  		stats: stats,
   126  
   127  		mCount:     stats.GetCounter("count"),
   128  		mErr:       stats.GetCounter("error"),
   129  		mSent:      stats.GetCounter("sent"),
   130  		mBatchSent: stats.GetCounter("batch.sent"),
   131  	}, nil
   132  }
   133  
   134  //------------------------------------------------------------------------------
   135  
   136  // ProcessMessage applies the processor to a message, either creating >0
   137  // resulting messages or a response to be sent back to the message source.
   138  func (c *Decode) ProcessMessage(msg types.Message) ([]types.Message, types.Response) {
   139  	c.mCount.Incr(1)
   140  	newMsg := msg.Copy()
   141  
   142  	proc := func(i int, span *tracing.Span, part types.Part) error {
   143  		newBytes, err := c.fn(part.Get())
   144  		if err != nil {
   145  			c.log.Errorf("Failed to decode message part: %v\n", err)
   146  			c.mErr.Incr(1)
   147  			return err
   148  		}
   149  		part.Set(newBytes)
   150  		return nil
   151  	}
   152  
   153  	if newMsg.Len() == 0 {
   154  		return nil, response.NewAck()
   155  	}
   156  
   157  	IteratePartsWithSpanV2(TypeDecode, c.conf.Parts, newMsg, proc)
   158  
   159  	c.mBatchSent.Incr(1)
   160  	c.mSent.Incr(int64(newMsg.Len()))
   161  	msgs := [1]types.Message{newMsg}
   162  	return msgs[:], nil
   163  }
   164  
   165  // CloseAsync shuts down the processor and stops processing requests.
   166  func (c *Decode) CloseAsync() {
   167  }
   168  
   169  // WaitForClose blocks until the processor has closed down.
   170  func (c *Decode) WaitForClose(timeout time.Duration) error {
   171  	return nil
   172  }
   173  
   174  //------------------------------------------------------------------------------