github.com/yandex/pandora@v0.5.32/core/plugin/registry.go (about) 1 package plugin 2 3 import ( 4 "reflect" 5 6 "github.com/pkg/errors" 7 ) 8 9 func NewRegistry() *Registry { 10 return &Registry{make(map[reflect.Type]nameRegistry)} 11 } 12 13 type Registry struct { 14 typeToNameReg map[reflect.Type]nameRegistry 15 } 16 17 func newNameRegistry() nameRegistry { return make(nameRegistry) } 18 19 type nameRegistry map[string]nameRegistryEntry 20 21 type nameRegistryEntry struct { 22 constructor implConstructor 23 defaultConfig defaultConfigContainer 24 } 25 26 // Register registers plugin constructor and optional default config factory, 27 // for given plugin interface type and plugin name. 28 // See package doc for type expectations details. 29 // Register designed to be called in package init func, so it panics if something go wrong. 30 // Panics if type expectations are violated. 31 // Panics if some constructor have been already registered for this (pluginType, name) pair. 32 // Register is thread unsafe. 33 // 34 // If constructor receive config argument, default config factory can be 35 // registered. Default config factory type should be: is func() <configType>. 36 // Default config factory is optional. If no default config factory has been 37 // registered, than plugin factory will receive zero config (zero struct or 38 // pointer to zero struct). 39 // Registered constructor will never receive nil config, even there 40 // are no registered default config factory, or default config is nil. Config 41 // will be pointer to zero config in such case. 42 func (r *Registry) Register( 43 pluginType reflect.Type, 44 name string, 45 constructor interface{}, 46 defaultConfigOptional ...interface{}, // default config factory, or nothing. 47 ) { 48 expect(pluginType.Kind() == reflect.Interface, "plugin type should be interface, but have: %T", pluginType) 49 expect(name != "", "empty name") 50 nameReg := r.typeToNameReg[pluginType] 51 if nameReg == nil { 52 nameReg = newNameRegistry() 53 r.typeToNameReg[pluginType] = nameReg 54 } 55 _, ok := nameReg[name] 56 expect(!ok, "plugin %s with name %q had been already registered", pluginType, name) 57 defaultConfig := getNewDefaultConfig(defaultConfigOptional) 58 nameReg[name] = newNameRegistryEntry(pluginType, constructor, defaultConfig) 59 } 60 61 // Lookup returns true if any plugin constructor has been registered for given 62 // type. 63 func (r *Registry) Lookup(pluginType reflect.Type) bool { 64 _, ok := r.typeToNameReg[pluginType] 65 return ok 66 } 67 68 // LookupFactory returns true if factoryType looks like func() (SomeInterface[, error]) 69 // and any plugin constructor has been registered for SomeInterface. 70 // That is, you may create instance of this factoryType using this registry. 71 func (r *Registry) LookupFactory(factoryType reflect.Type) bool { 72 return isFactoryType(factoryType) && r.Lookup(factoryType.Out(0)) 73 } 74 75 // New creates plugin using registered plugin constructor. Returns error if creation 76 // failed or no plugin were registered for given type and name. 77 // Passed fillConf called on created config before calling plugin factory. 78 // fillConf argument is always valid struct pointer, even if plugin factory 79 // receives no config: fillConf is called on empty struct pointer in such case. 80 // fillConf error fails plugin creation. 81 // New is thread safe, if there is no concurrent Register calls. 82 func (r *Registry) New(pluginType reflect.Type, name string, fillConfOptional ...func(conf interface{}) error) (plugin interface{}, err error) { 83 expect(pluginType.Kind() == reflect.Interface, "plugin type should be interface, but have: %T", pluginType) 84 expect(name != "", "empty name") 85 fillConf := getFillConf(fillConfOptional) 86 registered, err := r.get(pluginType, name) 87 if err != nil { 88 return 89 } 90 conf, err := registered.defaultConfig.Get(fillConf) 91 if err != nil { 92 return nil, err 93 } 94 return registered.constructor.NewPlugin(conf) 95 } 96 97 // NewFactory behaves like New, but creates factory func() (PluginInterface[, error]), that on call 98 // creates New plugin by registered factory. 99 // If registered constructor is <newPlugin> config is created filled for every factory call, 100 // if <newFactory, that only once for factory creation. 101 func (r *Registry) NewFactory(factoryType reflect.Type, name string, fillConfOptional ...func(conf interface{}) error) (factory interface{}, err error) { 102 expect(isFactoryType(factoryType), "plugin factory type should be like `func() (PluginInterface, error)`, but have: %T", factoryType) 103 expect(name != "", "empty name") 104 fillConf := getFillConf(fillConfOptional) 105 pluginType := factoryType.Out(0) 106 registered, err := r.get(pluginType, name) 107 if err != nil { 108 return 109 } 110 var getMaybeConfig func() ([]reflect.Value, error) 111 if registered.defaultConfig.configRequired() { 112 getMaybeConfig = func() ([]reflect.Value, error) { 113 return registered.defaultConfig.Get(fillConf) 114 } 115 } else if fillConf != nil { 116 // Just check, that fillConf not fails, when there is no config fields. 117 err := fillConf(&struct{}{}) 118 if err != nil { 119 return nil, err 120 } 121 } 122 return registered.constructor.NewFactory(factoryType, getMaybeConfig) 123 } 124 125 func newNameRegistryEntry(pluginType reflect.Type, constructor interface{}, defaultConfig interface{}) nameRegistryEntry { 126 implConstructor := newImplConstructor(pluginType, constructor) 127 defaultConfigContainer := newDefaultConfigContainer(reflect.TypeOf(constructor), defaultConfig) 128 return nameRegistryEntry{implConstructor, defaultConfigContainer} 129 } 130 131 func (r *Registry) get(pluginType reflect.Type, name string) (factory nameRegistryEntry, err error) { 132 pluginReg, ok := r.typeToNameReg[pluginType] 133 if !ok { 134 err = errors.Errorf("no plugins for type %s has been registered", pluginType) 135 return 136 } 137 factory, ok = pluginReg[name] 138 if !ok { 139 err = errors.Errorf("no plugins of type %s has been registered for name %s", pluginType, name) 140 } 141 return 142 } 143 144 // defaultConfigContainer contains default config creation logic. 145 // Zero value is valid and means that no config is needed. 146 type defaultConfigContainer struct { 147 // !IsValid() if constructor accepts no arguments. 148 // Otherwise type is func() <configType>. 149 newValue reflect.Value 150 } 151 152 func newDefaultConfigContainer(constructorType reflect.Type, defaultConfig interface{}) defaultConfigContainer { 153 if constructorType.NumIn() == 0 { 154 expect(defaultConfig == nil, "constructor accept no config, but defaultConfig passed") 155 return defaultConfigContainer{} 156 } 157 expect(constructorType.NumIn() == 1, "constructor should accept zero or one argument") 158 configType := constructorType.In(0) 159 expect(configType.Kind() == reflect.Struct || 160 configType.Kind() == reflect.Ptr && configType.Elem().Kind() == reflect.Struct, 161 "unexpected config kind: %s; should be struct or struct pointer") 162 newDefaultConfigType := reflect.FuncOf(nil, []reflect.Type{configType}, false) 163 if defaultConfig == nil { 164 value := reflect.MakeFunc(newDefaultConfigType, 165 func(_ []reflect.Value) (results []reflect.Value) { 166 // OPTIMIZE: create addressable. 167 return []reflect.Value{reflect.Zero(configType)} 168 }) 169 return defaultConfigContainer{value} 170 } 171 value := reflect.ValueOf(defaultConfig) 172 expect(value.Type() == newDefaultConfigType, 173 "defaultConfig should be func that accepts nothing, and returns constructor argument, but have type %T", defaultConfig) 174 return defaultConfigContainer{value} 175 } 176 177 // In reflect pkg []Value used to call functions. It's easier to return it, that convert from pointer when needed. 178 func (e defaultConfigContainer) Get(fillConf func(fillAddr interface{}) error) (maybeConf []reflect.Value, err error) { 179 var fillAddr interface{} 180 if e.configRequired() { 181 maybeConf, fillAddr = e.new() 182 } else { 183 var emptyStruct struct{} 184 fillAddr = &emptyStruct // No fields to fill. 185 } 186 if fillConf != nil { 187 err = fillConf(fillAddr) 188 if err != nil { 189 return nil, err 190 } 191 } 192 return 193 } 194 195 func (e defaultConfigContainer) new() (maybeConf []reflect.Value, fillAddr interface{}) { 196 if !e.configRequired() { 197 panic("try to create config when not required") 198 } 199 conf := e.newValue.Call(nil)[0] 200 switch conf.Kind() { 201 case reflect.Struct: 202 // Config can be filled only by pointer. 203 if !conf.CanAddr() { 204 // Can't address to pass pointer into decoder. Let's make New addressable! 205 newArg := reflect.New(conf.Type()).Elem() 206 newArg.Set(conf) 207 conf = newArg 208 } 209 fillAddr = conf.Addr().Interface() 210 case reflect.Ptr: 211 if conf.IsNil() { 212 // Can't fill nil config. Init with zero. 213 conf = reflect.New(conf.Type().Elem()) 214 } 215 fillAddr = conf.Interface() 216 default: 217 panic("unexpected type " + conf.String()) 218 } 219 maybeConf = []reflect.Value{conf} 220 return 221 } 222 223 func (e defaultConfigContainer) configRequired() bool { 224 return e.newValue.IsValid() 225 } 226 227 func getFillConf(fillConfOptional []func(conf interface{}) error) func(interface{}) error { 228 expect(len(fillConfOptional) <= 1, "only fill config parameter could be passed") 229 if len(fillConfOptional) == 0 { 230 return nil 231 } 232 return fillConfOptional[0] 233 } 234 235 func getNewDefaultConfig(newDefaultConfigOptional []interface{}) interface{} { 236 expect(len(newDefaultConfigOptional) <= 1, "too many arguments passed") 237 if len(newDefaultConfigOptional) == 0 { 238 return nil 239 } 240 return newDefaultConfigOptional[0] 241 }