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 }