Skip to content

Commit

Permalink
http handler injection via plugin added
Browse files Browse the repository at this point in the history
  • Loading branch information
kpacha committed May 10, 2019
1 parent 51c20bc commit 8f9ca62
Show file tree
Hide file tree
Showing 5 changed files with 181 additions and 26 deletions.
4 changes: 2 additions & 2 deletions plugin/plugin.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,14 @@ type Plugin interface {
// Load loads all the plugins in pluginFolder with pattern in its filename.
// It returns the number of plugins loaded and an error if something goes wrong.
func Load(cfg config.Plugin, reg *Register) (int, error) {
plugins, err := scan(cfg.Folder, cfg.Pattern)
plugins, err := Scan(cfg.Folder, cfg.Pattern)
if err != nil {
return 0, err
}
return load(plugins, reg)
}

func scan(folder, pattern string) ([]string, error) {
func Scan(folder, pattern string) ([]string, error) {
files, err := ioutil.ReadDir(folder)
if err != nil {
return []string{}, err
Expand Down
4 changes: 1 addition & 3 deletions transport/http/client/plugin/executor.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,7 @@ import (
"github.com/devopsfaith/krakend/transport/http/client"
)

const (
Namespace = "github.com/devopsfaith/krakend/transport/http/client/executor"
)
const Namespace = "github.com/devopsfaith/krakend/transport/http/client/executor"

func HTTPRequestExecutor(
logger logging.Logger,
Expand Down
26 changes: 5 additions & 21 deletions transport/http/client/plugin/plugin.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,59 +3,43 @@ package plugin
import (
"context"
"fmt"
"io/ioutil"
"net/http"
"plugin"
"strings"

krakendplugin "github.com/devopsfaith/krakend/plugin"
"github.com/devopsfaith/krakend/register"
)

var clientRegister = register.New()

func RegisterClient(
name string,
handler func(ctx context.Context, extra map[string]interface{}) (http.Handler, error),
handler func(context.Context, map[string]interface{}) (http.Handler, error),
) {
clientRegister.Register(Namespace, name, handler)
}

type Registerer interface {
RegisterClients(func(
name string,
handler func(ctx context.Context, extra map[string]interface{}) (http.Handler, error),
handler func(context.Context, map[string]interface{}) (http.Handler, error),
))
}

type RegisterClientFunc func(
name string,
handler func(ctx context.Context, extra map[string]interface{}) (http.Handler, error),
handler func(context.Context, map[string]interface{}) (http.Handler, error),
)

func Load(path, pattern string, rcf RegisterClientFunc) (int, error) {
plugins, err := scan(path, pattern)
plugins, err := krakendplugin.Scan(path, pattern)
if err != nil {
return 0, err
}
return load(plugins, rcf)
}

func scan(folder, pattern string) ([]string, error) {
files, err := ioutil.ReadDir(folder)
if err != nil {
return []string{}, err
}

plugins := []string{}
for _, file := range files {
if !file.IsDir() && strings.Contains(file.Name(), pattern) {
plugins = append(plugins, folder+file.Name())
}
}

return plugins, nil
}

func load(plugins []string, rcf RegisterClientFunc) (int, error) {
errors := []error{}
loadedPlugins := 0
Expand Down
112 changes: 112 additions & 0 deletions transport/http/server/plugin/plugin.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
package plugin

import (
"context"
"fmt"
"net/http"
"plugin"
"strings"

krakendplugin "github.com/devopsfaith/krakend/plugin"
"github.com/devopsfaith/krakend/register"
)

var serverRegister = register.New()

func RegisterHandler(
name string,
handler func(context.Context, map[string]interface{}, http.Handler) (http.Handler, error),
) {
serverRegister.Register(Namespace, name, handler)
}

type Registerer interface {
RegisterHandlers(func(
name string,
handler func(context.Context, map[string]interface{}, http.Handler) (http.Handler, error),
))
}

type RegisterHandlerFunc func(
name string,
handler func(context.Context, map[string]interface{}, http.Handler) (http.Handler, error),
)

func Load(path, pattern string, rcf RegisterHandlerFunc) (int, error) {
plugins, err := krakendplugin.Scan(path, pattern)
if err != nil {
return 0, err
}
return load(plugins, rcf)
}

func load(plugins []string, rcf RegisterHandlerFunc) (int, error) {
errors := []error{}
loadedPlugins := 0
for k, pluginName := range plugins {
if err := open(pluginName, rcf); err != nil {
errors = append(errors, fmt.Errorf("opening plugin %d (%s): %s", k, pluginName, err.Error()))
continue
}
loadedPlugins++
}

if len(errors) > 0 {
return loadedPlugins, loaderError{errors}
}
return loadedPlugins, nil
}

func open(pluginName string, rcf RegisterHandlerFunc) (err error) {
defer func() {
if r := recover(); r != nil {
var ok bool
err, ok = r.(error)
if !ok {
err = fmt.Errorf("%v", r)
}
}
}()

var p Plugin
p, err = pluginOpener(pluginName)
if err != nil {
return
}
var r interface{}
r, err = p.Lookup("HandlerRegisterer")
if err != nil {
return
}
registerer, ok := r.(Registerer)
if !ok {
return fmt.Errorf("http-server-handler plugin loader: unknown type")
}
registerer.RegisterHandlers(rcf)
return
}

// Plugin is the interface of the loaded plugins
type Plugin interface {
Lookup(name string) (plugin.Symbol, error)
}

// pluginOpener keeps the plugin open function in a var for easy testing
var pluginOpener = defaultPluginOpener

func defaultPluginOpener(name string) (Plugin, error) {
return plugin.Open(name)
}

type loaderError struct {
errors []error
}

// Error implements the error interface
func (l loaderError) Error() string {
msgs := make([]string, len(l.errors))
for i, err := range l.errors {
msgs[i] = err.Error()
}
return fmt.Sprintf("plugin loader found %d error(s): \n%s", len(msgs), strings.Join(msgs, "\n"))
}
61 changes: 61 additions & 0 deletions transport/http/server/plugin/server.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
package plugin

import (
"context"
"net/http"

"github.com/devopsfaith/krakend/config"
"github.com/devopsfaith/krakend/logging"
)

const Namespace = "github.com/devopsfaith/krakend/transport/http/server/handler"

type RunServer func(context.Context, config.ServiceConfig, http.Handler) error

func New(logger logging.Logger, next RunServer) RunServer {
return func(ctx context.Context, cfg config.ServiceConfig, handler http.Handler) error {
v, ok := cfg.ExtraConfig[Namespace]
if !ok {
logger.Debug("http-server-handler: no extra config")
return next(ctx, cfg, handler)
}
extra, ok := v.(map[string]interface{})
if !ok {
logger.Debug("http-server-handler: wrong extra config type")
return next(ctx, cfg, handler)
}

// load plugin
r, ok := serverRegister.Get(Namespace)
if !ok {
logger.Debug("http-server-handler: no plugins registered for the module")
return next(ctx, cfg, handler)
}

name, ok := extra["name"].(string)
if !ok {
logger.Debug("http-server-handler: no name defined in the extra config")
return next(ctx, cfg, handler)
}

rawHf, ok := r.Get(name)
if !ok {
logger.Debug("http-server-handler: no plugin resgistered as", name)
return next(ctx, cfg, handler)
}

hf, ok := rawHf.(func(context.Context, map[string]interface{}, http.Handler) (http.Handler, error))
if !ok {
logger.Warning("http-server-handler: wrong plugin handler type:", name)
return next(ctx, cfg, handler)
}

handlerWrapper, err := hf(context.Background(), extra, handler)
if err != nil {
logger.Warning("http-server-handler: error getting the plugin handler:", err.Error())
return next(ctx, cfg, handler)
}

return next(ctx, cfg, handlerWrapper)
}
}

0 comments on commit 8f9ca62

Please sign in to comment.