refactor: plugin structure

This commit is contained in:
debugtalk
2022-02-25 22:23:57 +08:00
parent c6179f1687
commit fead0c0a31
13 changed files with 48 additions and 53 deletions

View File

@@ -9,7 +9,7 @@ import (
"github.com/httprunner/hrp/internal/boomer"
"github.com/httprunner/hrp/internal/ga"
"github.com/httprunner/hrp/plugin/common"
pluginInternal "github.com/httprunner/hrp/plugin/internal"
)
func NewBoomer(spawnCount int, spawnRate float64) *HRPBoomer {
@@ -22,8 +22,8 @@ func NewBoomer(spawnCount int, spawnRate float64) *HRPBoomer {
type HRPBoomer struct {
*boomer.Boomer
plugins []common.Plugin // each task has its own plugin process
pluginsMutex *sync.RWMutex // avoid data race
plugins []pluginInternal.IPlugin // each task has its own plugin process
pluginsMutex *sync.RWMutex // avoid data race
}
// Run starts to run load test for one or multiple testcases.

View File

@@ -13,7 +13,7 @@ import (
"github.com/rs/zerolog/log"
"github.com/httprunner/hrp/internal/builtin"
"github.com/httprunner/hrp/plugin/common"
pluginInternal "github.com/httprunner/hrp/plugin/internal"
)
func newParser() *parser {
@@ -21,7 +21,7 @@ func newParser() *parser {
}
type parser struct {
plugin common.Plugin // plugin is used to call functions
plugin pluginInternal.IPlugin // plugin is used to call functions
}
func buildURL(baseURL, stepURL string) string {
@@ -252,7 +252,7 @@ func (p *parser) callFunc(funcName string, arguments ...interface{}) (interface{
fn := reflect.ValueOf(function)
// call with builtin function
return common.CallFunc(fn, arguments...)
return pluginInternal.CallFunc(fn, arguments...)
}
// merge two variables mapping, the first variables have higher priority

View File

@@ -1,4 +1,4 @@
package common
package pluginInternal
import (
"fmt"

View File

@@ -1,4 +1,4 @@
package common
package pluginInternal
import (
"errors"

View File

@@ -1,8 +1,8 @@
package shared
package pluginInternal
import "github.com/hashicorp/go-plugin"
const Name = "debugtalk"
const PluginName = "debugtalk"
// handshakeConfigs are used to just do a basic handshake between
// a plugin and host. If the handshake fails, a user friendly error is shown.
@@ -11,5 +11,5 @@ const Name = "debugtalk"
var HandshakeConfig = plugin.HandshakeConfig{
ProtocolVersion: 1,
MagicCookieKey: "HttpRunnerPlus",
MagicCookieValue: Name,
MagicCookieValue: PluginName,
}

View File

@@ -1,4 +1,4 @@
package common
package pluginInternal
import (
"fmt"

View File

@@ -1,7 +1,7 @@
// +build linux freebsd darwin
// go plugin doesn't support windows
package common
package pluginInternal
import (
"fmt"

View File

@@ -1,4 +1,4 @@
package common
package pluginInternal
import (
"os"
@@ -6,8 +6,6 @@ import (
"github.com/hashicorp/go-hclog"
"github.com/hashicorp/go-plugin"
"github.com/httprunner/hrp/plugin/shared"
pluginShared "github.com/httprunner/hrp/plugin/shared"
"github.com/rs/zerolog/log"
)
@@ -16,13 +14,13 @@ var client *plugin.Client
// HashicorpPlugin implements hashicorp/go-plugin
type HashicorpPlugin struct {
logOn bool // turn on plugin log
pluginShared.FuncCaller
FuncCaller
cachedFunctions map[string]bool // cache loaded functions to improve performance
}
func (p *HashicorpPlugin) Init(path string) error {
loggerOptions := &hclog.LoggerOptions{
Name: shared.Name,
Name: PluginName,
Output: os.Stdout,
}
if p.logOn {
@@ -32,9 +30,9 @@ func (p *HashicorpPlugin) Init(path string) error {
}
// launch the plugin process
client = plugin.NewClient(&plugin.ClientConfig{
HandshakeConfig: shared.HandshakeConfig,
HandshakeConfig: HandshakeConfig,
Plugins: map[string]plugin.Plugin{
shared.Name: &shared.HashicorpPlugin{},
PluginName: &HRPPlugin{},
},
Cmd: exec.Command(path),
Logger: hclog.New(loggerOptions),
@@ -48,7 +46,7 @@ func (p *HashicorpPlugin) Init(path string) error {
}
// Request the plugin
raw, err := rpcClient.Dispense(shared.Name)
raw, err := rpcClient.Dispense(PluginName)
if err != nil {
log.Error().Err(err).Msg("request plugin failed")
return err
@@ -56,7 +54,7 @@ func (p *HashicorpPlugin) Init(path string) error {
// We should have a Function now! This feels like a normal interface
// implementation but is in fact over an RPC connection.
p.FuncCaller = raw.(shared.FuncCaller)
p.FuncCaller = raw.(FuncCaller)
p.cachedFunctions = make(map[string]bool)
log.Info().Str("path", path).Msg("load hashicorp go plugin success")

View File

@@ -1,4 +1,4 @@
package common
package pluginInternal
import (
"os"

View File

@@ -1,4 +1,4 @@
package shared
package pluginInternal
import (
"encoding/gob"
@@ -89,15 +89,22 @@ func (s *functionRPCServer) Call(args interface{}, resp *interface{}) error {
return nil
}
// HashicorpPlugin implements hashicorp's plugin.Plugin.
type HashicorpPlugin struct {
// HRPPlugin implements hashicorp's plugin.Plugin.
type HRPPlugin struct {
Impl FuncCaller
}
func (p *HashicorpPlugin) Server(*plugin.MuxBroker) (interface{}, error) {
func (p *HRPPlugin) Server(*plugin.MuxBroker) (interface{}, error) {
return &functionRPCServer{Impl: p.Impl}, nil
}
func (HashicorpPlugin) Client(b *plugin.MuxBroker, c *rpc.Client) (interface{}, error) {
func (HRPPlugin) Client(b *plugin.MuxBroker, c *rpc.Client) (interface{}, error) {
return &functionRPC{client: c}, nil
}
type IPlugin interface {
Init(path string) error // init plugin
Has(funcName string) bool // check if plugin has function
Call(funcName string, args ...interface{}) (interface{}, error) // call function
Quit() error // quit plugin
}

View File

@@ -1,33 +1,24 @@
package common
package pluginInternal
import (
"fmt"
"os"
"path/filepath"
pluginShared "github.com/httprunner/hrp/plugin/shared"
)
type pluginFile string
const (
goPluginFile pluginFile = pluginShared.Name + ".so" // built from go plugin
hashicorpGoPluginFile pluginFile = pluginShared.Name + ".bin" // built from hashicorp go plugin
hashicorpPyPluginFile pluginFile = pluginShared.Name + ".py"
goPluginFile pluginFile = PluginName + ".so" // built from go plugin
hashicorpGoPluginFile pluginFile = PluginName + ".bin" // built from hashicorp go plugin
hashicorpPyPluginFile pluginFile = PluginName + ".py"
)
type Plugin interface {
Init(path string) error // init plugin
Has(funcName string) bool // check if plugin has function
Call(funcName string, args ...interface{}) (interface{}, error) // call function
Quit() error // quit plugin
}
func Init(path string, logOn bool) (Plugin, error) {
func Init(path string, logOn bool) (IPlugin, error) {
if path == "" {
return nil, nil
}
var plugin Plugin
var plugin IPlugin
// priority: hashicorp plugin > go plugin
// locate hashicorp plugin file

View File

@@ -8,8 +8,7 @@ import (
hclog "github.com/hashicorp/go-hclog"
"github.com/hashicorp/go-plugin"
"github.com/httprunner/hrp/plugin/common"
pluginShared "github.com/httprunner/hrp/plugin/shared"
pluginInternal "github.com/httprunner/hrp/plugin/internal"
)
// functionsMap stores plugin functions
@@ -37,7 +36,7 @@ func (p *functionPlugin) Call(funcName string, args ...interface{}) (interface{}
return nil, fmt.Errorf("function %s not found", funcName)
}
return common.CallFunc(fn, args...)
return pluginInternal.CallFunc(fn, args...)
}
var functions = make(functionsMap)
@@ -55,17 +54,17 @@ func Register(funcName string, fn interface{}) {
func Serve() {
funcPlugin := &functionPlugin{
logger: hclog.New(&hclog.LoggerOptions{
Name: pluginShared.Name,
Name: pluginInternal.PluginName,
Output: os.Stdout,
Level: hclog.Info,
}),
functions: functions,
}
var pluginMap = map[string]plugin.Plugin{
pluginShared.Name: &pluginShared.HashicorpPlugin{Impl: funcPlugin},
pluginInternal.PluginName: &pluginInternal.HRPPlugin{Impl: funcPlugin},
}
plugin.Serve(&plugin.ServeConfig{
HandshakeConfig: pluginShared.HandshakeConfig,
HandshakeConfig: pluginInternal.HandshakeConfig,
Plugins: pluginMap,
})
}

View File

@@ -32,7 +32,7 @@ import (
"github.com/httprunner/hrp/internal/builtin"
"github.com/httprunner/hrp/internal/ga"
"github.com/httprunner/hrp/plugin/common"
pluginInternal "github.com/httprunner/hrp/plugin/internal"
)
const (
@@ -282,8 +282,8 @@ func (r *caseRunner) run() error {
return nil
}
func initPlugin(path string, logOn bool) (plugin common.Plugin, err error) {
plugin, err = common.Init(path, logOn)
func initPlugin(path string, logOn bool) (plugin pluginInternal.IPlugin, err error) {
plugin, err = pluginInternal.Init(path, logOn)
if plugin == nil {
return
}
@@ -299,7 +299,7 @@ func initPlugin(path string, logOn bool) (plugin common.Plugin, err error) {
// report event for initializing plugin
var pluginType string
if _, ok := plugin.(*common.GoPlugin); ok {
if _, ok := plugin.(*pluginInternal.GoPlugin); ok {
pluginType = "go"
} else {
pluginType = "hashicorp"