125
									
								
								plugin/default.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										125
									
								
								plugin/default.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,125 @@ | |||||||
|  | // 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 | ||||||
|  | 	default: | ||||||
|  | 		return fmt.Errorf("Unknown plugin type: %s for %s", c.Type, c.Name) | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	return nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // 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() | ||||||
|  | } | ||||||
							
								
								
									
										46
									
								
								plugin/plugin.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										46
									
								
								plugin/plugin.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,46 @@ | |||||||
|  | // 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{} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | var ( | ||||||
|  | 	// Default plugin loader | ||||||
|  | 	DefaultPlugin = NewPlugin() | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | // NewPlugin creates a new plugin interface | ||||||
|  | func NewPlugin() Plugin { | ||||||
|  | 	return &plugin{} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func Build(path string, c *Config) error { | ||||||
|  | 	return DefaultPlugin.Build(path, c) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func Load(path string) (*Config, error) { | ||||||
|  | 	return DefaultPlugin.Load(path) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func Init(c *Config) error { | ||||||
|  | 	return DefaultPlugin.Init(c) | ||||||
|  | } | ||||||
							
								
								
									
										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}}, | ||||||
|  | } | ||||||
|  | ` | ||||||
|  | ) | ||||||
							
								
								
									
										21
									
								
								service.go
									
									
									
									
									
								
							
							
						
						
									
										21
									
								
								service.go
									
									
									
									
									
								
							| @@ -3,6 +3,7 @@ package micro | |||||||
| import ( | import ( | ||||||
| 	"os" | 	"os" | ||||||
| 	"os/signal" | 	"os/signal" | ||||||
|  | 	"strings" | ||||||
| 	"sync" | 	"sync" | ||||||
| 	"syscall" | 	"syscall" | ||||||
|  |  | ||||||
| @@ -10,7 +11,9 @@ import ( | |||||||
| 	"github.com/micro/go-micro/config/cmd" | 	"github.com/micro/go-micro/config/cmd" | ||||||
| 	"github.com/micro/go-micro/debug/handler" | 	"github.com/micro/go-micro/debug/handler" | ||||||
| 	"github.com/micro/go-micro/metadata" | 	"github.com/micro/go-micro/metadata" | ||||||
|  | 	"github.com/micro/go-micro/plugin" | ||||||
| 	"github.com/micro/go-micro/server" | 	"github.com/micro/go-micro/server" | ||||||
|  | 	"github.com/micro/go-micro/util/log" | ||||||
| ) | ) | ||||||
|  |  | ||||||
| type service struct { | type service struct { | ||||||
| @@ -44,6 +47,24 @@ func (s *service) Init(opts ...Option) { | |||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	s.once.Do(func() { | 	s.once.Do(func() { | ||||||
|  | 		// setup the plugins | ||||||
|  | 		for _, p := range strings.Split(os.Getenv("MICRO_PLUGIN"), ",") { | ||||||
|  | 			if len(p) == 0 { | ||||||
|  | 				continue | ||||||
|  | 			} | ||||||
|  |  | ||||||
|  | 			// load the plugin | ||||||
|  | 			c, err := plugin.Load(p) | ||||||
|  | 			if err != nil { | ||||||
|  | 				log.Fatal(err) | ||||||
|  | 			} | ||||||
|  |  | ||||||
|  | 			// initialise the plugin | ||||||
|  | 			if err := plugin.Init(c); err != nil { | ||||||
|  | 				log.Fatal(err) | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  |  | ||||||
| 		// Initialise the command flags, overriding new service | 		// Initialise the command flags, overriding new service | ||||||
| 		_ = s.opts.Cmd.Init( | 		_ = s.opts.Cmd.Init( | ||||||
| 			cmd.Broker(&s.opts.Broker), | 			cmd.Broker(&s.opts.Broker), | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user