knative.dev/func-go@v0.21.3/cloudevents/instance.go (about)

     1  package cloudevents
     2  
     3  import (
     4  	"context"
     5  
     6  	"github.com/cloudevents/sdk-go/v2/event"
     7  )
     8  
     9  // Handler is a CloudEvent function Handler, which is invoked when it
    10  // receives a cloud event.  It must implement one of the following methods:
    11  //
    12  //	Handle()
    13  //	Handle() error
    14  //	Handle(context.Context)
    15  //	Handle(context.Context) error
    16  //	Handle(event.Event)
    17  //	Handle(event.Event) error
    18  //	Handle(context.Context, event.Event)
    19  //	Handle(context.Context, event.Event) error
    20  //	Handle(event.Event) *event.Event
    21  //	Handle(event.Event) (*event.Event, error)
    22  //	Handle(context.Context, event.Event) *event.Event
    23  //	Handle(context.Context, event.Event) (*event.Event, error)
    24  //
    25  // It can optionaly implement any of Start, Stop, Ready, and Alive.
    26  type Handler any
    27  
    28  // Starter is a function which defines a method to be called on function start.
    29  type Starter interface {
    30  	// Start instance event hook.
    31  	Start(context.Context, map[string]string) error
    32  }
    33  
    34  // Stopper is function which defines a method to be called on function stop.
    35  type Stopper interface {
    36  	// Stop instance event hook.
    37  	Stop(context.Context) error
    38  }
    39  
    40  // ReadinessReporter is a function which defines a method to be used to
    41  // determine readiness.
    42  type ReadinessReporter interface {
    43  	// Ready to be invoked or not.
    44  	Ready(context.Context) (bool, error)
    45  }
    46  
    47  // LivenessReporter is a function which defines a method to be used to
    48  // determine liveness.
    49  type LivenessReporter interface {
    50  	// Alive allows the instance to report it's liveness status.
    51  	Alive(context.Context) (bool, error)
    52  }
    53  
    54  // DefaultHandler is used for simple static function implementations which
    55  // need only define a single exported function named Handle which must be
    56  // of a signature understood by the CloudEvents SDK.
    57  type DefaultHandler struct {
    58  	Handler any
    59  }
    60  
    61  // NOTE on the implementation of the various Handle methods:
    62  //
    63  // Since Go does not consider differing arguments and returns as indicating
    64  // a new method signature, each of the possible implementations supported
    65  // by the underlying CloudEvents SDK are enumerated as separate types.
    66  //
    67  // The cloudevents SDK wants us to pass a reference to a _function_ which is
    68  // of one of its accepted method signatures.  It uses reflection to determine
    69  // which signature has been provided and then invokes.
    70  // We, however, want to simply pass a structure which implements a
    71  // CloudEvent handler interface of a known and compile-time safe type.
    72  //
    73  // To bridge these two approaches, herein is created a new interface called
    74  // a CloudeventsHandlerProducer which, as the name suggests, produces
    75  // a CloudeventsHandler when requested.  This is of type "any" because
    76  // the cloudevents SDK supports several signatures, so we can not validate
    77  // this at compile-time without becoming coupled to the cloudevents SDK
    78  // implementation.
    79  // So here we accept any structure which exports a mamber named "Handle", and
    80  // then leave it up to the cloudevents SDK to fail if the arguments and
    81  // return variables are not one of the supported signature.
    82  // It is important to the function developer's usage to be able to simply
    83  // declare their function has a method Handle... without needing themselves
    84  // to implement the ProduceHandler method, because that's ugly and confusing.
    85  // The way this is accomplished is by decorating the passed instance in a
    86  // struct which uses reflection to implement the ProduceHandler method.
    87  
    88  // newReceiver satisfies the expectations of
    89  // cloudevents.NewHTTPReceiveHandler's handler argument the hard way.
    90  //
    91  // First attempt: use a reference to the function which should handle
    92  // the request via reflection.   This appears to fal because it becomes
    93  // a function with first argument the receiver, rather than a method where
    94  // that is implied, and thus fails the conversion to one of the CE
    95  // library's known set of method signatures.
    96  //
    97  //			t := reflect.TypeOf(f)
    98  //			m, ok := t.MethodByName("Handle")
    99  //	   if !ok {
   100  //	     panic("unable to find a 'Handle' method on the function.")
   101  //	   }
   102  //	   h = m.Func.Interface()
   103  //
   104  // Second attempt:  wrap the target in a closure with an entirely generic
   105  // method signature and invoke it directly.  This fails for basically the
   106  // same reason: the CE library checks and sees that []interface{} is not
   107  // one of its known signatures.
   108  //
   109  //	h = func(args ...interface{}) {
   110  //	  inputs := make([]reflect.Value, len(args))
   111  //	  for i, _ := range args {
   112  //	    inputs[i] = reflect.ValueOf(args[i])
   113  //	  }
   114  //	  reflect.ValueOf(f).MethodByName("Handle").Call(inputs)
   115  //	}
   116  //
   117  // Third Attempt: just give the CE library _exactly_ the method
   118  // signature it wants by enumerating them one at a time with the receiver
   119  // in the resultant closure.
   120  //
   121  // TODO: Can probably simplify this at least one level:  from
   122  // TODO: Should check the CloudEvents SDK to ensure passing a handling
   123  // struct is not already supported some other way, and if not,
   124  // contribute this to the codebase.  Also could check that the two earlier
   125  // reflection-based attempts are not in error.
   126  // TODO: One benefit of enumerating the types is that a user's function could
   127  // be type-checked at compile time with a littl extra introspection.
   128  type handler interface {
   129  	Handle()
   130  }
   131  type handlerErr interface {
   132  	Handle() error
   133  }
   134  type handlerCtx interface {
   135  	Handle(context.Context)
   136  }
   137  type handlerCtxErr interface {
   138  	Handle(context.Context) error
   139  }
   140  type handlerEvt interface {
   141  	Handle(event.Event)
   142  }
   143  type handlerEvtErr interface {
   144  	Handle(event.Event) error
   145  }
   146  type handlerCtxEvt interface {
   147  	Handle(context.Context, event.Event)
   148  }
   149  type handlerCtxEvtErr interface {
   150  	Handle(context.Context, event.Event) error
   151  }
   152  type handlerEvtEvt interface {
   153  	Handle(event.Event) *event.Event
   154  }
   155  type handlerEvtEvtErr interface {
   156  	Handle(event.Event) (*event.Event, error)
   157  }
   158  type handlerCtxEvtEvt interface {
   159  	Handle(context.Context, event.Event) *event.Event
   160  }
   161  type handlerCtxEvtEvtErr interface {
   162  	Handle(context.Context, event.Event) (*event.Event, error)
   163  }
   164  
   165  func getReceiverFn(f any) any {
   166  	switch h := f.(type) {
   167  	case handler:
   168  		return h.Handle
   169  	case handlerErr:
   170  		return h.Handle
   171  	case handlerCtx:
   172  		return h.Handle
   173  	case handlerCtxErr:
   174  		return h.Handle
   175  	case handlerEvt:
   176  		return h.Handle
   177  	case handlerEvtErr:
   178  		return h.Handle
   179  	case handlerCtxEvt:
   180  		return h.Handle
   181  	case handlerCtxEvtErr:
   182  		return h.Handle
   183  	case handlerEvtEvt:
   184  		return h.Handle
   185  	case handlerEvtEvtErr:
   186  		return h.Handle
   187  	case handlerCtxEvtEvt:
   188  		return h.Handle
   189  	case handlerCtxEvtEvtErr:
   190  		return h.Handle
   191  	default:
   192  		panic("Please see the supported function signatures list.")
   193  	}
   194  }