github.com/cosmos/cosmos-sdk@v0.50.10/runtime/services/autocli.go (about) 1 package services 2 3 import ( 4 "context" 5 6 gogogrpc "github.com/cosmos/gogoproto/grpc" 7 "github.com/cosmos/gogoproto/proto" 8 "google.golang.org/grpc" 9 protobuf "google.golang.org/protobuf/proto" 10 "google.golang.org/protobuf/reflect/protoreflect" 11 "google.golang.org/protobuf/reflect/protoregistry" 12 13 autocliv1 "cosmossdk.io/api/cosmos/autocli/v1" 14 cosmosmsg "cosmossdk.io/api/cosmos/msg/v1" 15 "cosmossdk.io/core/appmodule" 16 17 "github.com/cosmos/cosmos-sdk/types/module" 18 ) 19 20 // AutoCLIQueryService implements the cosmos.autocli.v1.Query service. 21 type AutoCLIQueryService struct { 22 autocliv1.UnimplementedQueryServer 23 24 moduleOptions map[string]*autocliv1.ModuleOptions 25 } 26 27 // NewAutoCLIQueryService returns a AutoCLIQueryService for the provided modules. 28 func NewAutoCLIQueryService(appModules map[string]interface{}) *AutoCLIQueryService { 29 return &AutoCLIQueryService{ 30 moduleOptions: ExtractAutoCLIOptions(appModules), 31 } 32 } 33 34 // ExtractAutoCLIOptions extracts autocli ModuleOptions from the provided app modules. 35 // 36 // Example Usage: 37 // 38 // ExtractAutoCLIOptions(ModuleManager.Modules) 39 func ExtractAutoCLIOptions(appModules map[string]interface{}) map[string]*autocliv1.ModuleOptions { 40 moduleOptions := map[string]*autocliv1.ModuleOptions{} 41 for modName, mod := range appModules { 42 if autoCliMod, ok := mod.(interface { 43 AutoCLIOptions() *autocliv1.ModuleOptions 44 }); ok { 45 moduleOptions[modName] = autoCliMod.AutoCLIOptions() 46 continue 47 } 48 49 cfg := &autocliConfigurator{} 50 51 // try to auto-discover options based on the last msg and query 52 // services registered for the module 53 if mod, ok := mod.(module.HasServices); ok { 54 mod.RegisterServices(cfg) 55 } 56 57 if mod, ok := mod.(appmodule.HasServices); ok { 58 err := mod.RegisterServices(cfg) 59 if err != nil { 60 panic(err) 61 } 62 } 63 64 // check for errors in the configurator 65 if cfg.Error() != nil { 66 panic(cfg.Error()) 67 } 68 69 haveServices := false 70 modOptions := &autocliv1.ModuleOptions{} 71 if cfg.msgServer.serviceName != "" { 72 haveServices = true 73 modOptions.Tx = &autocliv1.ServiceCommandDescriptor{ 74 Service: cfg.msgServer.serviceName, 75 } 76 } 77 78 if cfg.queryServer.serviceName != "" { 79 haveServices = true 80 modOptions.Query = &autocliv1.ServiceCommandDescriptor{ 81 Service: cfg.queryServer.serviceName, 82 } 83 } 84 85 if haveServices { 86 moduleOptions[modName] = modOptions 87 } 88 } 89 return moduleOptions 90 } 91 92 func (a AutoCLIQueryService) AppOptions(context.Context, *autocliv1.AppOptionsRequest) (*autocliv1.AppOptionsResponse, error) { 93 return &autocliv1.AppOptionsResponse{ 94 ModuleOptions: a.moduleOptions, 95 }, nil 96 } 97 98 // autocliConfigurator allows us to call RegisterServices and introspect the services 99 type autocliConfigurator struct { 100 msgServer autocliServiceRegistrar 101 queryServer autocliServiceRegistrar 102 registryCache *protoregistry.Files 103 err error 104 } 105 106 var _ module.Configurator = &autocliConfigurator{} 107 108 func (a *autocliConfigurator) MsgServer() gogogrpc.Server { return &a.msgServer } 109 110 func (a *autocliConfigurator) QueryServer() gogogrpc.Server { return &a.queryServer } 111 112 func (a *autocliConfigurator) RegisterMigration(string, uint64, module.MigrationHandler) error { 113 return nil 114 } 115 116 func (a *autocliConfigurator) RegisterService(sd *grpc.ServiceDesc, ss interface{}) { 117 if a.registryCache == nil { 118 a.registryCache, a.err = proto.MergedRegistry() 119 } 120 121 desc, err := a.registryCache.FindDescriptorByName(protoreflect.FullName(sd.ServiceName)) 122 if err != nil { 123 a.err = err 124 return 125 } 126 127 if protobuf.HasExtension(desc.Options(), cosmosmsg.E_Service) { 128 a.msgServer.RegisterService(sd, ss) 129 } else { 130 a.queryServer.RegisterService(sd, ss) 131 } 132 } 133 func (a *autocliConfigurator) Error() error { return nil } 134 135 // autocliServiceRegistrar is used to capture the service name for registered services 136 type autocliServiceRegistrar struct { 137 serviceName string 138 } 139 140 func (a *autocliServiceRegistrar) RegisterService(sd *grpc.ServiceDesc, _ interface{}) { 141 a.serviceName = sd.ServiceName 142 } 143 144 var _ autocliv1.QueryServer = &AutoCLIQueryService{}