Skip to content

Commit

Permalink
refactor(depinject/appconfig): remove api module dependency (#20931)
Browse files Browse the repository at this point in the history
Co-authored-by: Marko <marko@baricevic.me>
Co-authored-by: Matt Kocubinski <mkocubinski@gmail.com>
  • Loading branch information
3 people authored Jul 18, 2024
1 parent 64b3ebf commit 2e0e6d8
Show file tree
Hide file tree
Showing 24 changed files with 2,539 additions and 66 deletions.
52 changes: 42 additions & 10 deletions depinject/appconfig/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,18 +10,28 @@ import (
"google.golang.org/protobuf/encoding/protojson"
protov2 "google.golang.org/protobuf/proto"
"google.golang.org/protobuf/reflect/protoreflect"
"google.golang.org/protobuf/types/dynamicpb"
"google.golang.org/protobuf/types/known/anypb"
"sigs.k8s.io/yaml"

appv1alpha1 "cosmossdk.io/api/cosmos/app/v1alpha1"
"cosmossdk.io/depinject"
"cosmossdk.io/depinject/appconfig/v1alpha1"
internal "cosmossdk.io/depinject/internal/appconfig"
)

// LoadJSON loads an app config in JSON format.
func LoadJSON(bz []byte) depinject.Config {
config := &appv1alpha1.Config{}
err := protojson.UnmarshalOptions{
// in order to avoid a direct dependency on api types, but in order to also be able to support
// either gogo or google.golang.org/protobuf types, we use protojson and dynamicpb to unmarshal
// from JSON
resolver := gogoproto.HybridResolver
desc, err := resolver.FindDescriptorByName(protoreflect.FullName(gogoproto.MessageName(&v1alpha1.Config{})))
if err != nil {
return depinject.Error(err)
}

config := dynamicpb.NewMessage(desc.(protoreflect.MessageDescriptor))
err = protojson.UnmarshalOptions{
Resolver: dynamicTypeResolver{resolver: gogoproto.HybridResolver},
}.Unmarshal(bz, config)
if err != nil {
Expand Down Expand Up @@ -51,9 +61,27 @@ func WrapAny(config protoreflect.ProtoMessage) *anypb.Any {
return cfg
}

// Compose composes a v1alpha1 app config into a container option by resolving
// the required modules and composing their options.
func Compose(appConfig *appv1alpha1.Config) depinject.Config {
// Compose composes an app config into a container option by resolving
// the required modules and composing their options. appConfig should be an instance
// of cosmos.app.v1alpha1.Config (it doesn't matter whether you use gogo proto or
// google.golang.org/protobuf types).
func Compose(appConfig gogoproto.Message) depinject.Config {
appConfigConcrete, ok := appConfig.(*v1alpha1.Config)
if !ok {
// we convert any other proto type that was passed (such as an api module type) to the concrete
// type we're using here
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),
}
Expand All @@ -63,7 +91,7 @@ func Compose(appConfig *appv1alpha1.Config) depinject.Config {
return depinject.Error(err)
}

for _, module := range appConfig.Modules {
for _, module := range appConfigConcrete.Modules {
if module.Name == "" {
return depinject.Error(fmt.Errorf("module is missing name"))
}
Expand All @@ -84,10 +112,14 @@ func Compose(appConfig *appv1alpha1.Config) depinject.Config {
init, ok := modules[msgName]
if !ok {
if msgDesc, err := gogoproto.HybridResolver.FindDescriptorByName(protoreflect.FullName(msgName)); err == nil {
modDesc := protov2.GetExtension(msgDesc.Options(), appv1alpha1.E_Module).(*appv1alpha1.ModuleDescriptor)
modDesc, err := internal.GetModuleDescriptor(msgDesc)
if err != nil {
return depinject.Error(err)
}

if modDesc == nil {
return depinject.Error(fmt.Errorf("no module registered for type URL %s and that protobuf type does not have the option %s\n\n%s",
module.Config.TypeUrl, appv1alpha1.E_Module.TypeDescriptor().FullName(), dumpRegisteredModules(modules)))
module.Config.TypeUrl, v1alpha1.E_Module.Name, dumpRegisteredModules(modules)))
}

return depinject.Error(fmt.Errorf("no module registered for type URL %s, did you forget to import %s: find more information on how to make a module ready for app wiring: https://docs.cosmos.network/main/building-modules/depinject\n\n%s",
Expand Down Expand Up @@ -122,7 +154,7 @@ func Compose(appConfig *appv1alpha1.Config) depinject.Config {
}
}

for _, binding := range appConfig.GolangBindings {
for _, binding := range appConfigConcrete.GolangBindings {
opts = append(opts, depinject.BindInterface(binding.InterfaceType, binding.Implementation))
}

Expand Down
Loading

0 comments on commit 2e0e6d8

Please sign in to comment.