github.com/ari-anchor/sei-tendermint@v0.0.0-20230519144642-dc826b7b56bb/internal/inspect/rpc/rpc.go (about)

     1  package rpc
     2  
     3  import (
     4  	"context"
     5  	"net/http"
     6  	"time"
     7  
     8  	"github.com/rs/cors"
     9  
    10  	"github.com/ari-anchor/sei-tendermint/config"
    11  	"github.com/ari-anchor/sei-tendermint/internal/pubsub"
    12  	"github.com/ari-anchor/sei-tendermint/internal/rpc/core"
    13  	"github.com/ari-anchor/sei-tendermint/internal/state"
    14  	"github.com/ari-anchor/sei-tendermint/internal/state/indexer"
    15  	"github.com/ari-anchor/sei-tendermint/libs/log"
    16  	"github.com/ari-anchor/sei-tendermint/rpc/jsonrpc/server"
    17  )
    18  
    19  // Server defines parameters for running an Inspector rpc server.
    20  type Server struct {
    21  	Addr    string // TCP address to listen on, ":http" if empty
    22  	Handler http.Handler
    23  	Logger  log.Logger
    24  	Config  *config.RPCConfig
    25  }
    26  
    27  type eventBusUnsubscriber interface {
    28  	UnsubscribeAll(ctx context.Context, subscriber string) error
    29  }
    30  
    31  // Routes returns the set of routes used by the Inspector server.
    32  func Routes(cfg config.RPCConfig, s state.Store, bs state.BlockStore, es []indexer.EventSink, logger log.Logger) core.RoutesMap {
    33  	env := &core.Environment{
    34  		Config:     cfg,
    35  		EventSinks: es,
    36  		StateStore: s,
    37  		BlockStore: bs,
    38  		Logger:     logger,
    39  	}
    40  	return core.RoutesMap{
    41  		"blockchain":       server.NewRPCFunc(env.BlockchainInfo),
    42  		"consensus_params": server.NewRPCFunc(env.ConsensusParams),
    43  		"block":            server.NewRPCFunc(env.Block),
    44  		"block_by_hash":    server.NewRPCFunc(env.BlockByHash),
    45  		"block_results":    server.NewRPCFunc(env.BlockResults),
    46  		"commit":           server.NewRPCFunc(env.Commit),
    47  		"validators":       server.NewRPCFunc(env.Validators),
    48  		"tx":               server.NewRPCFunc(env.Tx),
    49  		"tx_search":        server.NewRPCFunc(env.TxSearch),
    50  		"block_search":     server.NewRPCFunc(env.BlockSearch),
    51  	}
    52  }
    53  
    54  // Handler returns the http.Handler configured for use with an Inspector server. Handler
    55  // registers the routes on the http.Handler and also registers the websocket handler
    56  // and the CORS handler if specified by the configuration options.
    57  func Handler(rpcConfig *config.RPCConfig, routes core.RoutesMap, logger log.Logger) http.Handler {
    58  	mux := http.NewServeMux()
    59  	wmLogger := logger.With("protocol", "websocket")
    60  
    61  	var eventBus eventBusUnsubscriber
    62  
    63  	websocketDisconnectFn := func(remoteAddr string) {
    64  		err := eventBus.UnsubscribeAll(context.Background(), remoteAddr)
    65  		if err != nil && err != pubsub.ErrSubscriptionNotFound {
    66  			wmLogger.Error("Failed to unsubscribe addr from events", "addr", remoteAddr, "err", err)
    67  		}
    68  	}
    69  	wm := server.NewWebsocketManager(logger, routes,
    70  		server.OnDisconnect(websocketDisconnectFn),
    71  		server.ReadLimit(rpcConfig.MaxBodyBytes))
    72  	mux.HandleFunc("/websocket", wm.WebsocketHandler)
    73  
    74  	server.RegisterRPCFuncs(mux, routes, logger)
    75  	var rootHandler http.Handler = mux
    76  	if rpcConfig.IsCorsEnabled() {
    77  		rootHandler = addCORSHandler(rpcConfig, mux)
    78  	}
    79  	return rootHandler
    80  }
    81  
    82  func addCORSHandler(rpcConfig *config.RPCConfig, h http.Handler) http.Handler {
    83  	corsMiddleware := cors.New(cors.Options{
    84  		AllowedOrigins: rpcConfig.CORSAllowedOrigins,
    85  		AllowedMethods: rpcConfig.CORSAllowedMethods,
    86  		AllowedHeaders: rpcConfig.CORSAllowedHeaders,
    87  	})
    88  	h = corsMiddleware.Handler(h)
    89  	return h
    90  }
    91  
    92  // ListenAndServe listens on the address specified in srv.Addr and handles any
    93  // incoming requests over HTTP using the Inspector rpc handler specified on the server.
    94  func (srv *Server) ListenAndServe(ctx context.Context) error {
    95  	listener, err := server.Listen(srv.Addr, srv.Config.MaxOpenConnections)
    96  	if err != nil {
    97  		return err
    98  	}
    99  	go func() {
   100  		<-ctx.Done()
   101  		listener.Close()
   102  	}()
   103  
   104  	return server.Serve(ctx, listener, srv.Handler, srv.Logger, serverRPCConfig(srv.Config))
   105  }
   106  
   107  // ListenAndServeTLS listens on the address specified in srv.Addr. ListenAndServeTLS handles
   108  // incoming requests over HTTPS using the Inspector rpc handler specified on the server.
   109  func (srv *Server) ListenAndServeTLS(ctx context.Context, certFile, keyFile string) error {
   110  	listener, err := server.Listen(srv.Addr, srv.Config.MaxOpenConnections)
   111  	if err != nil {
   112  		return err
   113  	}
   114  	go func() {
   115  		<-ctx.Done()
   116  		listener.Close()
   117  	}()
   118  	return server.ServeTLS(ctx, listener, srv.Handler, certFile, keyFile, srv.Logger, serverRPCConfig(srv.Config))
   119  }
   120  
   121  func serverRPCConfig(r *config.RPCConfig) *server.Config {
   122  	cfg := server.DefaultConfig()
   123  	cfg.MaxBodyBytes = r.MaxBodyBytes
   124  	cfg.MaxHeaderBytes = r.MaxHeaderBytes
   125  	// If necessary adjust global WriteTimeout to ensure it's greater than
   126  	// TimeoutBroadcastTxCommit.
   127  	// See https://github.com/ari-anchor/sei-tendermint/issues/3435
   128  	// Note we don't need to adjust anything if the timeout is already unlimited.
   129  	if cfg.WriteTimeout > 0 && cfg.WriteTimeout <= r.TimeoutBroadcastTxCommit {
   130  		cfg.WriteTimeout = r.TimeoutBroadcastTxCommit + 1*time.Second
   131  	}
   132  	return cfg
   133  }