mirror of
https://github.com/httprunner/httprunner.git
synced 2026-05-22 17:00:17 +08:00
refactor: plugin code structure
This commit is contained in:
37
plugin/go/config.go
Normal file
37
plugin/go/config.go
Normal file
@@ -0,0 +1,37 @@
|
||||
package pluginInternal
|
||||
|
||||
import (
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/hashicorp/go-plugin"
|
||||
)
|
||||
|
||||
const PluginName = "debugtalk"
|
||||
const RPCPluginName = PluginName + "_rpc"
|
||||
const GRPCPluginName = PluginName + "_grpc"
|
||||
|
||||
// handshakeConfigs are used to just do a basic handshake between
|
||||
// a plugin and host. If the handshake fails, a user friendly error is shown.
|
||||
// This prevents users from executing bad plugins or executing a plugin
|
||||
// directory. It is a UX feature, not a security feature.
|
||||
var HandshakeConfig = plugin.HandshakeConfig{
|
||||
ProtocolVersion: 1,
|
||||
MagicCookieKey: "HttpRunnerPlus",
|
||||
MagicCookieValue: PluginName,
|
||||
}
|
||||
|
||||
const hrpPluginTypeEnvName = "HRP_PLUGIN_TYPE"
|
||||
|
||||
var hrpPluginType string
|
||||
|
||||
func init() {
|
||||
hrpPluginType = strings.ToLower(os.Getenv(hrpPluginTypeEnvName))
|
||||
if hrpPluginType == "" {
|
||||
hrpPluginType = "grpc" // default
|
||||
}
|
||||
}
|
||||
|
||||
func IsRPCPluginType() bool {
|
||||
return hrpPluginType == "rpc"
|
||||
}
|
||||
72
plugin/go/go_plugin.go
Normal file
72
plugin/go/go_plugin.go
Normal file
@@ -0,0 +1,72 @@
|
||||
package pluginInternal
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"plugin"
|
||||
"reflect"
|
||||
"runtime"
|
||||
|
||||
"github.com/rs/zerolog/log"
|
||||
|
||||
pluginUtils "github.com/httprunner/hrp/plugin/utils"
|
||||
)
|
||||
|
||||
// GoPlugin implements golang official plugin
|
||||
type GoPlugin struct {
|
||||
*plugin.Plugin
|
||||
cachedFunctions map[string]reflect.Value // cache loaded functions to improve performance
|
||||
}
|
||||
|
||||
func (p *GoPlugin) Init(path string) error {
|
||||
if runtime.GOOS == "windows" {
|
||||
log.Warn().Msg("go plugin does not support windows")
|
||||
return fmt.Errorf("go plugin does not support windows")
|
||||
}
|
||||
|
||||
var err error
|
||||
p.Plugin, err = plugin.Open(path)
|
||||
if err != nil {
|
||||
log.Error().Err(err).Str("path", path).Msg("load go plugin failed")
|
||||
return err
|
||||
}
|
||||
|
||||
p.cachedFunctions = make(map[string]reflect.Value)
|
||||
log.Info().Str("path", path).Msg("load go plugin success")
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *GoPlugin) Has(funcName string) bool {
|
||||
fn, ok := p.cachedFunctions[funcName]
|
||||
if ok {
|
||||
return fn.IsValid()
|
||||
}
|
||||
|
||||
sym, err := p.Plugin.Lookup(funcName)
|
||||
if err != nil {
|
||||
p.cachedFunctions[funcName] = reflect.Value{} // mark as invalid
|
||||
return false
|
||||
}
|
||||
fn = reflect.ValueOf(sym)
|
||||
|
||||
// check function type
|
||||
if fn.Kind() != reflect.Func {
|
||||
p.cachedFunctions[funcName] = reflect.Value{} // mark as invalid
|
||||
return false
|
||||
}
|
||||
|
||||
p.cachedFunctions[funcName] = fn
|
||||
return true
|
||||
}
|
||||
|
||||
func (p *GoPlugin) Call(funcName string, args ...interface{}) (interface{}, error) {
|
||||
if !p.Has(funcName) {
|
||||
return nil, fmt.Errorf("function %s not found", funcName)
|
||||
}
|
||||
fn := p.cachedFunctions[funcName]
|
||||
return pluginUtils.CallFunc(fn, args...)
|
||||
}
|
||||
|
||||
func (p *GoPlugin) Quit() error {
|
||||
// no need to quit for go plugin
|
||||
return nil
|
||||
}
|
||||
90
plugin/go/go_plugin_test.go
Normal file
90
plugin/go/go_plugin_test.go
Normal file
@@ -0,0 +1,90 @@
|
||||
// +build linux freebsd darwin
|
||||
// go plugin doesn't support windows
|
||||
|
||||
package pluginInternal
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"os/exec"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func buildGoPlugin() {
|
||||
fmt.Println("[setup] build go plugin")
|
||||
// flag -race is necessary in order to be consistent with go test
|
||||
cmd := exec.Command("go", "build", "-buildmode=plugin", "-race",
|
||||
"-o=debugtalk.so", "../../examples/plugin/debugtalk.go")
|
||||
if err := cmd.Run(); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
func removeGoPlugin() {
|
||||
fmt.Println("[teardown] remove go plugin")
|
||||
os.Remove("debugtalk.so")
|
||||
}
|
||||
|
||||
func TestLocatePlugin(t *testing.T) {
|
||||
buildGoPlugin()
|
||||
defer removeGoPlugin()
|
||||
|
||||
_, err := locateFile("../", goPluginFile)
|
||||
if !assert.Error(t, err) {
|
||||
t.Fail()
|
||||
}
|
||||
|
||||
_, err = locateFile("", goPluginFile)
|
||||
if !assert.Error(t, err) {
|
||||
t.Fail()
|
||||
}
|
||||
|
||||
startPath := "debugtalk.so"
|
||||
_, err = locateFile(startPath, goPluginFile)
|
||||
if !assert.Nil(t, err) {
|
||||
t.Fail()
|
||||
}
|
||||
|
||||
startPath = "call.go"
|
||||
_, err = locateFile(startPath, goPluginFile)
|
||||
if !assert.Nil(t, err) {
|
||||
t.Fail()
|
||||
}
|
||||
|
||||
startPath = "."
|
||||
_, err = locateFile(startPath, goPluginFile)
|
||||
if !assert.Nil(t, err) {
|
||||
t.Fail()
|
||||
}
|
||||
|
||||
startPath = "/abc"
|
||||
_, err = locateFile(startPath, goPluginFile)
|
||||
if !assert.Error(t, err) {
|
||||
t.Fail()
|
||||
}
|
||||
}
|
||||
|
||||
func TestCallPluginFunction(t *testing.T) {
|
||||
buildGoPlugin()
|
||||
defer removeGoPlugin()
|
||||
|
||||
plugin, err := Init("debugtalk.so", false)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if !assert.True(t, plugin.Has("Concatenate")) {
|
||||
t.Fail()
|
||||
}
|
||||
|
||||
// call function without arguments
|
||||
result, err := plugin.Call("Concatenate", "1", 2, "3.14")
|
||||
if !assert.NoError(t, err) {
|
||||
t.Fail()
|
||||
}
|
||||
if !assert.Equal(t, "123.14", result) {
|
||||
t.Fail()
|
||||
}
|
||||
}
|
||||
108
plugin/go/grpc.go
Normal file
108
plugin/go/grpc.go
Normal file
@@ -0,0 +1,108 @@
|
||||
package pluginInternal
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/hashicorp/go-plugin"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/rs/zerolog/log"
|
||||
"google.golang.org/grpc"
|
||||
|
||||
"github.com/httprunner/hrp/internal/json"
|
||||
"github.com/httprunner/hrp/plugin/go/proto"
|
||||
)
|
||||
|
||||
// functionGRPCClient runs on the host side, it implements FuncCaller interface
|
||||
type functionGRPCClient struct {
|
||||
client proto.DebugTalkClient
|
||||
}
|
||||
|
||||
func (m *functionGRPCClient) GetNames() ([]string, error) {
|
||||
log.Info().Msg("function GetNames called on host side")
|
||||
resp, err := m.client.GetNames(context.Background(), &proto.Empty{})
|
||||
if err != nil {
|
||||
log.Error().Err(err).Msg("gRPC call GetNames() failed")
|
||||
return nil, err
|
||||
}
|
||||
return resp.Names, err
|
||||
}
|
||||
|
||||
func (m *functionGRPCClient) Call(funcName string, funcArgs ...interface{}) (interface{}, error) {
|
||||
log.Info().Str("funcName", funcName).Interface("funcArgs", funcArgs).Msg("call function via gRPC")
|
||||
|
||||
funcArgBytes, err := json.Marshal(funcArgs)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to marshal Call() funcArgs")
|
||||
}
|
||||
req := &proto.CallRequest{
|
||||
Name: funcName,
|
||||
Args: funcArgBytes,
|
||||
}
|
||||
|
||||
response, err := m.client.Call(context.Background(), req)
|
||||
if err != nil {
|
||||
log.Error().Err(err).
|
||||
Str("funcName", funcName).Interface("funcArgs", funcArgs).
|
||||
Msg("gRPC Call() failed")
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var resp interface{}
|
||||
err = json.Unmarshal(response.Value, &resp)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to unmarshal Call() response")
|
||||
}
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
// Here is the gRPC server that functionGRPCClient talks to.
|
||||
type functionGRPCServer struct {
|
||||
proto.UnimplementedDebugTalkServer
|
||||
Impl FuncCaller
|
||||
}
|
||||
|
||||
func (m *functionGRPCServer) GetNames(ctx context.Context, req *proto.Empty) (*proto.GetNamesResponse, error) {
|
||||
log.Info().Interface("req", req).Msg("gRPC GetNames() called on plugin side")
|
||||
v, err := m.Impl.GetNames()
|
||||
if err != nil {
|
||||
log.Error().Err(err).Msg("gRPC GetNames() execution failed")
|
||||
return nil, err
|
||||
}
|
||||
return &proto.GetNamesResponse{Names: v}, err
|
||||
}
|
||||
|
||||
func (m *functionGRPCServer) Call(ctx context.Context, req *proto.CallRequest) (*proto.CallResponse, error) {
|
||||
var funcArgs []interface{}
|
||||
if err := json.Unmarshal(req.Args, &funcArgs); err != nil {
|
||||
return nil, errors.Wrap(err, "failed to unmarshal Call() funcArgs")
|
||||
}
|
||||
|
||||
log.Info().Interface("req", req).Msg("gRPC Call() called on plugin side")
|
||||
|
||||
v, err := m.Impl.Call(req.Name, funcArgs...)
|
||||
if err != nil {
|
||||
log.Error().Err(err).Interface("req", req).Msg("gRPC Call() execution failed")
|
||||
return nil, err
|
||||
}
|
||||
|
||||
value, err := json.Marshal(v)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to marshal Call() response")
|
||||
}
|
||||
return &proto.CallResponse{Value: value}, err
|
||||
}
|
||||
|
||||
// HRPPlugin implements hashicorp's plugin.GRPCPlugin.
|
||||
type GRPCPlugin struct {
|
||||
plugin.Plugin
|
||||
Impl FuncCaller
|
||||
}
|
||||
|
||||
func (p *GRPCPlugin) GRPCServer(broker *plugin.GRPCBroker, s *grpc.Server) error {
|
||||
proto.RegisterDebugTalkServer(s, &functionGRPCServer{Impl: p.Impl})
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *GRPCPlugin) GRPCClient(ctx context.Context, broker *plugin.GRPCBroker, c *grpc.ClientConn) (interface{}, error) {
|
||||
return &functionGRPCClient{client: proto.NewDebugTalkClient(c)}, nil
|
||||
}
|
||||
113
plugin/go/hashicorp_plugin.go
Normal file
113
plugin/go/hashicorp_plugin.go
Normal file
@@ -0,0 +1,113 @@
|
||||
package pluginInternal
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"os/exec"
|
||||
|
||||
"github.com/hashicorp/go-hclog"
|
||||
"github.com/hashicorp/go-plugin"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/rs/zerolog/log"
|
||||
)
|
||||
|
||||
var client *plugin.Client
|
||||
|
||||
// HashicorpPlugin implements hashicorp/go-plugin
|
||||
type HashicorpPlugin struct {
|
||||
logOn bool // turn on plugin log
|
||||
FuncCaller
|
||||
cachedFunctions map[string]bool // cache loaded functions to improve performance
|
||||
}
|
||||
|
||||
func (p *HashicorpPlugin) Init(path string) error {
|
||||
var pluginName string
|
||||
if IsRPCPluginType() {
|
||||
pluginName = RPCPluginName
|
||||
} else {
|
||||
pluginName = GRPCPluginName
|
||||
}
|
||||
|
||||
// logger
|
||||
loggerOptions := &hclog.LoggerOptions{
|
||||
Name: pluginName,
|
||||
Output: os.Stdout,
|
||||
}
|
||||
if p.logOn {
|
||||
loggerOptions.Level = hclog.Debug
|
||||
} else {
|
||||
loggerOptions.Level = hclog.Info
|
||||
}
|
||||
|
||||
// cmd
|
||||
cmd := exec.Command(path)
|
||||
cmd.Env = append(os.Environ(), fmt.Sprintf("%s=%s", hrpPluginTypeEnvName, hrpPluginType))
|
||||
|
||||
// launch the plugin process
|
||||
client = plugin.NewClient(&plugin.ClientConfig{
|
||||
HandshakeConfig: HandshakeConfig,
|
||||
Plugins: map[string]plugin.Plugin{
|
||||
RPCPluginName: &RPCPlugin{},
|
||||
GRPCPluginName: &GRPCPlugin{},
|
||||
},
|
||||
Cmd: cmd,
|
||||
Logger: hclog.New(loggerOptions),
|
||||
AllowedProtocols: []plugin.Protocol{
|
||||
plugin.ProtocolNetRPC,
|
||||
plugin.ProtocolGRPC,
|
||||
},
|
||||
})
|
||||
|
||||
// Connect via RPC/gRPC
|
||||
rpcClient, err := client.Client()
|
||||
if err != nil {
|
||||
return errors.Wrap(err, fmt.Sprintf("connect %s plugin failed", hrpPluginType))
|
||||
}
|
||||
|
||||
// Request the plugin
|
||||
raw, err := rpcClient.Dispense(pluginName)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, fmt.Sprintf("request %s plugin failed", hrpPluginType))
|
||||
}
|
||||
|
||||
// We should have a Function now! This feels like a normal interface
|
||||
// implementation but is in fact over an RPC connection.
|
||||
p.FuncCaller = raw.(FuncCaller)
|
||||
|
||||
p.cachedFunctions = make(map[string]bool)
|
||||
log.Info().Str("path", path).Msg("load hashicorp go plugin success")
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *HashicorpPlugin) Has(funcName string) bool {
|
||||
flag, ok := p.cachedFunctions[funcName]
|
||||
if ok {
|
||||
return flag
|
||||
}
|
||||
|
||||
funcNames, err := p.GetNames()
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
for _, name := range funcNames {
|
||||
if name == funcName {
|
||||
p.cachedFunctions[funcName] = true // cache as exists
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
p.cachedFunctions[funcName] = false // cache as not exists
|
||||
return false
|
||||
}
|
||||
|
||||
func (p *HashicorpPlugin) Call(funcName string, args ...interface{}) (interface{}, error) {
|
||||
return p.FuncCaller.Call(funcName, args...)
|
||||
}
|
||||
|
||||
func (p *HashicorpPlugin) Quit() error {
|
||||
// kill hashicorp plugin process
|
||||
log.Info().Msg("quit hashicorp plugin process")
|
||||
client.Kill()
|
||||
return nil
|
||||
}
|
||||
90
plugin/go/hashicorp_plugin_test.go
Normal file
90
plugin/go/hashicorp_plugin_test.go
Normal file
@@ -0,0 +1,90 @@
|
||||
package pluginInternal
|
||||
|
||||
import (
|
||||
"os"
|
||||
"os/exec"
|
||||
"testing"
|
||||
|
||||
"github.com/rs/zerolog/log"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func buildHashicorpPlugin() {
|
||||
log.Info().Msg("[init] build hashicorp go plugin")
|
||||
cmd := exec.Command("go", "build",
|
||||
"-o", "../../examples/debugtalk.bin",
|
||||
"../../examples/plugin/hashicorp.go", "../../examples/plugin/debugtalk.go")
|
||||
if err := cmd.Run(); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
func removeHashicorpPlugin() {
|
||||
log.Info().Msg("[teardown] remove hashicorp plugin")
|
||||
os.Remove("../../examples/debugtalk.bin")
|
||||
}
|
||||
|
||||
func TestInitHashicorpPlugin(t *testing.T) {
|
||||
buildHashicorpPlugin()
|
||||
defer removeHashicorpPlugin()
|
||||
|
||||
plugin, err := Init("../../examples/debugtalk.bin", false)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer plugin.Quit()
|
||||
|
||||
if !assert.True(t, plugin.Has("sum_ints")) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !assert.True(t, plugin.Has("concatenate")) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
var v2 interface{}
|
||||
v2, err = plugin.Call("sum_ints", 1, 2, 3, 4)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !assert.Equal(t, 10, v2) {
|
||||
t.Fail()
|
||||
}
|
||||
v2, err = plugin.Call("sum_two_int", 1, 2)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !assert.Equal(t, 3, v2) {
|
||||
t.Fail()
|
||||
}
|
||||
v2, err = plugin.Call("sum", 1, 2, 3.4, 5)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !assert.Equal(t, 11.4, v2) {
|
||||
t.Fail()
|
||||
}
|
||||
|
||||
var v3 interface{}
|
||||
v3, err = plugin.Call("sum_two_string", "a", "b")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !assert.Equal(t, "ab", v3) {
|
||||
t.Fail()
|
||||
}
|
||||
v3, err = plugin.Call("sum_strings", "a", "b", "c")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !assert.Equal(t, "abc", v3) {
|
||||
t.Fail()
|
||||
}
|
||||
|
||||
v3, err = plugin.Call("concatenate", "a", 2, "c", 3.4)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !assert.Equal(t, "a2c3.4", v3) {
|
||||
t.Fail()
|
||||
}
|
||||
}
|
||||
83
plugin/go/init.go
Normal file
83
plugin/go/init.go
Normal file
@@ -0,0 +1,83 @@
|
||||
package pluginInternal
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
)
|
||||
|
||||
type pluginFile string
|
||||
|
||||
const (
|
||||
goPluginFile pluginFile = PluginName + ".so" // built from go plugin
|
||||
hashicorpGoPluginFile pluginFile = PluginName + ".bin" // built from hashicorp go plugin
|
||||
hashicorpPyPluginFile pluginFile = PluginName + ".py"
|
||||
)
|
||||
|
||||
func Init(path string, logOn bool) (IPlugin, error) {
|
||||
if path == "" {
|
||||
return nil, nil
|
||||
}
|
||||
var plugin IPlugin
|
||||
|
||||
// priority: hashicorp plugin > go plugin
|
||||
// locate hashicorp plugin file
|
||||
pluginPath, err := locateFile(path, hashicorpGoPluginFile)
|
||||
if err == nil {
|
||||
// found hashicorp go plugin file
|
||||
plugin = &HashicorpPlugin{
|
||||
logOn: logOn,
|
||||
}
|
||||
err = plugin.Init(pluginPath)
|
||||
return plugin, err
|
||||
}
|
||||
|
||||
// locate go plugin file
|
||||
pluginPath, err = locateFile(path, goPluginFile)
|
||||
if err == nil {
|
||||
// found go plugin file
|
||||
plugin = &GoPlugin{}
|
||||
err = plugin.Init(pluginPath)
|
||||
return plugin, err
|
||||
}
|
||||
|
||||
// plugin not found
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// locateFile searches destFile upward recursively until current
|
||||
// working directory or system root dir.
|
||||
func locateFile(startPath string, destFile pluginFile) (string, error) {
|
||||
stat, err := os.Stat(startPath)
|
||||
if os.IsNotExist(err) {
|
||||
return "", err
|
||||
}
|
||||
|
||||
var startDir string
|
||||
if stat.IsDir() {
|
||||
startDir = startPath
|
||||
} else {
|
||||
startDir = filepath.Dir(startPath)
|
||||
}
|
||||
startDir, _ = filepath.Abs(startDir)
|
||||
|
||||
// convention over configuration
|
||||
pluginPath := filepath.Join(startDir, string(destFile))
|
||||
if _, err := os.Stat(pluginPath); err == nil {
|
||||
return pluginPath, nil
|
||||
}
|
||||
|
||||
// current working directory
|
||||
cwd, _ := os.Getwd()
|
||||
if startDir == cwd {
|
||||
return "", fmt.Errorf("searched to CWD, plugin file not found")
|
||||
}
|
||||
|
||||
// system root dir
|
||||
parentDir, _ := filepath.Abs(filepath.Dir(startDir))
|
||||
if parentDir == startDir {
|
||||
return "", fmt.Errorf("searched to system root dir, plugin file not found")
|
||||
}
|
||||
|
||||
return locateFile(parentDir, destFile)
|
||||
}
|
||||
14
plugin/go/interface.go
Normal file
14
plugin/go/interface.go
Normal file
@@ -0,0 +1,14 @@
|
||||
package pluginInternal
|
||||
|
||||
// FuncCaller is the interface that we're exposing as a plugin.
|
||||
type FuncCaller interface {
|
||||
GetNames() ([]string, error) // get all plugin function names list
|
||||
Call(funcName string, args ...interface{}) (interface{}, error) // call plugin function
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
340
plugin/go/proto/debugtalk.pb.go
Normal file
340
plugin/go/proto/debugtalk.pb.go
Normal file
@@ -0,0 +1,340 @@
|
||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||
// versions:
|
||||
// protoc-gen-go v1.27.1
|
||||
// protoc v3.19.4
|
||||
// source: plugin/proto/debugtalk.proto
|
||||
|
||||
package proto
|
||||
|
||||
import (
|
||||
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
|
||||
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
||||
reflect "reflect"
|
||||
sync "sync"
|
||||
)
|
||||
|
||||
const (
|
||||
// Verify that this generated code is sufficiently up-to-date.
|
||||
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
|
||||
// Verify that runtime/protoimpl is sufficiently up-to-date.
|
||||
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
|
||||
)
|
||||
|
||||
type Empty struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
}
|
||||
|
||||
func (x *Empty) Reset() {
|
||||
*x = Empty{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_plugin_proto_debugtalk_proto_msgTypes[0]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
}
|
||||
|
||||
func (x *Empty) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*Empty) ProtoMessage() {}
|
||||
|
||||
func (x *Empty) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_plugin_proto_debugtalk_proto_msgTypes[0]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use Empty.ProtoReflect.Descriptor instead.
|
||||
func (*Empty) Descriptor() ([]byte, []int) {
|
||||
return file_plugin_proto_debugtalk_proto_rawDescGZIP(), []int{0}
|
||||
}
|
||||
|
||||
type GetNamesResponse struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
Names []string `protobuf:"bytes,1,rep,name=names,proto3" json:"names,omitempty"`
|
||||
}
|
||||
|
||||
func (x *GetNamesResponse) Reset() {
|
||||
*x = GetNamesResponse{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_plugin_proto_debugtalk_proto_msgTypes[1]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
}
|
||||
|
||||
func (x *GetNamesResponse) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*GetNamesResponse) ProtoMessage() {}
|
||||
|
||||
func (x *GetNamesResponse) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_plugin_proto_debugtalk_proto_msgTypes[1]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use GetNamesResponse.ProtoReflect.Descriptor instead.
|
||||
func (*GetNamesResponse) Descriptor() ([]byte, []int) {
|
||||
return file_plugin_proto_debugtalk_proto_rawDescGZIP(), []int{1}
|
||||
}
|
||||
|
||||
func (x *GetNamesResponse) GetNames() []string {
|
||||
if x != nil {
|
||||
return x.Names
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type CallRequest struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"`
|
||||
Args []byte `protobuf:"bytes,2,opt,name=args,proto3" json:"args,omitempty"` // []interface{}
|
||||
}
|
||||
|
||||
func (x *CallRequest) Reset() {
|
||||
*x = CallRequest{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_plugin_proto_debugtalk_proto_msgTypes[2]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
}
|
||||
|
||||
func (x *CallRequest) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*CallRequest) ProtoMessage() {}
|
||||
|
||||
func (x *CallRequest) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_plugin_proto_debugtalk_proto_msgTypes[2]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use CallRequest.ProtoReflect.Descriptor instead.
|
||||
func (*CallRequest) Descriptor() ([]byte, []int) {
|
||||
return file_plugin_proto_debugtalk_proto_rawDescGZIP(), []int{2}
|
||||
}
|
||||
|
||||
func (x *CallRequest) GetName() string {
|
||||
if x != nil {
|
||||
return x.Name
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *CallRequest) GetArgs() []byte {
|
||||
if x != nil {
|
||||
return x.Args
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type CallResponse struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
Value []byte `protobuf:"bytes,1,opt,name=value,proto3" json:"value,omitempty"` // interface{}
|
||||
}
|
||||
|
||||
func (x *CallResponse) Reset() {
|
||||
*x = CallResponse{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_plugin_proto_debugtalk_proto_msgTypes[3]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
}
|
||||
|
||||
func (x *CallResponse) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*CallResponse) ProtoMessage() {}
|
||||
|
||||
func (x *CallResponse) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_plugin_proto_debugtalk_proto_msgTypes[3]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use CallResponse.ProtoReflect.Descriptor instead.
|
||||
func (*CallResponse) Descriptor() ([]byte, []int) {
|
||||
return file_plugin_proto_debugtalk_proto_rawDescGZIP(), []int{3}
|
||||
}
|
||||
|
||||
func (x *CallResponse) GetValue() []byte {
|
||||
if x != nil {
|
||||
return x.Value
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
var File_plugin_proto_debugtalk_proto protoreflect.FileDescriptor
|
||||
|
||||
var file_plugin_proto_debugtalk_proto_rawDesc = []byte{
|
||||
0x0a, 0x1c, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x64,
|
||||
0x65, 0x62, 0x75, 0x67, 0x74, 0x61, 0x6c, 0x6b, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x05,
|
||||
0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x07, 0x0a, 0x05, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x22, 0x28,
|
||||
0x0a, 0x10, 0x47, 0x65, 0x74, 0x4e, 0x61, 0x6d, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e,
|
||||
0x73, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28,
|
||||
0x09, 0x52, 0x05, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x22, 0x35, 0x0a, 0x0b, 0x43, 0x61, 0x6c, 0x6c,
|
||||
0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18,
|
||||
0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x61,
|
||||
0x72, 0x67, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, 0x61, 0x72, 0x67, 0x73, 0x22,
|
||||
0x24, 0x0a, 0x0c, 0x43, 0x61, 0x6c, 0x6c, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12,
|
||||
0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05,
|
||||
0x76, 0x61, 0x6c, 0x75, 0x65, 0x32, 0x6f, 0x0a, 0x09, 0x44, 0x65, 0x62, 0x75, 0x67, 0x54, 0x61,
|
||||
0x6c, 0x6b, 0x12, 0x31, 0x0a, 0x08, 0x47, 0x65, 0x74, 0x4e, 0x61, 0x6d, 0x65, 0x73, 0x12, 0x0c,
|
||||
0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x17, 0x2e, 0x70,
|
||||
0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x47, 0x65, 0x74, 0x4e, 0x61, 0x6d, 0x65, 0x73, 0x52, 0x65, 0x73,
|
||||
0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x2f, 0x0a, 0x04, 0x43, 0x61, 0x6c, 0x6c, 0x12, 0x12, 0x2e,
|
||||
0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x43, 0x61, 0x6c, 0x6c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73,
|
||||
0x74, 0x1a, 0x13, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x43, 0x61, 0x6c, 0x6c, 0x52, 0x65,
|
||||
0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x42, 0x11, 0x5a, 0x0f, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e,
|
||||
0x2f, 0x67, 0x6f, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f,
|
||||
0x33,
|
||||
}
|
||||
|
||||
var (
|
||||
file_plugin_proto_debugtalk_proto_rawDescOnce sync.Once
|
||||
file_plugin_proto_debugtalk_proto_rawDescData = file_plugin_proto_debugtalk_proto_rawDesc
|
||||
)
|
||||
|
||||
func file_plugin_proto_debugtalk_proto_rawDescGZIP() []byte {
|
||||
file_plugin_proto_debugtalk_proto_rawDescOnce.Do(func() {
|
||||
file_plugin_proto_debugtalk_proto_rawDescData = protoimpl.X.CompressGZIP(file_plugin_proto_debugtalk_proto_rawDescData)
|
||||
})
|
||||
return file_plugin_proto_debugtalk_proto_rawDescData
|
||||
}
|
||||
|
||||
var file_plugin_proto_debugtalk_proto_msgTypes = make([]protoimpl.MessageInfo, 4)
|
||||
var file_plugin_proto_debugtalk_proto_goTypes = []interface{}{
|
||||
(*Empty)(nil), // 0: proto.Empty
|
||||
(*GetNamesResponse)(nil), // 1: proto.GetNamesResponse
|
||||
(*CallRequest)(nil), // 2: proto.CallRequest
|
||||
(*CallResponse)(nil), // 3: proto.CallResponse
|
||||
}
|
||||
var file_plugin_proto_debugtalk_proto_depIdxs = []int32{
|
||||
0, // 0: proto.DebugTalk.GetNames:input_type -> proto.Empty
|
||||
2, // 1: proto.DebugTalk.Call:input_type -> proto.CallRequest
|
||||
1, // 2: proto.DebugTalk.GetNames:output_type -> proto.GetNamesResponse
|
||||
3, // 3: proto.DebugTalk.Call:output_type -> proto.CallResponse
|
||||
2, // [2:4] is the sub-list for method output_type
|
||||
0, // [0:2] is the sub-list for method input_type
|
||||
0, // [0:0] is the sub-list for extension type_name
|
||||
0, // [0:0] is the sub-list for extension extendee
|
||||
0, // [0:0] is the sub-list for field type_name
|
||||
}
|
||||
|
||||
func init() { file_plugin_proto_debugtalk_proto_init() }
|
||||
func file_plugin_proto_debugtalk_proto_init() {
|
||||
if File_plugin_proto_debugtalk_proto != nil {
|
||||
return
|
||||
}
|
||||
if !protoimpl.UnsafeEnabled {
|
||||
file_plugin_proto_debugtalk_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*Empty); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
return &v.sizeCache
|
||||
case 2:
|
||||
return &v.unknownFields
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
file_plugin_proto_debugtalk_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*GetNamesResponse); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
return &v.sizeCache
|
||||
case 2:
|
||||
return &v.unknownFields
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
file_plugin_proto_debugtalk_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*CallRequest); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
return &v.sizeCache
|
||||
case 2:
|
||||
return &v.unknownFields
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
file_plugin_proto_debugtalk_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*CallResponse); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
return &v.sizeCache
|
||||
case 2:
|
||||
return &v.unknownFields
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
type x struct{}
|
||||
out := protoimpl.TypeBuilder{
|
||||
File: protoimpl.DescBuilder{
|
||||
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
||||
RawDescriptor: file_plugin_proto_debugtalk_proto_rawDesc,
|
||||
NumEnums: 0,
|
||||
NumMessages: 4,
|
||||
NumExtensions: 0,
|
||||
NumServices: 1,
|
||||
},
|
||||
GoTypes: file_plugin_proto_debugtalk_proto_goTypes,
|
||||
DependencyIndexes: file_plugin_proto_debugtalk_proto_depIdxs,
|
||||
MessageInfos: file_plugin_proto_debugtalk_proto_msgTypes,
|
||||
}.Build()
|
||||
File_plugin_proto_debugtalk_proto = out.File
|
||||
file_plugin_proto_debugtalk_proto_rawDesc = nil
|
||||
file_plugin_proto_debugtalk_proto_goTypes = nil
|
||||
file_plugin_proto_debugtalk_proto_depIdxs = nil
|
||||
}
|
||||
141
plugin/go/proto/debugtalk_grpc.pb.go
Normal file
141
plugin/go/proto/debugtalk_grpc.pb.go
Normal file
@@ -0,0 +1,141 @@
|
||||
// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
|
||||
// versions:
|
||||
// - protoc-gen-go-grpc v1.2.0
|
||||
// - protoc v3.19.4
|
||||
// source: plugin/proto/debugtalk.proto
|
||||
|
||||
package proto
|
||||
|
||||
import (
|
||||
context "context"
|
||||
grpc "google.golang.org/grpc"
|
||||
codes "google.golang.org/grpc/codes"
|
||||
status "google.golang.org/grpc/status"
|
||||
)
|
||||
|
||||
// This is a compile-time assertion to ensure that this generated file
|
||||
// is compatible with the grpc package it is being compiled against.
|
||||
// Requires gRPC-Go v1.32.0 or later.
|
||||
const _ = grpc.SupportPackageIsVersion7
|
||||
|
||||
// DebugTalkClient is the client API for DebugTalk service.
|
||||
//
|
||||
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.
|
||||
type DebugTalkClient interface {
|
||||
GetNames(ctx context.Context, in *Empty, opts ...grpc.CallOption) (*GetNamesResponse, error)
|
||||
Call(ctx context.Context, in *CallRequest, opts ...grpc.CallOption) (*CallResponse, error)
|
||||
}
|
||||
|
||||
type debugTalkClient struct {
|
||||
cc grpc.ClientConnInterface
|
||||
}
|
||||
|
||||
func NewDebugTalkClient(cc grpc.ClientConnInterface) DebugTalkClient {
|
||||
return &debugTalkClient{cc}
|
||||
}
|
||||
|
||||
func (c *debugTalkClient) GetNames(ctx context.Context, in *Empty, opts ...grpc.CallOption) (*GetNamesResponse, error) {
|
||||
out := new(GetNamesResponse)
|
||||
err := c.cc.Invoke(ctx, "/proto.DebugTalk/GetNames", in, out, opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *debugTalkClient) Call(ctx context.Context, in *CallRequest, opts ...grpc.CallOption) (*CallResponse, error) {
|
||||
out := new(CallResponse)
|
||||
err := c.cc.Invoke(ctx, "/proto.DebugTalk/Call", in, out, opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
// DebugTalkServer is the server API for DebugTalk service.
|
||||
// All implementations must embed UnimplementedDebugTalkServer
|
||||
// for forward compatibility
|
||||
type DebugTalkServer interface {
|
||||
GetNames(context.Context, *Empty) (*GetNamesResponse, error)
|
||||
Call(context.Context, *CallRequest) (*CallResponse, error)
|
||||
mustEmbedUnimplementedDebugTalkServer()
|
||||
}
|
||||
|
||||
// UnimplementedDebugTalkServer must be embedded to have forward compatible implementations.
|
||||
type UnimplementedDebugTalkServer struct {
|
||||
}
|
||||
|
||||
func (UnimplementedDebugTalkServer) GetNames(context.Context, *Empty) (*GetNamesResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method GetNames not implemented")
|
||||
}
|
||||
func (UnimplementedDebugTalkServer) Call(context.Context, *CallRequest) (*CallResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method Call not implemented")
|
||||
}
|
||||
func (UnimplementedDebugTalkServer) mustEmbedUnimplementedDebugTalkServer() {}
|
||||
|
||||
// UnsafeDebugTalkServer may be embedded to opt out of forward compatibility for this service.
|
||||
// Use of this interface is not recommended, as added methods to DebugTalkServer will
|
||||
// result in compilation errors.
|
||||
type UnsafeDebugTalkServer interface {
|
||||
mustEmbedUnimplementedDebugTalkServer()
|
||||
}
|
||||
|
||||
func RegisterDebugTalkServer(s grpc.ServiceRegistrar, srv DebugTalkServer) {
|
||||
s.RegisterService(&DebugTalk_ServiceDesc, srv)
|
||||
}
|
||||
|
||||
func _DebugTalk_GetNames_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(Empty)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(DebugTalkServer).GetNames(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: "/proto.DebugTalk/GetNames",
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(DebugTalkServer).GetNames(ctx, req.(*Empty))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
func _DebugTalk_Call_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(CallRequest)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(DebugTalkServer).Call(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: "/proto.DebugTalk/Call",
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(DebugTalkServer).Call(ctx, req.(*CallRequest))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
// DebugTalk_ServiceDesc is the grpc.ServiceDesc for DebugTalk service.
|
||||
// It's only intended for direct use with grpc.RegisterService,
|
||||
// and not to be introspected or modified (even as a copy)
|
||||
var DebugTalk_ServiceDesc = grpc.ServiceDesc{
|
||||
ServiceName: "proto.DebugTalk",
|
||||
HandlerType: (*DebugTalkServer)(nil),
|
||||
Methods: []grpc.MethodDesc{
|
||||
{
|
||||
MethodName: "GetNames",
|
||||
Handler: _DebugTalk_GetNames_Handler,
|
||||
},
|
||||
{
|
||||
MethodName: "Call",
|
||||
Handler: _DebugTalk_Call_Handler,
|
||||
},
|
||||
},
|
||||
Streams: []grpc.StreamDesc{},
|
||||
Metadata: "plugin/proto/debugtalk.proto",
|
||||
}
|
||||
97
plugin/go/rpc.go
Normal file
97
plugin/go/rpc.go
Normal file
@@ -0,0 +1,97 @@
|
||||
package pluginInternal
|
||||
|
||||
import (
|
||||
"encoding/gob"
|
||||
"net/rpc"
|
||||
|
||||
"github.com/hashicorp/go-plugin"
|
||||
"github.com/rs/zerolog/log"
|
||||
)
|
||||
|
||||
func init() {
|
||||
gob.Register(new(funcData))
|
||||
}
|
||||
|
||||
// funcData is used to transfer between plugin and host via RPC.
|
||||
type funcData struct {
|
||||
Name string // function name
|
||||
Args []interface{} // function arguments
|
||||
}
|
||||
|
||||
// functionRPCClient runs on the host side, it implements FuncCaller interface
|
||||
type functionRPCClient struct {
|
||||
client *rpc.Client
|
||||
}
|
||||
|
||||
func (g *functionRPCClient) GetNames() ([]string, error) {
|
||||
var resp []string
|
||||
err := g.client.Call("Plugin.GetNames", new(interface{}), &resp)
|
||||
if err != nil {
|
||||
log.Error().Err(err).Msg("rpc call GetNames() failed")
|
||||
return nil, err
|
||||
}
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
// host -> plugin
|
||||
func (g *functionRPCClient) Call(funcName string, funcArgs ...interface{}) (interface{}, error) {
|
||||
log.Info().Str("funcName", funcName).Interface("funcArgs", funcArgs).Msg("call function via RPC")
|
||||
f := funcData{
|
||||
Name: funcName,
|
||||
Args: funcArgs,
|
||||
}
|
||||
|
||||
var args interface{} = f
|
||||
var resp interface{}
|
||||
err := g.client.Call("Plugin.Call", &args, &resp)
|
||||
if err != nil {
|
||||
log.Error().Err(err).
|
||||
Str("funcName", funcName).Interface("funcArgs", funcArgs).
|
||||
Msg("rpc Call() failed")
|
||||
return nil, err
|
||||
}
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
// functionRPCServer runs on the plugin side, executing the user custom function.
|
||||
type functionRPCServer struct {
|
||||
Impl FuncCaller
|
||||
}
|
||||
|
||||
// plugin execution
|
||||
func (s *functionRPCServer) GetNames(args interface{}, resp *[]string) error {
|
||||
log.Info().Interface("args", args).Msg("rpc GetNames() called on plugin side")
|
||||
var err error
|
||||
*resp, err = s.Impl.GetNames()
|
||||
if err != nil {
|
||||
log.Error().Err(err).Msg("rpc GetNames() execution failed")
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// plugin execution
|
||||
func (s *functionRPCServer) Call(args interface{}, resp *interface{}) error {
|
||||
log.Info().Interface("args", args).Msg("rpc Call() called on plugin side")
|
||||
f := args.(*funcData)
|
||||
var err error
|
||||
*resp, err = s.Impl.Call(f.Name, f.Args...)
|
||||
if err != nil {
|
||||
log.Error().Err(err).Interface("args", args).Msg("rpc Call() execution failed")
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// RPCPlugin implements hashicorp's plugin.Plugin.
|
||||
type RPCPlugin struct {
|
||||
Impl FuncCaller
|
||||
}
|
||||
|
||||
func (p *RPCPlugin) Server(*plugin.MuxBroker) (interface{}, error) {
|
||||
return &functionRPCServer{Impl: p.Impl}, nil
|
||||
}
|
||||
|
||||
func (RPCPlugin) Client(b *plugin.MuxBroker, c *rpc.Client) (interface{}, error) {
|
||||
return &functionRPCClient{client: c}, nil
|
||||
}
|
||||
Reference in New Issue
Block a user