github.com/Jeffail/benthos/v3@v3.65.0/internal/bundle/outputs.go (about)

     1  package bundle
     2  
     3  import (
     4  	"fmt"
     5  	"sort"
     6  
     7  	"github.com/Jeffail/benthos/v3/internal/docs"
     8  	"github.com/Jeffail/benthos/v3/lib/output"
     9  	"github.com/Jeffail/benthos/v3/lib/types"
    10  )
    11  
    12  // AllOutputs is a set containing every single output that has been imported.
    13  var AllOutputs = &OutputSet{
    14  	specs: map[string]outputSpec{},
    15  }
    16  
    17  //------------------------------------------------------------------------------
    18  
    19  // OutputAdd adds a new output to this environment by providing a constructor
    20  // and documentation.
    21  func (e *Environment) OutputAdd(constructor OutputConstructor, spec docs.ComponentSpec) error {
    22  	return e.outputs.Add(constructor, spec)
    23  }
    24  
    25  // OutputInit attempts to initialise a output from a config.
    26  func (e *Environment) OutputInit(
    27  	conf output.Config,
    28  	mgr NewManagement,
    29  	pipelines ...types.PipelineConstructorFunc,
    30  ) (types.Output, error) {
    31  	return e.outputs.Init(conf, mgr, pipelines...)
    32  }
    33  
    34  // OutputDocs returns a slice of output specs, which document each method.
    35  func (e *Environment) OutputDocs() []docs.ComponentSpec {
    36  	return e.outputs.Docs()
    37  }
    38  
    39  //------------------------------------------------------------------------------
    40  
    41  // OutputConstructorFromSimple provides a way to define an output constructor
    42  // without manually initializing processors of the config.
    43  func OutputConstructorFromSimple(fn func(output.Config, NewManagement) (output.Type, error)) OutputConstructor {
    44  	return func(c output.Config, nm NewManagement, pcf ...types.PipelineConstructorFunc) (output.Type, error) {
    45  		o, err := fn(c, nm)
    46  		if err != nil {
    47  			return nil, fmt.Errorf("failed to create output '%v': %w", c.Type, err)
    48  		}
    49  		pcf = output.AppendProcessorsFromConfig(c, nm, nm.Logger(), nm.Metrics(), pcf...)
    50  		return output.WrapWithPipelines(o, pcf...)
    51  	}
    52  }
    53  
    54  //------------------------------------------------------------------------------
    55  
    56  // OutputConstructor constructs an output component.
    57  type OutputConstructor func(output.Config, NewManagement, ...types.PipelineConstructorFunc) (output.Type, error)
    58  
    59  type outputSpec struct {
    60  	constructor OutputConstructor
    61  	spec        docs.ComponentSpec
    62  }
    63  
    64  // OutputSet contains an explicit set of outputs available to a Benthos service.
    65  type OutputSet struct {
    66  	specs map[string]outputSpec
    67  }
    68  
    69  // Add a new output to this set by providing a spec (name, documentation, and
    70  // constructor).
    71  func (s *OutputSet) Add(constructor OutputConstructor, spec docs.ComponentSpec) error {
    72  	if s.specs == nil {
    73  		s.specs = map[string]outputSpec{}
    74  	}
    75  	s.specs[spec.Name] = outputSpec{
    76  		constructor: constructor,
    77  		spec:        spec,
    78  	}
    79  	docs.RegisterDocs(spec)
    80  	return nil
    81  }
    82  
    83  // Init attempts to initialise an output from a config.
    84  func (s *OutputSet) Init(
    85  	conf output.Config,
    86  	mgr NewManagement,
    87  	pipelines ...types.PipelineConstructorFunc,
    88  ) (types.Output, error) {
    89  	spec, exists := s.specs[conf.Type]
    90  	if !exists {
    91  		// TODO: V4 Remove this
    92  		if ctor, exists := output.GetDeprecatedPlugin(conf.Type); exists {
    93  			return ctor(conf, mgr, mgr.Logger(), mgr.Metrics(), pipelines...)
    94  		}
    95  		return nil, types.ErrInvalidOutputType
    96  	}
    97  	return spec.constructor(conf, mgr, pipelines...)
    98  }
    99  
   100  // Docs returns a slice of output specs, which document each method.
   101  func (s *OutputSet) Docs() []docs.ComponentSpec {
   102  	var docs []docs.ComponentSpec
   103  	for _, v := range s.specs {
   104  		docs = append(docs, v.spec)
   105  	}
   106  	sort.Slice(docs, func(i, j int) bool {
   107  		return docs[i].Name < docs[j].Name
   108  	})
   109  	return docs
   110  }
   111  
   112  // DocsFor returns the documentation for a given component name, returns a
   113  // boolean indicating whether the component name exists.
   114  func (s *OutputSet) DocsFor(name string) (docs.ComponentSpec, bool) {
   115  	c, ok := s.specs[name]
   116  	if !ok {
   117  		return docs.ComponentSpec{}, false
   118  	}
   119  	return c.spec, true
   120  }