package modules import ( "fmt" "github.com/mitchellh/mapstructure" "go.uber.org/fx" "go.uber.org/zap" ) type ModuleConfiguration interface { Extract(destination any) error } var registry map[string]Module = map[string]Module{} func RegisterModule(module Module) { registry[module.Name()] = module } func GetModule(name string) Module { return registry[name] } type Module interface { Name() string Create(id string, moduleConfiguration map[string]interface{}) (fx.Option, error) } type ModuleFactoryContext interface { Id() string Kind() string NameTag() string GroupTag() string ConfigureLogger(logger *zap.Logger) *zap.Logger ExtractConfig(destination any) error AddOption(option fx.Option) Provide(constructors ...interface{}) Invoke(funcs ...interface{}) } type simpleFactoryContext struct { id string kind string config map[string]interface{} options []fx.Option } func (s *simpleFactoryContext) Kind() string { return s.kind } func (s *simpleFactoryContext) ConfigureLogger(logger *zap.Logger) *zap.Logger { return logger.Named(fmt.Sprintf("%s[%s]", s.Kind(), s.id)) } func (s *simpleFactoryContext) Provide(constructors ...interface{}) { s.AddOption(fx.Provide(constructors...)) } func (s *simpleFactoryContext) Invoke(funcs ...interface{}) { s.AddOption(fx.Invoke(funcs...)) } func (s *simpleFactoryContext) Id() string { return s.id } func (s *simpleFactoryContext) NameTag() string { return fmt.Sprintf(`name:"%s"`, s.id) } func (s *simpleFactoryContext) GroupTag() string { return fmt.Sprintf(`group:"%s"`, s.id) } func (s *simpleFactoryContext) ExtractConfig(destination any) error { return mapstructure.Decode(s.config, destination) } func (s *simpleFactoryContext) AddOption(option fx.Option) { s.options = append(s.options, option) } type simpleFactory = func(context ModuleFactoryContext) error type simple struct { name string factory simpleFactory } func (s simple) Name() string { return s.name } func (s simple) Create(id string, config map[string]interface{}) (fx.Option, error) { ctx := &simpleFactoryContext{ options: make([]fx.Option, 0), config: config, id: id, kind: s.name, } err := s.factory(ctx) if err != nil { return nil, err } return fx.Options(ctx.options...), nil } func SimpleModule(name string, factory simpleFactory) Module { module := &simple{name: name, factory: factory} RegisterModule(module) return module }