gitee.com/sasukebo/go-micro/v4@v4.7.1/plugins/plugin.go (about)

     1  // Package plugin provides the ability to load plugins
     2  package plugin
     3  
     4  import (
     5  	"errors"
     6  	"fmt"
     7  	"os"
     8  	"os/exec"
     9  	"path/filepath"
    10  	"plugin"
    11  	"strings"
    12  	"text/template"
    13  
    14  	"gitee.com/sasukebo/go-micro/v4/broker"
    15  	"gitee.com/sasukebo/go-micro/v4/client"
    16  	"gitee.com/sasukebo/go-micro/v4/cmd"
    17  	"gitee.com/sasukebo/go-micro/v4/registry"
    18  	"gitee.com/sasukebo/go-micro/v4/selector"
    19  	"gitee.com/sasukebo/go-micro/v4/server"
    20  	"gitee.com/sasukebo/go-micro/v4/transport"
    21  )
    22  
    23  // Plugin is a plugin loaded from a file
    24  type Plugin struct {
    25  	// Name of the plugin e.g rabbitmq
    26  	Name string
    27  	// Type of the plugin e.g broker
    28  	Type string
    29  	// Path specifies the import path
    30  	Path string
    31  	// NewFunc creates an instance of the plugin
    32  	NewFunc interface{}
    33  }
    34  
    35  // Init sets up the plugin
    36  func Init(p *Plugin) error {
    37  	switch p.Type {
    38  	case "broker":
    39  		pg, ok := p.NewFunc.(func(...broker.Option) broker.Broker)
    40  		if !ok {
    41  			return fmt.Errorf("Invalid plugin %s", p.Name)
    42  		}
    43  		cmd.DefaultBrokers[p.Name] = pg
    44  	case "client":
    45  		pg, ok := p.NewFunc.(func(...client.Option) client.Client)
    46  		if !ok {
    47  			return fmt.Errorf("Invalid plugin %s", p.Name)
    48  		}
    49  		cmd.DefaultClients[p.Name] = pg
    50  	case "registry":
    51  		pg, ok := p.NewFunc.(func(...registry.Option) registry.Registry)
    52  		if !ok {
    53  			return fmt.Errorf("Invalid plugin %s", p.Name)
    54  		}
    55  		cmd.DefaultRegistries[p.Name] = pg
    56  
    57  	case "selector":
    58  		pg, ok := p.NewFunc.(func(...selector.Option) selector.Selector)
    59  		if !ok {
    60  			return fmt.Errorf("Invalid plugin %s", p.Name)
    61  		}
    62  		cmd.DefaultSelectors[p.Name] = pg
    63  	case "server":
    64  		pg, ok := p.NewFunc.(func(...server.Option) server.Server)
    65  		if !ok {
    66  			return fmt.Errorf("Invalid plugin %s", p.Name)
    67  		}
    68  		cmd.DefaultServers[p.Name] = pg
    69  	case "transport":
    70  		pg, ok := p.NewFunc.(func(...transport.Option) transport.Transport)
    71  		if !ok {
    72  			return fmt.Errorf("Invalid plugin %s", p.Name)
    73  		}
    74  		cmd.DefaultTransports[p.Name] = pg
    75  	}
    76  
    77  	return fmt.Errorf("Unknown plugin type: %s for %s", p.Type, p.Name)
    78  }
    79  
    80  // Load loads a plugin created with `go build -buildmode=plugin`
    81  func Load(path string) (*Plugin, error) {
    82  	p, err := plugin.Open(path)
    83  	if err != nil {
    84  		return nil, err
    85  	}
    86  	s, err := p.Lookup("Plugin")
    87  	if err != nil {
    88  		return nil, err
    89  	}
    90  	pl, ok := s.(*Plugin)
    91  	if !ok {
    92  		return nil, errors.New("could not cast Plugin object")
    93  	}
    94  	return pl, nil
    95  }
    96  
    97  // Generate creates a go file at the specified path.
    98  // You must use `go build -buildmode=plugin`to build it.
    99  func Generate(path string, p *Plugin) error {
   100  	f, err := os.Create(path)
   101  	if err != nil {
   102  		return err
   103  	}
   104  	defer f.Close()
   105  	t, err := template.New(p.Name).Parse(tmpl)
   106  	if err != nil {
   107  		return err
   108  	}
   109  	return t.Execute(f, p)
   110  }
   111  
   112  // Build generates a dso plugin using the go command `go build -buildmode=plugin`
   113  func Build(path string, p *Plugin) error {
   114  	path = strings.TrimSuffix(path, ".so")
   115  
   116  	// create go file in tmp path
   117  	temp := os.TempDir()
   118  	base := filepath.Base(path)
   119  	goFile := filepath.Join(temp, base+".go")
   120  
   121  	// generate .go file
   122  	if err := Generate(goFile, p); err != nil {
   123  		return err
   124  	}
   125  	// remove .go file
   126  	defer os.Remove(goFile)
   127  
   128  	if err := os.MkdirAll(filepath.Dir(path), 0755); err != nil && !os.IsExist(err) {
   129  		return fmt.Errorf("Failed to create dir %s: %v", filepath.Dir(path), err)
   130  	}
   131  	c := exec.Command("go", "build", "-buildmode=plugin", "-o", path+".so", goFile)
   132  	return c.Run()
   133  }