github.com/Unheilbar/quorum@v1.0.0/plugin/service.go (about) 1 package plugin 2 3 import ( 4 "fmt" 5 "reflect" 6 "sync" 7 "sync/atomic" 8 "unsafe" 9 10 "github.com/ethereum/go-ethereum/accounts/pluggable" 11 "github.com/ethereum/go-ethereum/log" 12 "github.com/ethereum/go-ethereum/rpc" 13 ) 14 15 type PluginManagerInterface interface { 16 APIs() []rpc.API 17 Start() (err error) 18 Stop() error 19 IsEnabled(name PluginInterfaceName) bool 20 PluginsInfo() interface{} 21 Reload(name PluginInterfaceName) (bool, error) 22 GetPluginTemplate(name PluginInterfaceName, v managedPlugin) error 23 } 24 25 //go:generate mockgen -source=service.go -destination plugin_manager_mockery.go -package plugin 26 var _ PluginManagerInterface = &PluginManager{} 27 var _ PluginManagerInterface = &MockPluginManagerInterface{} 28 29 // this implements geth service 30 type PluginManager struct { 31 nodeName string // geth node name 32 pluginBaseDir string // base directory for all the plugins 33 verifier Verifier 34 centralClient *CentralClient 35 downloader *Downloader 36 settings *Settings 37 mux sync.Mutex // control concurrent access to plugins cache 38 plugins map[PluginInterfaceName]managedPlugin // lazy load the actual plugin templates 39 initializedPlugins map[PluginInterfaceName]managedPlugin // prepopulate during initialization of plugin manager, needed for starting/stopping/getting info 40 pluginsStarted *int32 41 } 42 43 // this is called after PluginManager service has been successfully started 44 // See node/node.go#Start() 45 func (s *PluginManager) APIs() []rpc.API { 46 return append([]rpc.API{ 47 { 48 Namespace: "admin", 49 Service: NewPluginManagerAPI(s), 50 Version: "1.0", 51 Public: false, 52 }, 53 }, s.delegateAPIs()...) 54 } 55 56 func (s *PluginManager) Start() (err error) { 57 initializedPluginsCount := len(s.initializedPlugins) 58 if initializedPluginsCount == 0 { 59 log.Info("No plugins to initialise") 60 return 61 } 62 if atomic.LoadInt32(s.pluginsStarted) != 0 { 63 log.Info("Plugins already started") 64 return 65 } 66 log.Info("Starting all plugins", "count", initializedPluginsCount) 67 startedPlugins := make([]managedPlugin, 0, initializedPluginsCount) 68 for _, p := range s.initializedPlugins { 69 if err = p.Start(); err != nil { 70 break 71 } else { 72 startedPlugins = append(startedPlugins, p) 73 } 74 } 75 if err != nil { 76 for _, p := range startedPlugins { 77 _ = p.Stop() 78 } 79 } else { 80 atomic.StoreInt32(s.pluginsStarted, 1) 81 } 82 return 83 } 84 85 func (s *PluginManager) getPlugin(name PluginInterfaceName) (managedPlugin, bool) { 86 s.mux.Lock() 87 defer s.mux.Unlock() 88 p, ok := s.plugins[name] // check if it's been used before 89 if !ok { 90 p, ok = s.initializedPlugins[name] // check if it's been initialized before 91 } 92 return p, ok 93 } 94 95 // Check if a plugin is enabled/setup 96 func (s *PluginManager) IsEnabled(name PluginInterfaceName) bool { 97 if s == nil { 98 return false 99 } 100 _, ok := s.initializedPlugins[name] 101 return ok 102 } 103 104 // store the plugin instance to the value of the pointer v and cache it 105 // this function makes sure v value will never be nil 106 func (s *PluginManager) GetPluginTemplate(name PluginInterfaceName, v managedPlugin) error { 107 rv := reflect.ValueOf(v) 108 if rv.Kind() != reflect.Ptr || rv.IsNil() { 109 return fmt.Errorf("invalid argument value, expected a pointer but got %s", reflect.TypeOf(v)) 110 } 111 recoverToErrorFunc := func(f func()) (err error) { 112 defer func() { 113 if r := recover(); r != nil { 114 err = fmt.Errorf("%s", r) 115 } 116 }() 117 f() 118 return 119 } 120 if p, ok := s.plugins[name]; ok { 121 return recoverToErrorFunc(func() { 122 cachedValue := reflect.ValueOf(p) 123 rv.Elem().Set(cachedValue.Elem()) 124 }) 125 } 126 base, ok := s.initializedPlugins[name] 127 if !ok { 128 return fmt.Errorf("plugin: [%s] is not found", name) 129 } 130 if err := recoverToErrorFunc(func() { 131 basePluginValue := reflect.ValueOf(base) 132 // the first field in the plugin template object is the basePlugin 133 // it indicates that the plugin template "extends" basePlugin 134 basePluginField := rv.Elem().FieldByName("basePlugin") 135 if !basePluginField.IsValid() || basePluginField.Type() != basePluginPointerType { 136 panic("plugin template must extend *basePlugin") 137 } 138 // need to have write access to the unexported field in the target object 139 basePluginField = reflect.NewAt(basePluginField.Type(), unsafe.Pointer(basePluginField.UnsafeAddr())).Elem() 140 basePluginField.Set(basePluginValue) 141 }); err != nil { 142 return err 143 } 144 s.mux.Lock() 145 defer s.mux.Unlock() 146 s.plugins[name] = v 147 return nil 148 } 149 150 func (s *PluginManager) Stop() error { 151 initializedPluginsCount := len(s.initializedPlugins) 152 log.Info("Stopping all plugins", "count", initializedPluginsCount) 153 allErrors := make([]error, 0) 154 for _, p := range s.initializedPlugins { 155 if err := p.Stop(); err != nil { 156 allErrors = append(allErrors, err) 157 } 158 } 159 log.Info("All plugins stopped", "errors", allErrors) 160 if initializedPluginsCount > 0 { 161 atomic.StoreInt32(s.pluginsStarted, 0) 162 } 163 if len(allErrors) == 0 { 164 return nil 165 } 166 return fmt.Errorf("%s", allErrors) 167 } 168 169 // Provide details of current plugins being used 170 func (s *PluginManager) PluginsInfo() interface{} { 171 info := make(map[PluginInterfaceName]interface{}) 172 if len(s.initializedPlugins) == 0 { 173 return info 174 } 175 info["baseDir"] = s.pluginBaseDir 176 for _, p := range s.initializedPlugins { 177 k, v := p.Info() 178 info[k] = v 179 } 180 return info 181 } 182 183 // AddAccountPluginToBackend adds the account plugin to the provided account backend 184 func (s *PluginManager) AddAccountPluginToBackend(b *pluggable.Backend) error { 185 v := new(ReloadableAccountServiceFactory) 186 if err := s.GetPluginTemplate(AccountPluginInterfaceName, v); err != nil { 187 return err 188 } 189 service, err := v.Create() 190 if err != nil { 191 return err 192 } 193 if err := b.SetPluginService(service); err != nil { 194 return err 195 } 196 return nil 197 } 198 199 func (s *PluginManager) Reload(name PluginInterfaceName) (bool, error) { 200 p, ok := s.getPlugin(name) 201 if !ok { 202 return false, fmt.Errorf("no such plugin provider: %s", name) 203 } 204 _ = p.Stop() 205 if err := p.Start(); err != nil { 206 return false, err 207 } 208 return true, nil 209 } 210 211 // this is to configure delegate APIs call to the plugins 212 func (s *PluginManager) delegateAPIs() []rpc.API { 213 apis := make([]rpc.API, 0) 214 for _, p := range s.initializedPlugins { 215 interfaceName, _ := p.Info() 216 if pluginProvider, ok := pluginProviders[interfaceName]; ok { 217 if pluginProvider.apiProviderFunc != nil { 218 namespace := fmt.Sprintf("plugin@%s", interfaceName) 219 log.Debug("adding RPC API delegate for plugin", "provider", interfaceName, "namespace", namespace) 220 if delegates, err := pluginProvider.apiProviderFunc(namespace, s); err != nil { 221 log.Error("unable to delegate RPC API calls to plugin", "provider", interfaceName, "error", err) 222 } else { 223 apis = append(apis, delegates...) 224 } 225 } 226 } 227 } 228 return apis 229 } 230 231 func NewPluginManager(nodeName string, settings *Settings, skipVerify bool, localVerify bool, publicKey string) (*PluginManager, error) { 232 pm := &PluginManager{ 233 nodeName: nodeName, 234 pluginBaseDir: settings.BaseDir.String(), 235 centralClient: NewPluginCentralClient(settings.CentralConfig), 236 plugins: make(map[PluginInterfaceName]managedPlugin), 237 initializedPlugins: make(map[PluginInterfaceName]managedPlugin), 238 settings: settings, 239 pluginsStarted: new(int32), 240 } 241 pm.downloader = NewDownloader(pm) 242 if skipVerify { 243 log.Warn("plugin: ignore integrity verification") 244 pm.verifier = NewNonVerifier() 245 } else { 246 var err error 247 if pm.verifier, err = NewVerifier(pm, localVerify, publicKey); err != nil { 248 return nil, err 249 } 250 } 251 for pluginName, pluginDefinition := range settings.Providers { 252 log.Debug("Preparing plugin", "provider", pluginName, "name", pluginDefinition.Name, "version", pluginDefinition.Version) 253 pluginProvider, ok := pluginProviders[pluginName] 254 if !ok { 255 return nil, fmt.Errorf("plugin: [%s] is not supported", pluginName) 256 } 257 base, err := newBasePlugin(pm, pluginName, pluginDefinition, pluginProvider.pluginSet) 258 if err != nil { 259 return nil, fmt.Errorf("plugin [%s] %s", pluginName, err.Error()) 260 } 261 pm.initializedPlugins[pluginName] = base 262 } 263 log.Debug("Created plugin manager", "PluginsInfo()", pm.PluginsInfo()) 264 return pm, nil 265 } 266 267 func NewEmptyPluginManager() *PluginManager { 268 return &PluginManager{ 269 plugins: make(map[PluginInterfaceName]managedPlugin), 270 } 271 }