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  }