github.com/fibonacci-chain/fbc@v0.0.0-20231124064014-c7636198c1e9/libs/cosmos-sdk/client/lcd/root.go (about) 1 package lcd 2 3 import ( 4 "fmt" 5 grpctypes "github.com/fibonacci-chain/fbc/libs/cosmos-sdk/types/grpc" 6 "github.com/gogo/gateway" 7 "github.com/gogo/protobuf/jsonpb" 8 "github.com/grpc-ecosystem/grpc-gateway/runtime" 9 "net" 10 "net/http" 11 "os" 12 "strings" 13 "time" 14 15 "github.com/fibonacci-chain/fbc/libs/tendermint/libs/log" 16 "github.com/fibonacci-chain/fbc/libs/tendermint/node" 17 "github.com/fibonacci-chain/fbc/libs/tendermint/rpc/client/local" 18 tmrpcserver "github.com/fibonacci-chain/fbc/libs/tendermint/rpc/jsonrpc/server" 19 "github.com/gorilla/handlers" 20 "github.com/gorilla/mux" 21 "github.com/rakyll/statik/fs" 22 "github.com/spf13/cobra" 23 "github.com/spf13/viper" 24 25 "github.com/fibonacci-chain/fbc/libs/cosmos-sdk/client/context" 26 "github.com/fibonacci-chain/fbc/libs/cosmos-sdk/client/flags" 27 "github.com/fibonacci-chain/fbc/libs/cosmos-sdk/codec" 28 keybase "github.com/fibonacci-chain/fbc/libs/cosmos-sdk/crypto/keys" 29 30 // unnamed import of statik for swagger UI support 31 _ "github.com/fibonacci-chain/fbc/libs/cosmos-sdk/client/lcd/statik" 32 ) 33 34 // RestServer represents the Light Client Rest server 35 type RestServer struct { 36 Mux *mux.Router 37 CliCtx context.CLIContext 38 KeyBase keybase.Keybase 39 Cdc *codec.CodecProxy 40 41 log log.Logger 42 listener net.Listener 43 44 GRPCGatewayRouter *runtime.ServeMux 45 } 46 47 // CustomGRPCHeaderMatcher for mapping request headers to 48 // GRPC metadata. 49 // HTTP headers that start with 'Grpc-Metadata-' are automatically mapped to 50 // gRPC metadata after removing prefix 'Grpc-Metadata-'. We can use this 51 // CustomGRPCHeaderMatcher if headers don't start with `Grpc-Metadata-` 52 func CustomGRPCHeaderMatcher(key string) (string, bool) { 53 switch strings.ToLower(key) { 54 case grpctypes.GRPCBlockHeightHeader: 55 return grpctypes.GRPCBlockHeightHeader, true 56 default: 57 return runtime.DefaultHeaderMatcher(key) 58 } 59 } 60 61 // NewRestServer creates a new rest server instance 62 func NewRestServer(cdc *codec.CodecProxy, interfaceReg jsonpb.AnyResolver, tmNode *node.Node) *RestServer { 63 rootRouter := mux.NewRouter() 64 cliCtx := context.NewCLIContext().WithProxy(cdc) 65 logger := log.NewTMLogger(log.NewSyncWriter(os.Stdout)).With("module", "rest-server") 66 if tmNode != nil { 67 cliCtx = cliCtx.WithChainID(tmNode.ConsensusState().GetState().ChainID) 68 cliCtx.Client = local.New(tmNode) 69 logger = tmNode.Logger.With("module", "rest-server") 70 } else { 71 cliCtx = cliCtx.WithChainID(viper.GetString(flags.FlagChainID)) 72 } 73 74 cliCtx.TrustNode = true 75 76 marshalerOption := NewJSONMarshalAdapter(&gateway.JSONPb{ 77 EmitDefaults: true, 78 Indent: " ", 79 OrigName: true, 80 AnyResolver: interfaceReg, 81 }, cdc) 82 83 return &RestServer{ 84 Mux: rootRouter, 85 CliCtx: cliCtx, 86 Cdc: cdc, 87 88 log: logger, 89 GRPCGatewayRouter: runtime.NewServeMux( 90 // Custom marshaler option is required for gogo proto 91 runtime.WithMarshalerOption(runtime.MIMEWildcard, marshalerOption), 92 93 // This is necessary to get error details properly 94 // marshalled in unary requests. 95 runtime.WithProtoErrorHandler(runtime.DefaultHTTPProtoErrorHandler), 96 97 // Custom header matcher for mapping request headers to 98 // GRPC metadata 99 runtime.WithIncomingHeaderMatcher(CustomGRPCHeaderMatcher), 100 ), 101 } 102 } 103 104 func (rs *RestServer) Logger() log.Logger { 105 return rs.log 106 } 107 108 // Start starts the rest server 109 func (rs *RestServer) Start(listenAddr string, maxOpen int, readTimeout, writeTimeout uint, cors bool) (err error) { 110 //trapSignal(func() { 111 // err := rs.listener.Close() 112 // rs.log.Error("error closing listener", "err", err) 113 //}) 114 115 cfg := tmrpcserver.DefaultConfig() 116 cfg.MaxOpenConnections = maxOpen 117 cfg.ReadTimeout = time.Duration(readTimeout) * time.Second 118 cfg.WriteTimeout = time.Duration(writeTimeout) * time.Second 119 120 rs.listener, err = tmrpcserver.Listen(listenAddr, cfg) 121 if err != nil { 122 return 123 } 124 125 rs.registerGRPCGatewayRoutes() 126 127 rs.log.Info( 128 fmt.Sprintf( 129 "Starting application REST service (chain-id: %q)...", 130 viper.GetString(flags.FlagChainID), 131 ), 132 ) 133 134 var h http.Handler = rs.Mux 135 if cors { 136 allowAllCORS := handlers.CORS(handlers.AllowedHeaders([]string{"Content-Type"})) 137 h = allowAllCORS(h) 138 } 139 140 return tmrpcserver.Serve(rs.listener, h, rs.log, cfg) 141 } 142 143 func (s *RestServer) registerGRPCGatewayRoutes() { 144 s.Mux.PathPrefix("/").Handler(s.GRPCGatewayRouter) 145 } 146 147 // ServeCommand will start the application REST service as a blocking process. It 148 // takes a codec to create a RestServer object and a function to register all 149 // necessary routes. 150 func ServeCommand(cdc *codec.CodecProxy, interfaceReg jsonpb.AnyResolver, registerRoutesFn func(*RestServer)) *cobra.Command { 151 cmd := &cobra.Command{ 152 Use: "rest-server", 153 Short: "Start LCD (light-client daemon), a local REST server", 154 RunE: func(cmd *cobra.Command, args []string) (err error) { 155 rs := NewRestServer(cdc, interfaceReg, nil) 156 157 registerRoutesFn(rs) 158 //rs.registerSwaggerUI() 159 160 // Start the rest server and return error if one exists 161 err = rs.Start( 162 viper.GetString(flags.FlagListenAddr), 163 viper.GetInt(flags.FlagMaxOpenConnections), 164 uint(viper.GetInt(flags.FlagRPCReadTimeout)), 165 uint(viper.GetInt(flags.FlagRPCWriteTimeout)), 166 viper.GetBool(flags.FlagUnsafeCORS), 167 ) 168 169 return err 170 }, 171 } 172 173 return flags.RegisterRestServerFlags(cmd) 174 } 175 176 func StartRestServer(cdc *codec.CodecProxy, interfaceReg jsonpb.AnyResolver, registerRoutesFn func(*RestServer), tmNode *node.Node, addr string) error { 177 rs := NewRestServer(cdc, interfaceReg, tmNode) 178 179 registerRoutesFn(rs) 180 //rs.registerSwaggerUI() 181 rs.log.Info("start rest server") 182 // Start the rest server and return error if one exists 183 return rs.Start( 184 addr, 185 viper.GetInt(flags.FlagMaxOpenConnections), 186 uint(viper.GetInt(flags.FlagRPCReadTimeout)), 187 uint(viper.GetInt(flags.FlagRPCWriteTimeout)), 188 viper.GetBool(flags.FlagUnsafeCORS), 189 ) 190 } 191 192 func (rs *RestServer) registerSwaggerUI() { 193 statikFS, err := fs.New() 194 if err != nil { 195 panic(err) 196 } 197 staticServer := http.FileServer(statikFS) 198 rs.Mux.PathPrefix("/swagger-ui/").Handler(http.StripPrefix("/swagger-ui/", staticServer)) 199 }