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 }