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 }