2016-08-10 02:08:15 +02:00
|
|
|
// Package middleware implements the TrackerLogic interface by executing
|
|
|
|
// a series of middleware hooks.
|
|
|
|
package middleware
|
|
|
|
|
|
|
|
import (
|
2017-12-23 20:54:51 +01:00
|
|
|
"errors"
|
|
|
|
"sync"
|
|
|
|
|
|
|
|
"gopkg.in/yaml.v2"
|
2016-08-10 02:08:15 +02:00
|
|
|
)
|
|
|
|
|
2017-12-23 20:54:51 +01:00
|
|
|
var (
|
|
|
|
driversM sync.RWMutex
|
|
|
|
drivers = make(map[string]Driver)
|
2016-08-10 02:08:15 +02:00
|
|
|
|
2017-12-23 20:54:51 +01:00
|
|
|
// ErrDriverDoesNotExist is the error returned by NewMiddleware when a
|
|
|
|
// middleware driver with that name does not exist.
|
|
|
|
ErrDriverDoesNotExist = errors.New("middleware driver with that name does not exist")
|
|
|
|
)
|
2016-08-10 02:08:15 +02:00
|
|
|
|
2017-12-23 20:54:51 +01:00
|
|
|
// Driver is the interface used to initialize a new type of middleware.
|
|
|
|
//
|
|
|
|
// The options parameter is YAML encoded bytes that should be unmarshalled into
|
|
|
|
// the hook's custom configuration.
|
|
|
|
type Driver interface {
|
|
|
|
NewHook(options []byte) (Hook, error)
|
2016-08-10 02:08:15 +02:00
|
|
|
}
|
|
|
|
|
2017-12-23 20:54:51 +01:00
|
|
|
// RegisterDriver makes a Driver available by the provided name.
|
|
|
|
//
|
|
|
|
// If called twice with the same name, the name is blank, or if the provided
|
|
|
|
// Driver is nil, this function panics.
|
|
|
|
func RegisterDriver(name string, d Driver) {
|
|
|
|
if name == "" {
|
|
|
|
panic("middleware: could not register a Driver with an empty name")
|
2016-08-10 02:08:15 +02:00
|
|
|
}
|
2017-12-23 20:54:51 +01:00
|
|
|
if d == nil {
|
|
|
|
panic("middleware: could not register a nil Driver")
|
2016-08-10 02:08:15 +02:00
|
|
|
}
|
|
|
|
|
2017-12-23 20:54:51 +01:00
|
|
|
driversM.Lock()
|
|
|
|
defer driversM.Unlock()
|
2016-08-10 02:08:15 +02:00
|
|
|
|
2017-12-23 20:54:51 +01:00
|
|
|
if _, dup := drivers[name]; dup {
|
|
|
|
panic("middleware: RegisterDriver called twice for " + name)
|
2016-08-10 02:08:15 +02:00
|
|
|
}
|
2017-12-23 20:54:51 +01:00
|
|
|
|
|
|
|
drivers[name] = d
|
2016-08-10 02:08:15 +02:00
|
|
|
}
|
|
|
|
|
2017-12-23 20:54:51 +01:00
|
|
|
// New attempts to initialize a new middleware instance from the
|
|
|
|
// list of registered Drivers.
|
|
|
|
//
|
|
|
|
// If a driver does not exist, returns ErrDriverDoesNotExist.
|
|
|
|
func New(name string, optionBytes []byte) (Hook, error) {
|
|
|
|
driversM.RLock()
|
|
|
|
defer driversM.RUnlock()
|
|
|
|
|
|
|
|
var d Driver
|
|
|
|
d, ok := drivers[name]
|
|
|
|
if !ok {
|
|
|
|
return nil, ErrDriverDoesNotExist
|
2016-08-10 02:08:15 +02:00
|
|
|
}
|
|
|
|
|
2017-12-23 20:54:51 +01:00
|
|
|
return d.NewHook(optionBytes)
|
2016-08-10 02:08:15 +02:00
|
|
|
}
|
|
|
|
|
2017-12-23 20:54:51 +01:00
|
|
|
// HookConfig is the generic configuration format used for all registered Hooks.
|
|
|
|
type HookConfig struct {
|
|
|
|
Name string `yaml:"name"`
|
|
|
|
Options map[string]interface{} `yaml:"options"`
|
2016-08-10 02:08:15 +02:00
|
|
|
}
|
2016-09-24 19:38:05 +02:00
|
|
|
|
2017-12-23 20:54:51 +01:00
|
|
|
// HooksFromHookConfigs is a utility function for initializing Hooks in bulk.
|
|
|
|
func HooksFromHookConfigs(cfgs []HookConfig) (hooks []Hook, err error) {
|
|
|
|
for _, cfg := range cfgs {
|
|
|
|
// Marshal the options back into bytes.
|
|
|
|
var optionBytes []byte
|
|
|
|
optionBytes, err = yaml.Marshal(cfg.Options)
|
|
|
|
if err != nil {
|
|
|
|
return
|
2016-09-24 19:38:05 +02:00
|
|
|
}
|
|
|
|
|
2017-12-23 20:54:51 +01:00
|
|
|
var h Hook
|
|
|
|
h, err = New(cfg.Name, optionBytes)
|
|
|
|
if err != nil {
|
|
|
|
return
|
2016-09-24 19:38:05 +02:00
|
|
|
}
|
2017-12-23 20:54:51 +01:00
|
|
|
|
|
|
|
hooks = append(hooks, h)
|
2016-09-24 19:38:05 +02:00
|
|
|
}
|
|
|
|
|
2017-12-23 20:54:51 +01:00
|
|
|
return
|
2016-09-24 19:38:05 +02:00
|
|
|
}
|