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