This project needs to use the dynamic link library technology, the main program dynamically loaded some functional modules, so that in the expansion of the function, no need to modify the main program, only need to add the function module dynamic call. The plugin function of Golang officially supported was studied, and several deficiencies were found.
1. The official plugin function is essentially implemented with CGO, compiling an so file and then calling
2. Linux only, Windows not supported
3. Plugin module Panic, the main program will also panic, can not be isolated.
For these reasons, I started looking for appropriate third-party support. Later found such an open source library, Https://github.com/hashicorp/go-plugin, feel in line with my needs. It is based on the NET/RPC, GRPC implementation, the main program and plugin program is two QTJ independent process, can be called through the main program plugin process startup, can also attach a process way. The effect of similar dynamic link library calls is achieved through local network communication.
The official examples are as follows:
Plugin
Package Mainimport ("OS" "Github.com/hashicorp/go-hclog" "Github.com/hashicorp/go-plugin" "github.com/hashicorp/ Go-plugin/examples/basic/commons ")//here is a real implementation of Greetertype Greeterhello struct {logger hclog. Logger}func (g *greeterhello) Greet () string {g.logger.debug ("message from Greeterhello.greet") return "hello!"} Handshakeconfigs is used to just do a basic handshake between//a plugin and host. If The handshake fails, a user friendly error is shown.//This prevents users from executing bad plugins or executing a pl ugin//directory. It is a UX feature, not a security feature.var handshakeconfig = plugin. Handshakeconfig{protocolversion:1,magiccookiekey: "Basic_plugin", Magiccookievalue: "Hello",}func main () {logger: = Hclog. New (&hclog. Loggeroptions{level:hclog. Trace,output:os. Stderr,jsonformat:true,}) greeter: = &greeterhello{logger:logger,}//Pluginmap is the map of plugins we can dispense. var pluginmap = Map[string]plugin. plugin{"Greeter": &example. Greeterplugin{impl:greeter},}logger. Debug ("Message from plugin", "foo", "bar") plugin. Serve (&plugin. Serveconfig{handshakeconfig:handshakeconfig,plugins:pluginmap,})}
Main program (caller):
Package Mainimport ("FMT" "Log" "OS" "Os/exec" Hclog "Github.com/hashicorp/go-hclog" "Github.com/hashicorp/go-plugin" " Github.com/hashicorp/go-plugin/examples/basic/commons ") Func main () {//Create an hclog. Loggerlogger: = Hclog. New (&hclog. Loggeroptions{name: "Plugin", Output:os. Stdout,level:hclog. Debug,})//We ' re a host! Start by launching the plugin process.client: = plugin. Newclient (&plugin. Clientconfig{handshakeconfig:handshakeconfig,plugins:pluginmap,cmd:exec. Command ("./plugin/greeter"), Logger:logger,}) defer client. Kill ()//Connect via rpcrpcclient, err: = client. Client () if err! = Nil {log. Fatal (Err)}//Request the Pluginraw, err: = Rpcclient.dispense ("greeter") if err! = Nil {log. Fatal (ERR)}//We should have a Greeter now! This feels-like-a normal interface//implementation but was in fact-over-an RPC connection.greeter: = Raw. (Example. Greeter) fmt. Println (greeter. Greet ())}//Handshakeconfigs is used to just do a basic handshake between//a PLUGin and host. If The handshake fails, a user friendly error is shown.//This prevents users from executing bad plugins or executing a pl ugin//directory. It is a UX feature, not a security feature.var handshakeconfig = plugin. Handshakeconfig{protocolversion:1,magiccookiekey: "Basic_plugin", Magiccookievalue: "Hello",}//PluginMap is the map o F Plugins we can dispense.var Pluginmap = Map[string]plugin. plugin{"greeter": &example. greeterplugin{},}