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 }