Support plugin loading
This commit is contained in:
		
							
								
								
									
										122
									
								
								plugin/default.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										122
									
								
								plugin/default.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,122 @@ | ||||
| // Package plugin provides the ability to load plugins | ||||
| package plugin | ||||
|  | ||||
| import ( | ||||
| 	"errors" | ||||
| 	"fmt" | ||||
| 	"os" | ||||
| 	"os/exec" | ||||
| 	"path/filepath" | ||||
| 	pg "plugin" | ||||
| 	"strings" | ||||
| 	"text/template" | ||||
|  | ||||
| 	"github.com/micro/go-micro/broker" | ||||
| 	"github.com/micro/go-micro/client" | ||||
| 	"github.com/micro/go-micro/client/selector" | ||||
| 	"github.com/micro/go-micro/config/cmd" | ||||
| 	"github.com/micro/go-micro/registry" | ||||
| 	"github.com/micro/go-micro/server" | ||||
| 	"github.com/micro/go-micro/transport" | ||||
| ) | ||||
|  | ||||
| type plugin struct{} | ||||
|  | ||||
| // Init sets up the plugin | ||||
| func (p *plugin) Init(c *Config) error { | ||||
| 	switch c.Type { | ||||
| 	case "broker": | ||||
| 		pg, ok := c.NewFunc.(func(...broker.Option) broker.Broker) | ||||
| 		if !ok { | ||||
| 			return fmt.Errorf("Invalid plugin %s", c.Name) | ||||
| 		} | ||||
| 		cmd.DefaultBrokers[c.Name] = pg | ||||
| 	case "client": | ||||
| 		pg, ok := c.NewFunc.(func(...client.Option) client.Client) | ||||
| 		if !ok { | ||||
| 			return fmt.Errorf("Invalid plugin %s", c.Name) | ||||
| 		} | ||||
| 		cmd.DefaultClients[c.Name] = pg | ||||
| 	case "registry": | ||||
| 		pg, ok := c.NewFunc.(func(...registry.Option) registry.Registry) | ||||
| 		if !ok { | ||||
| 			return fmt.Errorf("Invalid plugin %s", c.Name) | ||||
| 		} | ||||
| 		cmd.DefaultRegistries[c.Name] = pg | ||||
|  | ||||
| 	case "selector": | ||||
| 		pg, ok := c.NewFunc.(func(...selector.Option) selector.Selector) | ||||
| 		if !ok { | ||||
| 			return fmt.Errorf("Invalid plugin %s", c.Name) | ||||
| 		} | ||||
| 		cmd.DefaultSelectors[c.Name] = pg | ||||
| 	case "server": | ||||
| 		pg, ok := c.NewFunc.(func(...server.Option) server.Server) | ||||
| 		if !ok { | ||||
| 			return fmt.Errorf("Invalid plugin %s", c.Name) | ||||
| 		} | ||||
| 		cmd.DefaultServers[c.Name] = pg | ||||
| 	case "transport": | ||||
| 		pg, ok := c.NewFunc.(func(...transport.Option) transport.Transport) | ||||
| 		if !ok { | ||||
| 			return fmt.Errorf("Invalid plugin %s", c.Name) | ||||
| 		} | ||||
| 		cmd.DefaultTransports[c.Name] = pg | ||||
| 	} | ||||
| 	return fmt.Errorf("Unknown plugin type: %s for %s", c.Type, c.Name) | ||||
| } | ||||
|  | ||||
| // Load loads a plugin created with `go build -buildmode=plugin` | ||||
| func (p *plugin) Load(path string) (*Config, error) { | ||||
| 	plugin, err := pg.Open(path) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	s, err := plugin.Lookup("Plugin") | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	pl, ok := s.(*Config) | ||||
| 	if !ok { | ||||
| 		return nil, errors.New("could not cast Plugin object") | ||||
| 	} | ||||
| 	return pl, nil | ||||
| } | ||||
|  | ||||
| // Generate creates a go file at the specified path. | ||||
| // You must use `go build -buildmode=plugin`to build it. | ||||
| func (p *plugin) Generate(path string, c *Config) error { | ||||
| 	f, err := os.Create(path) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	defer f.Close() | ||||
| 	t, err := template.New(c.Name).Parse(tmpl) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	return t.Execute(f, c) | ||||
| } | ||||
|  | ||||
| // Build generates a dso plugin using the go command `go build -buildmode=plugin` | ||||
| func (p *plugin) Build(path string, c *Config) error { | ||||
| 	path = strings.TrimSuffix(path, ".so") | ||||
|  | ||||
| 	// create go file in tmp path | ||||
| 	temp := os.TempDir() | ||||
| 	base := filepath.Base(path) | ||||
| 	goFile := filepath.Join(temp, base+".go") | ||||
|  | ||||
| 	// generate .go file | ||||
| 	if err := p.Generate(goFile, c); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	// remove .go file | ||||
| 	defer os.Remove(goFile) | ||||
|  | ||||
| 	if err := os.MkdirAll(filepath.Dir(path), 0755); err != nil && !os.IsExist(err) { | ||||
| 		return fmt.Errorf("Failed to create dir %s: %v", filepath.Dir(path), err) | ||||
| 	} | ||||
| 	cmd := exec.Command("go", "build", "-buildmode=plugin", "-o", path+".so", goFile) | ||||
| 	return cmd.Run() | ||||
| } | ||||
							
								
								
									
										29
									
								
								plugin/plugin.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								plugin/plugin.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,29 @@ | ||||
| // Package plugin provides the ability to load plugins | ||||
| package plugin | ||||
|  | ||||
| // Plugin is a plugin loaded from a file | ||||
| type Plugin interface { | ||||
| 	// Initialise a plugin with the config | ||||
| 	Init(c *Config) error | ||||
| 	// Load loads a .so plugin at the given path | ||||
| 	Load(path string) (*Config, error) | ||||
| 	// Build a .so plugin with config at the path specified | ||||
| 	Build(path string, c *Config) error | ||||
| } | ||||
|  | ||||
| // Config is the plugin config | ||||
| type Config struct { | ||||
| 	// Name of the plugin e.g rabbitmq | ||||
| 	Name string | ||||
| 	// Type of the plugin e.g broker | ||||
| 	Type string | ||||
| 	// Path specifies the import path | ||||
| 	Path string | ||||
| 	// NewFunc creates an instance of the plugin | ||||
| 	NewFunc interface{} | ||||
| } | ||||
|  | ||||
| // NewPlugin creates a new plugin interface | ||||
| func NewPlugin() Plugin { | ||||
| 	return &plugin{} | ||||
| } | ||||
							
								
								
									
										20
									
								
								plugin/template.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								plugin/template.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,20 @@ | ||||
| package plugin | ||||
|  | ||||
| var ( | ||||
| 	tmpl = ` | ||||
| package main | ||||
|  | ||||
| import ( | ||||
| 	"github.com/micro/go-micro/plugin" | ||||
|  | ||||
| 	"{{.Path}}" | ||||
| ) | ||||
|  | ||||
| var Plugin = plugin.Config{ | ||||
| 	Name: "{{.Name}}", | ||||
| 	Type: "{{.Type}}", | ||||
| 	Path: "{{.Path}}", | ||||
| 	NewFunc: {{.Name}}.{{.NewFunc}}, | ||||
| } | ||||
| ` | ||||
| ) | ||||
		Reference in New Issue
	
	Block a user