internal/registry/registry.go (93 lines of code) (raw):

package registry import ( "context" "fmt" "net/http" cloudevents "github.com/cloudevents/sdk-go/v2" ) // RegisteredFunction represents a function that has been // registered with the registry. type RegisteredFunction struct { Name string // The name of the function Path string // The serving path of the function CloudEventFn func(context.Context, cloudevents.Event) error // Optional: The user's CloudEvent function HTTPFn func(http.ResponseWriter, *http.Request) // Optional: The user's HTTP function EventFn interface{} // Optional: The user's Event function TypedFn interface{} // Optional: The user's typed function } // Option is an option used when registering a function. type Option func(*RegisteredFunction) func WithPath(path string) Option { return func(fn *RegisteredFunction) { fn.Path = path } } func WithName(name string) Option { return func(fn *RegisteredFunction) { fn.Name = name } } // Registry is a registry of functions. type Registry struct { functions map[string]*RegisteredFunction functionsWithoutNames []*RegisteredFunction // The functions that are not registered declaratively. } var defaultInstance = New() // Default returns the default, singleton registry instance. func Default() *Registry { return defaultInstance } func New() *Registry { return &Registry{ functions: map[string]*RegisteredFunction{}, } } func (r *Registry) Reset() { r.functions = map[string]*RegisteredFunction{} r.functionsWithoutNames = []*RegisteredFunction{} } // RegisterHTTP registes a HTTP function. func (r *Registry) RegisterHTTP(fn func(http.ResponseWriter, *http.Request), options ...Option) error { return r.register(&RegisteredFunction{HTTPFn: fn}, options...) } // RegisterCloudEvent registers a CloudEvent function. func (r *Registry) RegisterCloudEvent(fn func(context.Context, cloudevents.Event) error, options ...Option) error { return r.register(&RegisteredFunction{CloudEventFn: fn}, options...) } // RegisterEvent registers an Event function. func (r *Registry) RegisterEvent(fn interface{}, options ...Option) error { return r.register(&RegisteredFunction{EventFn: fn}, options...) } // RegisterTyped registers a strongly typed function. func (r *Registry) RegisterTyped(fn interface{}, options ...Option) error { return r.register(&RegisteredFunction{TypedFn: fn}, options...) } func (r *Registry) register(function *RegisteredFunction, options ...Option) error { for _, o := range options { o(function) } if function.Name == "" && function.Path == "" { return fmt.Errorf("either the function path or the function name should be specified") } if function.Name == "" { // The function is not registered declaratively. r.functionsWithoutNames = append(r.functionsWithoutNames, function) return nil } if _, ok := r.functions[function.Name]; ok { return fmt.Errorf("function name already registered: %q", function.Name) } if function.Path == "" { function.Path = "/" + function.Name } r.functions[function.Name] = function return nil } // GetRegisteredFunction a registered function by name func (r *Registry) GetRegisteredFunction(name string) (*RegisteredFunction, bool) { fn, ok := r.functions[name] return fn, ok } // GetAllFunctions returns all the registered functions. func (r *Registry) GetAllFunctions() []*RegisteredFunction { all := r.functionsWithoutNames for _, fn := range r.functions { all = append(all, fn) } return all } // GetLastFunctionWithoutName returns the last function that's not registered declaratively. // As the function is registered without a name, it can not be found by setting FUNCTION_TARGET // when deploying. In this case, the last function that's not registered declaratively // will be served. func (r *Registry) GetLastFunctionWithoutName() *RegisteredFunction { count := len(r.functionsWithoutNames) if count == 0 { return nil } return r.functionsWithoutNames[count-1] }