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