| package plugins |
| |
| import ( |
| "errors" |
| "sync" |
| |
| "github.com/Sirupsen/logrus" |
| ) |
| |
| var ( |
| ErrNotImplements = errors.New("Plugin does not implement the requested driver") |
| ) |
| |
| type plugins struct { |
| sync.Mutex |
| plugins map[string]*Plugin |
| } |
| |
| var ( |
| storage = plugins{plugins: make(map[string]*Plugin)} |
| extpointHandlers = make(map[string]func(string, *Client)) |
| ) |
| |
| type Manifest struct { |
| Implements []string |
| } |
| |
| type Plugin struct { |
| Name string |
| Addr string |
| Client *Client |
| Manifest *Manifest |
| } |
| |
| func (p *Plugin) activate() error { |
| m := new(Manifest) |
| p.Client = NewClient(p.Addr) |
| err := p.Client.Call("Plugin.Activate", nil, m) |
| if err != nil { |
| return err |
| } |
| |
| logrus.Debugf("%s's manifest: %v", p.Name, m) |
| p.Manifest = m |
| for _, iface := range m.Implements { |
| handler, handled := extpointHandlers[iface] |
| if !handled { |
| continue |
| } |
| handler(p.Name, p.Client) |
| } |
| return nil |
| } |
| |
| func load(name string) (*Plugin, error) { |
| registry := newLocalRegistry("") |
| pl, err := registry.Plugin(name) |
| if err != nil { |
| return nil, err |
| } |
| if err := pl.activate(); err != nil { |
| return nil, err |
| } |
| return pl, nil |
| } |
| |
| func get(name string) (*Plugin, error) { |
| storage.Lock() |
| defer storage.Unlock() |
| pl, ok := storage.plugins[name] |
| if ok { |
| return pl, nil |
| } |
| pl, err := load(name) |
| if err != nil { |
| return nil, err |
| } |
| |
| logrus.Debugf("Plugin: %v", pl) |
| storage.plugins[name] = pl |
| return pl, nil |
| } |
| |
| func Get(name, imp string) (*Plugin, error) { |
| pl, err := get(name) |
| if err != nil { |
| return nil, err |
| } |
| for _, driver := range pl.Manifest.Implements { |
| logrus.Debugf("%s implements: %s", name, driver) |
| if driver == imp { |
| return pl, nil |
| } |
| } |
| return nil, ErrNotImplements |
| } |
| |
| func Handle(iface string, fn func(string, *Client)) { |
| extpointHandlers[iface] = fn |
| } |