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 }