diff --git a/api/agent/agent.go b/api/agent/agent.go index bd9144b88e..d0fc50c77d 100644 --- a/api/agent/agent.go +++ b/api/agent/agent.go @@ -109,7 +109,7 @@ type agent struct { shutWg *common.WaitGroup shutonce sync.Once - callOverrider CallOverrider + callOverrider fnext.CallOverrider // deferred actions to call at end of initialisation onStartup []func() } @@ -203,7 +203,7 @@ func WithDockerDriver(drv drivers.Driver) Option { } // WithCallOverrider registers register a CallOverrider to modify a Call and extensions on call construction -func WithCallOverrider(fn CallOverrider) Option { +func WithCallOverrider(fn fnext.CallOverrider) Option { return func(a *agent) error { if a.callOverrider != nil { return errors.New("lb-agent call overriders already exists") diff --git a/api/agent/call.go b/api/agent/call.go index 5e23451952..7e2da42bec 100644 --- a/api/agent/call.go +++ b/api/agent/call.go @@ -39,9 +39,6 @@ type Call interface { End(ctx context.Context, err error) error } -// Interceptor in GetCall -type CallOverrider func(*models.Call, map[string]string) (map[string]string, error) - // TODO build w/o closures... lazy type CallOpt func(c *call) error diff --git a/api/agent/lb_agent.go b/api/agent/lb_agent.go index 9df824c616..91d2ad09ae 100644 --- a/api/agent/lb_agent.go +++ b/api/agent/lb_agent.go @@ -24,7 +24,7 @@ type lbAgent struct { callListeners []fnext.CallListener rp pool.RunnerPool placer pool.Placer - callOverrider CallOverrider + callOverrider fnext.CallOverrider shutWg *common.WaitGroup } @@ -71,7 +71,7 @@ func WithLBAgentConfig(cfg *Config) LBAgentOption { } // LB agents can use this to register a CallOverrider to modify a Call and extensions -func WithLBCallOverrider(fn CallOverrider) LBAgentOption { +func WithLBCallOverrider(fn fnext.CallOverrider) LBAgentOption { return func(a *lbAgent) error { if a.callOverrider != nil { return errors.New("lb-agent call overriders already exists") diff --git a/fnext/listeners.go b/fnext/listeners.go index 5cbb70f934..ec9a41b36b 100644 --- a/fnext/listeners.go +++ b/fnext/listeners.go @@ -57,7 +57,7 @@ type FnListener interface { AfterFnDelete(ctx context.Context, fnID string) error } -//// TriggerListener enables callbacks around Trigger events +// TriggerListener enables callbacks around Trigger events type TriggerListener interface { // BeforeTriggerCreate called before trigger created in the datastore BeforeTriggerCreate(ctx context.Context, trigger *models.Trigger) error @@ -68,9 +68,9 @@ type TriggerListener interface { // AfterTriggerUpdate called after trigger updated in datastore AfterTriggerUpdate(ctx context.Context, trigger *models.Trigger) error // BeforeTriggerDelete called before trigger deleted from the datastore - BeforeTriggerDelete(ctx context.Context, triggerId string) error + BeforeTriggerDelete(ctx context.Context, triggerID string) error // AfterTriggerDelete called after trigger deleted from the datastore - AfterTriggerDelete(ctx context.Context, triggerId string) error + AfterTriggerDelete(ctx context.Context, triggerID string) error } // CallListener enables callbacks around Call events. diff --git a/fnext/overrider.go b/fnext/overrider.go new file mode 100644 index 0000000000..24a74cdc7c --- /dev/null +++ b/fnext/overrider.go @@ -0,0 +1,8 @@ +package fnext + +import ( + "github.com/fnproject/fn/api/models" +) + +// CallOverrider is an interceptor in GetCall which can modify Call and extensions +type CallOverrider func(*models.Call, map[string]string) (map[string]string, error) diff --git a/fnext/plugin.go b/fnext/plugin.go new file mode 100644 index 0000000000..2e7980ca4e --- /dev/null +++ b/fnext/plugin.go @@ -0,0 +1,98 @@ +package fnext + +import ( + "fmt" + "plugin" +) + +const ( + listenerSymbolName = "Listener" + middlewareSymbolName = "Handle" + overriderSymbolName = "Overrider" +) + +func symbolFromPlugin(path, symbolName string) (plugin.Symbol, error) { + plugin, err := plugin.Open(path) + if err != nil { + return nil, err + } + return plugin.Lookup(symbolName) +} + +// NewPluginMiddleware creates an Fn Middleware from a Golang plugin +func NewPluginMiddleware(path string) (Middleware, error) { + handleSymbol, err := symbolFromPlugin(path, middlewareSymbolName) + if err != nil { + return nil, err + } + handler, ok := handleSymbol.(*MiddlewareFunc) + if !ok { + return nil, fmt.Errorf("%s is not a valid middleware function in plugin: %s", middlewareSymbolName, path) + } + return handler, nil +} + +// NewPluginAppListener creates an Fn AppListener from a Golang plugin +func NewPluginAppListener(path string) (AppListener, error) { + listenerSymbol, err := symbolFromPlugin(path, listenerSymbolName) + if err != nil { + return nil, err + } + callListener, ok := listenerSymbol.(AppListener) + if !ok { + return nil, fmt.Errorf("%s is not a AppListener", listenerSymbolName) + } + return callListener, nil +} + +// NewPluginFnListener creates an Fn FnListener from a Golang plugin +func NewPluginFnListener(path string) (FnListener, error) { + listenerSymbol, err := symbolFromPlugin(path, listenerSymbolName) + if err != nil { + return nil, err + } + callListener, ok := listenerSymbol.(FnListener) + if !ok { + return nil, fmt.Errorf("%s is not a FnListener", listenerSymbolName) + } + return callListener, nil +} + +// NewPluginTriggerListener creates an Trigger TriggerListener from a Golang plugin +func NewPluginTriggerListener(path string) (TriggerListener, error) { + listenerSymbol, err := symbolFromPlugin(path, listenerSymbolName) + if err != nil { + return nil, err + } + callListener, ok := listenerSymbol.(TriggerListener) + if !ok { + return nil, fmt.Errorf("%s is not a TriggerListener", listenerSymbolName) + } + return callListener, nil +} + +// NewPluginCallListener creates an Fn CallListener from a Golang plugin +func NewPluginCallListener(path string) (CallListener, error) { + listenerSymbol, err := symbolFromPlugin(path, listenerSymbolName) + if err != nil { + return nil, err + } + callListener, ok := listenerSymbol.(CallListener) + if !ok { + return nil, fmt.Errorf("%s is not a CallListener", listenerSymbolName) + } + return callListener, nil +} + +// NewPluginCallOverrider creates an Fn CallOverrider from a Golang plugin +func NewPluginCallOverrider(path string) (CallOverrider, error) { + overriderSymbol, err := symbolFromPlugin(path, overriderSymbolName) + if err != nil { + return nil, err + } + callOverrider, ok := overriderSymbol.(*CallOverrider) + if !ok { + return nil, fmt.Errorf("%s is not a valid call overrider in plugin: %s", overriderSymbolName, path) + } + return *callOverrider, nil +}