gitlab.com/gpdionisio/tendermint@v0.34.19-dev2/light/proxy/proxy.go (about) 1 package proxy 2 3 import ( 4 "context" 5 "fmt" 6 "net" 7 "net/http" 8 9 "github.com/tendermint/tendermint/libs/log" 10 tmpubsub "github.com/tendermint/tendermint/libs/pubsub" 11 "github.com/tendermint/tendermint/light" 12 lrpc "github.com/tendermint/tendermint/light/rpc" 13 rpchttp "github.com/tendermint/tendermint/rpc/client/http" 14 rpcserver "github.com/tendermint/tendermint/rpc/jsonrpc/server" 15 ) 16 17 // A Proxy defines parameters for running an HTTP server proxy. 18 type Proxy struct { 19 Addr string // TCP address to listen on, ":http" if empty 20 Config *rpcserver.Config 21 Client *lrpc.Client 22 Logger log.Logger 23 Listener net.Listener 24 } 25 26 // NewProxy creates the struct used to run an HTTP server for serving light 27 // client rpc requests. 28 func NewProxy( 29 lightClient *light.Client, 30 listenAddr, providerAddr string, 31 config *rpcserver.Config, 32 logger log.Logger, 33 opts ...lrpc.Option, 34 ) (*Proxy, error) { 35 rpcClient, err := rpchttp.NewWithTimeout(providerAddr, "/websocket", uint(config.WriteTimeout.Seconds())) 36 if err != nil { 37 return nil, fmt.Errorf("failed to create http client for %s: %w", providerAddr, err) 38 } 39 40 return &Proxy{ 41 Addr: listenAddr, 42 Config: config, 43 Client: lrpc.NewClient(rpcClient, lightClient, opts...), 44 Logger: logger, 45 }, nil 46 } 47 48 // ListenAndServe configures the rpcserver.WebsocketManager, sets up the RPC 49 // routes to proxy via Client, and starts up an HTTP server on the TCP network 50 // address p.Addr. 51 // See http#Server#ListenAndServe. 52 func (p *Proxy) ListenAndServe() error { 53 listener, mux, err := p.listen() 54 if err != nil { 55 return err 56 } 57 p.Listener = listener 58 59 return rpcserver.Serve( 60 listener, 61 mux, 62 p.Logger, 63 p.Config, 64 ) 65 } 66 67 // ListenAndServeTLS acts identically to ListenAndServe, except that it expects 68 // HTTPS connections. 69 // See http#Server#ListenAndServeTLS. 70 func (p *Proxy) ListenAndServeTLS(certFile, keyFile string) error { 71 listener, mux, err := p.listen() 72 if err != nil { 73 return err 74 } 75 p.Listener = listener 76 77 return rpcserver.ServeTLS( 78 listener, 79 mux, 80 certFile, 81 keyFile, 82 p.Logger, 83 p.Config, 84 ) 85 } 86 87 func (p *Proxy) listen() (net.Listener, *http.ServeMux, error) { 88 mux := http.NewServeMux() 89 90 // 1) Register regular routes. 91 r := RPCRoutes(p.Client) 92 rpcserver.RegisterRPCFuncs(mux, r, p.Logger) 93 94 // 2) Allow websocket connections. 95 wmLogger := p.Logger.With("protocol", "websocket") 96 wm := rpcserver.NewWebsocketManager(r, 97 rpcserver.OnDisconnect(func(remoteAddr string) { 98 err := p.Client.UnsubscribeAll(context.Background(), remoteAddr) 99 if err != nil && err != tmpubsub.ErrSubscriptionNotFound { 100 wmLogger.Error("Failed to unsubscribe addr from events", "addr", remoteAddr, "err", err) 101 } 102 }), 103 rpcserver.ReadLimit(p.Config.MaxBodyBytes), 104 ) 105 wm.SetLogger(wmLogger) 106 mux.HandleFunc("/websocket", wm.WebsocketHandler) 107 108 // 3) Start a client. 109 if !p.Client.IsRunning() { 110 if err := p.Client.Start(); err != nil { 111 return nil, mux, fmt.Errorf("can't start client: %w", err) 112 } 113 } 114 115 // 4) Start listening for new connections. 116 listener, err := rpcserver.Listen(p.Addr, p.Config) 117 if err != nil { 118 return nil, mux, err 119 } 120 121 return listener, mux, nil 122 }