func Compose(appConfig gogoproto.Message) depinject.Config {
// Convert to concrete type if needed
appConfigConcrete, ok := appConfig.(*v1alpha1.Config)
if !ok {
appConfigConcrete = &v1alpha1.Config{}
bz, err := gogoproto.Marshal(appConfig)
if err != nil {
return depinject.Error(err)
}
err = gogoproto.Unmarshal(bz, appConfigConcrete)
if err != nil {
return depinject.Error(err)
}
}
opts := []depinject.Config{
depinject.Supply(appConfig),
}
modules, err := internal.ModulesByModuleTypeName()
if err != nil {
return depinject.Error(err)
}
// Process each module configuration
for _, module := range appConfigConcrete.Modules {
if module.Name == "" {
return depinject.Error(errors.New("module is missing name"))
}
if module.Config == nil {
return depinject.Error(
fmt.Errorf("module %q is missing a config object", module.Name)
)
}
msgName := module.Config.TypeUrl
// Strip type URL prefix
if slashIdx := strings.LastIndex(msgName, "/"); slashIdx >= 0 {
msgName = msgName[slashIdx+1:]
}
init, ok := modules[msgName]
if !ok {
// Module not found - provide helpful error
return depinject.Error(
fmt.Errorf("no module registered for type URL %s",
module.Config.TypeUrl)
)
}
// Unmarshal module config
var config gogoproto.Message
if configInit, ok := init.ConfigProtoMessage.(protov2.Message); ok {
config = configInit.ProtoReflect().Type().New().Interface().(gogoproto.Message)
} else {
config = reflect.New(init.ConfigGoType.Elem()).Interface().(gogoproto.Message)
}
err = gogoproto.Unmarshal(module.Config.Value, config)
if err != nil {
return depinject.Error(err)
}
// Supply module config
opts = append(opts, depinject.Supply(config))
// Register module providers
for _, provider := range init.Providers {
opts = append(opts, depinject.ProvideInModule(module.Name, provider))
}
// Register module invokers
for _, invoker := range init.Invokers {
opts = append(opts, depinject.InvokeInModule(module.Name, invoker))
}
// Register interface bindings
for _, binding := range module.GolangBindings {
opts = append(opts,
depinject.BindInterfaceInModule(
module.Name,
binding.InterfaceType,
binding.Implementation,
)
)
}
}
// Register global interface bindings
for _, binding := range appConfigConcrete.GolangBindings {
opts = append(opts,
depinject.BindInterface(
binding.InterfaceType,
binding.Implementation,
)
)
}
return depinject.Configs(opts...)
}