github.com/franono/tendermint@v0.32.2-0.20200527150959-749313264ce9/lite/proxy/proxy.go (about) 1 package proxy 2 3 import ( 4 "context" 5 "net/http" 6 7 amino "github.com/tendermint/go-amino" 8 9 "github.com/franono/tendermint/libs/bytes" 10 "github.com/franono/tendermint/libs/log" 11 rpcclient "github.com/franono/tendermint/rpc/client" 12 ctypes "github.com/franono/tendermint/rpc/core/types" 13 rpcserver "github.com/franono/tendermint/rpc/jsonrpc/server" 14 rpctypes "github.com/franono/tendermint/rpc/jsonrpc/types" 15 "github.com/franono/tendermint/types" 16 ) 17 18 const ( 19 wsEndpoint = "/websocket" 20 ) 21 22 // StartProxy will start the websocket manager on the client, 23 // set up the rpc routes to proxy via the given client, 24 // and start up an http/rpc server on the location given by bind (eg. :1234) 25 // NOTE: This function blocks - you may want to call it in a go-routine. 26 func StartProxy(c rpcclient.Client, listenAddr string, logger log.Logger, maxOpenConnections int) error { 27 err := c.Start() 28 if err != nil { 29 return err 30 } 31 32 cdc := amino.NewCodec() 33 ctypes.RegisterAmino(cdc) 34 r := RPCRoutes(c) 35 36 // build the handler... 37 mux := http.NewServeMux() 38 rpcserver.RegisterRPCFuncs(mux, r, cdc, logger) 39 40 unsubscribeFromAllEvents := func(remoteAddr string) { 41 if err := c.UnsubscribeAll(context.Background(), remoteAddr); err != nil { 42 logger.Error("Failed to unsubscribe from events", "err", err) 43 } 44 } 45 wm := rpcserver.NewWebsocketManager(r, cdc, rpcserver.OnDisconnect(unsubscribeFromAllEvents)) 46 wm.SetLogger(logger) 47 // core.SetLogger(logger) 48 mux.HandleFunc(wsEndpoint, wm.WebsocketHandler) 49 50 config := rpcserver.DefaultConfig() 51 config.MaxOpenConnections = maxOpenConnections 52 l, err := rpcserver.Listen(listenAddr, config) 53 if err != nil { 54 return err 55 } 56 return rpcserver.Serve(l, mux, logger, config) 57 } 58 59 // RPCRoutes just routes everything to the given client, as if it were 60 // a tendermint fullnode. 61 // 62 // if we want security, the client must implement it as a secure client 63 func RPCRoutes(c rpcclient.Client) map[string]*rpcserver.RPCFunc { 64 return map[string]*rpcserver.RPCFunc{ 65 // Subscribe/unsubscribe are reserved for websocket events. 66 "subscribe": rpcserver.NewWSRPCFunc(c.(Wrapper).SubscribeWS, "query"), 67 "unsubscribe": rpcserver.NewWSRPCFunc(c.(Wrapper).UnsubscribeWS, "query"), 68 "unsubscribe_all": rpcserver.NewWSRPCFunc(c.(Wrapper).UnsubscribeAllWS, ""), 69 70 // info API 71 "status": rpcserver.NewRPCFunc(makeStatusFunc(c), ""), 72 "blockchain": rpcserver.NewRPCFunc(makeBlockchainInfoFunc(c), "minHeight,maxHeight"), 73 "genesis": rpcserver.NewRPCFunc(makeGenesisFunc(c), ""), 74 "block": rpcserver.NewRPCFunc(makeBlockFunc(c), "height"), 75 "commit": rpcserver.NewRPCFunc(makeCommitFunc(c), "height"), 76 "tx": rpcserver.NewRPCFunc(makeTxFunc(c), "hash,prove"), 77 "validators": rpcserver.NewRPCFunc(makeValidatorsFunc(c), "height"), 78 79 // broadcast API 80 "broadcast_tx_commit": rpcserver.NewRPCFunc(makeBroadcastTxCommitFunc(c), "tx"), 81 "broadcast_tx_sync": rpcserver.NewRPCFunc(makeBroadcastTxSyncFunc(c), "tx"), 82 "broadcast_tx_async": rpcserver.NewRPCFunc(makeBroadcastTxAsyncFunc(c), "tx"), 83 84 // abci API 85 "abci_query": rpcserver.NewRPCFunc(makeABCIQueryFunc(c), "path,data"), 86 "abci_info": rpcserver.NewRPCFunc(makeABCIInfoFunc(c), ""), 87 } 88 } 89 90 func makeStatusFunc(c rpcclient.StatusClient) func(ctx *rpctypes.Context) (*ctypes.ResultStatus, error) { 91 return func(ctx *rpctypes.Context) (*ctypes.ResultStatus, error) { 92 return c.Status() 93 } 94 } 95 96 func makeBlockchainInfoFunc(c rpcclient.Client) func( 97 ctx *rpctypes.Context, 98 minHeight, 99 maxHeight int64, 100 ) (*ctypes.ResultBlockchainInfo, error) { 101 return func(ctx *rpctypes.Context, minHeight, maxHeight int64) (*ctypes.ResultBlockchainInfo, error) { 102 return c.BlockchainInfo(minHeight, maxHeight) 103 } 104 } 105 106 func makeGenesisFunc(c rpcclient.Client) func(ctx *rpctypes.Context) (*ctypes.ResultGenesis, error) { 107 return func(ctx *rpctypes.Context) (*ctypes.ResultGenesis, error) { 108 return c.Genesis() 109 } 110 } 111 112 func makeBlockFunc(c rpcclient.Client) func(ctx *rpctypes.Context, height *int64) (*ctypes.ResultBlock, error) { 113 return func(ctx *rpctypes.Context, height *int64) (*ctypes.ResultBlock, error) { 114 return c.Block(height) 115 } 116 } 117 118 func makeCommitFunc(c rpcclient.Client) func(ctx *rpctypes.Context, height *int64) (*ctypes.ResultCommit, error) { 119 return func(ctx *rpctypes.Context, height *int64) (*ctypes.ResultCommit, error) { 120 return c.Commit(height) 121 } 122 } 123 124 func makeTxFunc(c rpcclient.Client) func(ctx *rpctypes.Context, hash []byte, prove bool) (*ctypes.ResultTx, error) { 125 return func(ctx *rpctypes.Context, hash []byte, prove bool) (*ctypes.ResultTx, error) { 126 return c.Tx(hash, prove) 127 } 128 } 129 130 func makeValidatorsFunc(c rpcclient.Client) func( 131 ctx *rpctypes.Context, 132 height *int64, 133 ) (*ctypes.ResultValidators, error) { 134 return func(ctx *rpctypes.Context, height *int64) (*ctypes.ResultValidators, error) { 135 return c.Validators(height, 0, 0) 136 } 137 } 138 139 func makeBroadcastTxCommitFunc(c rpcclient.Client) func( 140 ctx *rpctypes.Context, 141 tx types.Tx, 142 ) (*ctypes.ResultBroadcastTxCommit, error) { 143 return func(ctx *rpctypes.Context, tx types.Tx) (*ctypes.ResultBroadcastTxCommit, error) { 144 return c.BroadcastTxCommit(tx) 145 } 146 } 147 148 func makeBroadcastTxSyncFunc(c rpcclient.Client) func( 149 ctx *rpctypes.Context, 150 tx types.Tx, 151 ) (*ctypes.ResultBroadcastTx, error) { 152 return func(ctx *rpctypes.Context, tx types.Tx) (*ctypes.ResultBroadcastTx, error) { 153 return c.BroadcastTxSync(tx) 154 } 155 } 156 157 func makeBroadcastTxAsyncFunc(c rpcclient.Client) func( 158 ctx *rpctypes.Context, 159 tx types.Tx, 160 ) (*ctypes.ResultBroadcastTx, error) { 161 return func(ctx *rpctypes.Context, tx types.Tx) (*ctypes.ResultBroadcastTx, error) { 162 return c.BroadcastTxAsync(tx) 163 } 164 } 165 166 func makeABCIQueryFunc(c rpcclient.Client) func( 167 ctx *rpctypes.Context, 168 path string, 169 data bytes.HexBytes, 170 ) (*ctypes.ResultABCIQuery, error) { 171 return func(ctx *rpctypes.Context, path string, data bytes.HexBytes) (*ctypes.ResultABCIQuery, error) { 172 return c.ABCIQuery(path, data) 173 } 174 } 175 176 func makeABCIInfoFunc(c rpcclient.Client) func(ctx *rpctypes.Context) (*ctypes.ResultABCIInfo, error) { 177 return func(ctx *rpctypes.Context) (*ctypes.ResultABCIInfo, error) { 178 return c.ABCIInfo() 179 } 180 }