mirror of
https://github.com/buger/goreplay.git
synced 2024-04-21 12:32:02 +00:00
104 lines
2.5 KiB
Go
104 lines
2.5 KiB
Go
package plugin
|
|
|
|
import (
|
|
"errors"
|
|
"reflect"
|
|
"strings"
|
|
)
|
|
|
|
// ErrorStopped is the error returned when the go routines reading the input is stopped.
|
|
var ErrorStopped = errors.New("reading stopped")
|
|
|
|
// Message represents data across plugins
|
|
type Message struct {
|
|
Meta []byte // metadata
|
|
Data []byte // actual data
|
|
}
|
|
|
|
// PluginReader is an interface for input plugins
|
|
type PluginReader interface {
|
|
PluginRead() (msg *Message, err error)
|
|
}
|
|
|
|
// PluginWriter is an interface for output plugins
|
|
type PluginWriter interface {
|
|
PluginWrite(msg *Message) (n int, err error)
|
|
}
|
|
|
|
// PluginLimited is an interface for plugins that support limiting
|
|
type PluginLimited interface {
|
|
Limited() bool
|
|
SetLimit(float64)
|
|
}
|
|
|
|
// PluginReadWriter is an interface for plugins that support reading and writing
|
|
type PluginReadWriter interface {
|
|
PluginReader
|
|
PluginWriter
|
|
}
|
|
|
|
type Response struct {
|
|
Payload []byte
|
|
UUID []byte
|
|
StartedAt int64
|
|
RoundTripTime int64
|
|
}
|
|
|
|
// extractLimitOptions detects if plugin get called with limiter support
|
|
// Returns address and limit
|
|
func extractLimitOptions(options string) (string, string) {
|
|
split := strings.Split(options, "|")
|
|
|
|
if len(split) > 1 {
|
|
return split[0], split[1]
|
|
}
|
|
|
|
return split[0], ""
|
|
}
|
|
|
|
// InOutPlugins struct for holding references to plugins
|
|
type InOutPlugins struct {
|
|
Inputs []PluginReader
|
|
Outputs []PluginWriter
|
|
All []interface{}
|
|
}
|
|
|
|
// RegisterPlugin automatically detects type of plugin and initialize it
|
|
//
|
|
// See this article if curious about reflect stuff below: http://blog.burntsushi.net/type-parametric-functions-golang
|
|
func (plugins *InOutPlugins) RegisterPlugin(constructor interface{}, options ...interface{}) {
|
|
var path, limit string
|
|
vc := reflect.ValueOf(constructor)
|
|
|
|
// Pre-processing options to make it work with reflect
|
|
vo := []reflect.Value{}
|
|
for _, oi := range options {
|
|
vo = append(vo, reflect.ValueOf(oi))
|
|
}
|
|
|
|
if len(vo) > 0 {
|
|
// Removing limit options from path
|
|
path, limit = extractLimitOptions(vo[0].String())
|
|
|
|
// Writing value back without limiter "|" options
|
|
vo[0] = reflect.ValueOf(path)
|
|
}
|
|
|
|
// Calling our constructor with list of given options
|
|
p := vc.Call(vo)[0].Interface()
|
|
|
|
if limit != "" {
|
|
p = NewLimiter(p, limit)
|
|
}
|
|
|
|
// Some of the output can be Readers as well because return responses
|
|
if r, ok := p.(PluginReader); ok {
|
|
plugins.Inputs = append(plugins.Inputs, r)
|
|
}
|
|
|
|
if w, ok := p.(PluginWriter); ok {
|
|
plugins.Outputs = append(plugins.Outputs, w)
|
|
}
|
|
plugins.All = append(plugins.All, p)
|
|
}
|