github.com/soomindae/tendermint@v0.0.5-0.20210528140126-84a0c70c8162/rpc/client/http/http.go (about) 1 package http 2 3 import ( 4 "context" 5 "errors" 6 "net/http" 7 "strings" 8 "time" 9 10 "github.com/soomindae/tendermint/libs/bytes" 11 tmjson "github.com/soomindae/tendermint/libs/json" 12 "github.com/soomindae/tendermint/libs/log" 13 tmpubsub "github.com/soomindae/tendermint/libs/pubsub" 14 "github.com/soomindae/tendermint/libs/service" 15 tmsync "github.com/soomindae/tendermint/libs/sync" 16 rpcclient "github.com/soomindae/tendermint/rpc/client" 17 ctypes "github.com/soomindae/tendermint/rpc/core/types" 18 jsonrpcclient "github.com/soomindae/tendermint/rpc/jsonrpc/client" 19 "github.com/soomindae/tendermint/types" 20 ) 21 22 /* 23 HTTP is a Client implementation that communicates with a Tendermint node over 24 JSON RPC and WebSockets. 25 26 This is the main implementation you probably want to use in production code. 27 There are other implementations when calling the Tendermint node in-process 28 (Local), or when you want to mock out the server for test code (mock). 29 30 You can subscribe for any event published by Tendermint using Subscribe method. 31 Note delivery is best-effort. If you don't read events fast enough or network is 32 slow, Tendermint might cancel the subscription. The client will attempt to 33 resubscribe (you don't need to do anything). It will keep trying every second 34 indefinitely until successful. 35 36 Request batching is available for JSON RPC requests over HTTP, which conforms to 37 the JSON RPC specification (https://www.jsonrpc.org/specification#batch). See 38 the example for more details. 39 40 Example: 41 42 c, err := New("http://192.168.1.10:26657", "/websocket") 43 if err != nil { 44 // handle error 45 } 46 47 // call Start/Stop if you're subscribing to events 48 err = c.Start() 49 if err != nil { 50 // handle error 51 } 52 defer c.Stop() 53 54 res, err := c.Status() 55 if err != nil { 56 // handle error 57 } 58 59 // handle result 60 */ 61 type HTTP struct { 62 remote string 63 rpc *jsonrpcclient.Client 64 65 *baseRPCClient 66 *WSEvents 67 } 68 69 // BatchHTTP provides the same interface as `HTTP`, but allows for batching of 70 // requests (as per https://www.jsonrpc.org/specification#batch). Do not 71 // instantiate directly - rather use the HTTP.NewBatch() method to create an 72 // instance of this struct. 73 // 74 // Batching of HTTP requests is thread-safe in the sense that multiple 75 // goroutines can each create their own batches and send them using the same 76 // HTTP client. Multiple goroutines could also enqueue transactions in a single 77 // batch, but ordering of transactions in the batch cannot be guaranteed in such 78 // an example. 79 type BatchHTTP struct { 80 rpcBatch *jsonrpcclient.RequestBatch 81 *baseRPCClient 82 } 83 84 // rpcClient is an internal interface to which our RPC clients (batch and 85 // non-batch) must conform. Acts as an additional code-level sanity check to 86 // make sure the implementations stay coherent. 87 type rpcClient interface { 88 rpcclient.ABCIClient 89 rpcclient.HistoryClient 90 rpcclient.NetworkClient 91 rpcclient.SignClient 92 rpcclient.StatusClient 93 } 94 95 // baseRPCClient implements the basic RPC method logic without the actual 96 // underlying RPC call functionality, which is provided by `caller`. 97 type baseRPCClient struct { 98 caller jsonrpcclient.Caller 99 } 100 101 var _ rpcClient = (*HTTP)(nil) 102 var _ rpcClient = (*BatchHTTP)(nil) 103 var _ rpcClient = (*baseRPCClient)(nil) 104 105 //----------------------------------------------------------------------------- 106 // HTTP 107 108 // New takes a remote endpoint in the form <protocol>://<host>:<port> and 109 // the websocket path (which always seems to be "/websocket") 110 // An error is returned on invalid remote. The function panics when remote is nil. 111 func New(remote, wsEndpoint string) (*HTTP, error) { 112 httpClient, err := jsonrpcclient.DefaultHTTPClient(remote) 113 if err != nil { 114 return nil, err 115 } 116 return NewWithClient(remote, wsEndpoint, httpClient) 117 } 118 119 // Create timeout enabled http client 120 func NewWithTimeout(remote, wsEndpoint string, timeout uint) (*HTTP, error) { 121 httpClient, err := jsonrpcclient.DefaultHTTPClient(remote) 122 if err != nil { 123 return nil, err 124 } 125 httpClient.Timeout = time.Duration(timeout) * time.Second 126 return NewWithClient(remote, wsEndpoint, httpClient) 127 } 128 129 // NewWithClient allows for setting a custom http client (See New). 130 // An error is returned on invalid remote. The function panics when remote is nil. 131 func NewWithClient(remote, wsEndpoint string, client *http.Client) (*HTTP, error) { 132 if client == nil { 133 panic("nil http.Client provided") 134 } 135 136 rc, err := jsonrpcclient.NewWithHTTPClient(remote, client) 137 if err != nil { 138 return nil, err 139 } 140 141 wsEvents, err := newWSEvents(remote, wsEndpoint) 142 if err != nil { 143 return nil, err 144 } 145 146 httpClient := &HTTP{ 147 rpc: rc, 148 remote: remote, 149 baseRPCClient: &baseRPCClient{caller: rc}, 150 WSEvents: wsEvents, 151 } 152 153 return httpClient, nil 154 } 155 156 var _ rpcclient.Client = (*HTTP)(nil) 157 158 // SetLogger sets a logger. 159 func (c *HTTP) SetLogger(l log.Logger) { 160 c.WSEvents.SetLogger(l) 161 } 162 163 // Remote returns the remote network address in a string form. 164 func (c *HTTP) Remote() string { 165 return c.remote 166 } 167 168 // NewBatch creates a new batch client for this HTTP client. 169 func (c *HTTP) NewBatch() *BatchHTTP { 170 rpcBatch := c.rpc.NewRequestBatch() 171 return &BatchHTTP{ 172 rpcBatch: rpcBatch, 173 baseRPCClient: &baseRPCClient{ 174 caller: rpcBatch, 175 }, 176 } 177 } 178 179 //----------------------------------------------------------------------------- 180 // BatchHTTP 181 182 // Send is a convenience function for an HTTP batch that will trigger the 183 // compilation of the batched requests and send them off using the client as a 184 // single request. On success, this returns a list of the deserialized results 185 // from each request in the sent batch. 186 func (b *BatchHTTP) Send(ctx context.Context) ([]interface{}, error) { 187 return b.rpcBatch.Send(ctx) 188 } 189 190 // Clear will empty out this batch of requests and return the number of requests 191 // that were cleared out. 192 func (b *BatchHTTP) Clear() int { 193 return b.rpcBatch.Clear() 194 } 195 196 // Count returns the number of enqueued requests waiting to be sent. 197 func (b *BatchHTTP) Count() int { 198 return b.rpcBatch.Count() 199 } 200 201 //----------------------------------------------------------------------------- 202 // baseRPCClient 203 204 func (c *baseRPCClient) Status(ctx context.Context) (*ctypes.ResultStatus, error) { 205 result := new(ctypes.ResultStatus) 206 _, err := c.caller.Call(ctx, "status", map[string]interface{}{}, result) 207 if err != nil { 208 return nil, err 209 } 210 211 return result, nil 212 } 213 214 func (c *baseRPCClient) ABCIInfo(ctx context.Context) (*ctypes.ResultABCIInfo, error) { 215 result := new(ctypes.ResultABCIInfo) 216 _, err := c.caller.Call(ctx, "abci_info", map[string]interface{}{}, result) 217 if err != nil { 218 return nil, err 219 } 220 221 return result, nil 222 } 223 224 func (c *baseRPCClient) ABCIQuery( 225 ctx context.Context, 226 path string, 227 data bytes.HexBytes, 228 ) (*ctypes.ResultABCIQuery, error) { 229 return c.ABCIQueryWithOptions(ctx, path, data, rpcclient.DefaultABCIQueryOptions) 230 } 231 232 func (c *baseRPCClient) ABCIQueryWithOptions( 233 ctx context.Context, 234 path string, 235 data bytes.HexBytes, 236 opts rpcclient.ABCIQueryOptions) (*ctypes.ResultABCIQuery, error) { 237 result := new(ctypes.ResultABCIQuery) 238 _, err := c.caller.Call(ctx, "abci_query", 239 map[string]interface{}{"path": path, "data": data, "height": opts.Height, "prove": opts.Prove}, 240 result) 241 if err != nil { 242 return nil, err 243 } 244 245 return result, nil 246 } 247 248 func (c *baseRPCClient) BroadcastTxCommit( 249 ctx context.Context, 250 tx types.Tx, 251 ) (*ctypes.ResultBroadcastTxCommit, error) { 252 result := new(ctypes.ResultBroadcastTxCommit) 253 _, err := c.caller.Call(ctx, "broadcast_tx_commit", map[string]interface{}{"tx": tx}, result) 254 if err != nil { 255 return nil, err 256 } 257 return result, nil 258 } 259 260 func (c *baseRPCClient) BroadcastTxAsync( 261 ctx context.Context, 262 tx types.Tx, 263 ) (*ctypes.ResultBroadcastTx, error) { 264 return c.broadcastTX(ctx, "broadcast_tx_async", tx) 265 } 266 267 func (c *baseRPCClient) BroadcastTxSync( 268 ctx context.Context, 269 tx types.Tx, 270 ) (*ctypes.ResultBroadcastTx, error) { 271 return c.broadcastTX(ctx, "broadcast_tx_sync", tx) 272 } 273 274 func (c *baseRPCClient) broadcastTX( 275 ctx context.Context, 276 route string, 277 tx types.Tx, 278 ) (*ctypes.ResultBroadcastTx, error) { 279 result := new(ctypes.ResultBroadcastTx) 280 _, err := c.caller.Call(ctx, route, map[string]interface{}{"tx": tx}, result) 281 if err != nil { 282 return nil, err 283 } 284 return result, nil 285 } 286 287 func (c *baseRPCClient) UnconfirmedTxs( 288 ctx context.Context, 289 limit *int, 290 ) (*ctypes.ResultUnconfirmedTxs, error) { 291 result := new(ctypes.ResultUnconfirmedTxs) 292 params := make(map[string]interface{}) 293 if limit != nil { 294 params["limit"] = limit 295 } 296 _, err := c.caller.Call(ctx, "unconfirmed_txs", params, result) 297 if err != nil { 298 return nil, err 299 } 300 return result, nil 301 } 302 303 func (c *baseRPCClient) NumUnconfirmedTxs(ctx context.Context) (*ctypes.ResultUnconfirmedTxs, error) { 304 result := new(ctypes.ResultUnconfirmedTxs) 305 _, err := c.caller.Call(ctx, "num_unconfirmed_txs", map[string]interface{}{}, result) 306 if err != nil { 307 return nil, err 308 } 309 return result, nil 310 } 311 312 func (c *baseRPCClient) CheckTx(ctx context.Context, tx types.Tx) (*ctypes.ResultCheckTx, error) { 313 result := new(ctypes.ResultCheckTx) 314 _, err := c.caller.Call(ctx, "check_tx", map[string]interface{}{"tx": tx}, result) 315 if err != nil { 316 return nil, err 317 } 318 return result, nil 319 } 320 321 func (c *baseRPCClient) NetInfo(ctx context.Context) (*ctypes.ResultNetInfo, error) { 322 result := new(ctypes.ResultNetInfo) 323 _, err := c.caller.Call(ctx, "net_info", map[string]interface{}{}, result) 324 if err != nil { 325 return nil, err 326 } 327 return result, nil 328 } 329 330 func (c *baseRPCClient) DumpConsensusState(ctx context.Context) (*ctypes.ResultDumpConsensusState, error) { 331 result := new(ctypes.ResultDumpConsensusState) 332 _, err := c.caller.Call(ctx, "dump_consensus_state", map[string]interface{}{}, result) 333 if err != nil { 334 return nil, err 335 } 336 return result, nil 337 } 338 339 func (c *baseRPCClient) ConsensusState(ctx context.Context) (*ctypes.ResultConsensusState, error) { 340 result := new(ctypes.ResultConsensusState) 341 _, err := c.caller.Call(ctx, "consensus_state", map[string]interface{}{}, result) 342 if err != nil { 343 return nil, err 344 } 345 return result, nil 346 } 347 348 func (c *baseRPCClient) ConsensusParams( 349 ctx context.Context, 350 height *int64, 351 ) (*ctypes.ResultConsensusParams, error) { 352 result := new(ctypes.ResultConsensusParams) 353 params := make(map[string]interface{}) 354 if height != nil { 355 params["height"] = height 356 } 357 _, err := c.caller.Call(ctx, "consensus_params", params, result) 358 if err != nil { 359 return nil, err 360 } 361 return result, nil 362 } 363 364 func (c *baseRPCClient) Health(ctx context.Context) (*ctypes.ResultHealth, error) { 365 result := new(ctypes.ResultHealth) 366 _, err := c.caller.Call(ctx, "health", map[string]interface{}{}, result) 367 if err != nil { 368 return nil, err 369 } 370 return result, nil 371 } 372 373 func (c *baseRPCClient) BlockchainInfo( 374 ctx context.Context, 375 minHeight, 376 maxHeight int64, 377 ) (*ctypes.ResultBlockchainInfo, error) { 378 result := new(ctypes.ResultBlockchainInfo) 379 _, err := c.caller.Call(ctx, "blockchain", 380 map[string]interface{}{"minHeight": minHeight, "maxHeight": maxHeight}, 381 result) 382 if err != nil { 383 return nil, err 384 } 385 return result, nil 386 } 387 388 func (c *baseRPCClient) Genesis(ctx context.Context) (*ctypes.ResultGenesis, error) { 389 result := new(ctypes.ResultGenesis) 390 _, err := c.caller.Call(ctx, "genesis", map[string]interface{}{}, result) 391 if err != nil { 392 return nil, err 393 } 394 return result, nil 395 } 396 397 func (c *baseRPCClient) Block(ctx context.Context, height *int64) (*ctypes.ResultBlock, error) { 398 result := new(ctypes.ResultBlock) 399 params := make(map[string]interface{}) 400 if height != nil { 401 params["height"] = height 402 } 403 _, err := c.caller.Call(ctx, "block", params, result) 404 if err != nil { 405 return nil, err 406 } 407 return result, nil 408 } 409 410 func (c *baseRPCClient) BlockByHash(ctx context.Context, hash []byte) (*ctypes.ResultBlock, error) { 411 result := new(ctypes.ResultBlock) 412 params := map[string]interface{}{ 413 "hash": hash, 414 } 415 _, err := c.caller.Call(ctx, "block_by_hash", params, result) 416 if err != nil { 417 return nil, err 418 } 419 return result, nil 420 } 421 422 func (c *baseRPCClient) BlockResults( 423 ctx context.Context, 424 height *int64, 425 ) (*ctypes.ResultBlockResults, error) { 426 result := new(ctypes.ResultBlockResults) 427 params := make(map[string]interface{}) 428 if height != nil { 429 params["height"] = height 430 } 431 _, err := c.caller.Call(ctx, "block_results", params, result) 432 if err != nil { 433 return nil, err 434 } 435 return result, nil 436 } 437 438 func (c *baseRPCClient) Commit(ctx context.Context, height *int64) (*ctypes.ResultCommit, error) { 439 result := new(ctypes.ResultCommit) 440 params := make(map[string]interface{}) 441 if height != nil { 442 params["height"] = height 443 } 444 _, err := c.caller.Call(ctx, "commit", params, result) 445 if err != nil { 446 return nil, err 447 } 448 return result, nil 449 } 450 451 func (c *baseRPCClient) Tx(ctx context.Context, hash []byte, prove bool) (*ctypes.ResultTx, error) { 452 result := new(ctypes.ResultTx) 453 params := map[string]interface{}{ 454 "hash": hash, 455 "prove": prove, 456 } 457 _, err := c.caller.Call(ctx, "tx", params, result) 458 if err != nil { 459 return nil, err 460 } 461 return result, nil 462 } 463 464 func (c *baseRPCClient) TxSearch( 465 ctx context.Context, 466 query string, 467 prove bool, 468 page, 469 perPage *int, 470 orderBy string, 471 ) (*ctypes.ResultTxSearch, error) { 472 473 result := new(ctypes.ResultTxSearch) 474 params := map[string]interface{}{ 475 "query": query, 476 "prove": prove, 477 "order_by": orderBy, 478 } 479 480 if page != nil { 481 params["page"] = page 482 } 483 if perPage != nil { 484 params["per_page"] = perPage 485 } 486 487 _, err := c.caller.Call(ctx, "tx_search", params, result) 488 if err != nil { 489 return nil, err 490 } 491 492 return result, nil 493 } 494 495 func (c *baseRPCClient) BlockSearch( 496 ctx context.Context, 497 query string, 498 page, perPage *int, 499 orderBy string, 500 ) (*ctypes.ResultBlockSearch, error) { 501 502 result := new(ctypes.ResultBlockSearch) 503 params := map[string]interface{}{ 504 "query": query, 505 "order_by": orderBy, 506 } 507 508 if page != nil { 509 params["page"] = page 510 } 511 if perPage != nil { 512 params["per_page"] = perPage 513 } 514 515 _, err := c.caller.Call(ctx, "block_search", params, result) 516 if err != nil { 517 return nil, err 518 } 519 520 return result, nil 521 } 522 523 func (c *baseRPCClient) Validators( 524 ctx context.Context, 525 height *int64, 526 page, 527 perPage *int, 528 ) (*ctypes.ResultValidators, error) { 529 result := new(ctypes.ResultValidators) 530 params := make(map[string]interface{}) 531 if page != nil { 532 params["page"] = page 533 } 534 if perPage != nil { 535 params["per_page"] = perPage 536 } 537 if height != nil { 538 params["height"] = height 539 } 540 _, err := c.caller.Call(ctx, "validators", params, result) 541 if err != nil { 542 return nil, err 543 } 544 return result, nil 545 } 546 547 func (c *baseRPCClient) BroadcastEvidence( 548 ctx context.Context, 549 ev types.Evidence, 550 ) (*ctypes.ResultBroadcastEvidence, error) { 551 result := new(ctypes.ResultBroadcastEvidence) 552 _, err := c.caller.Call(ctx, "broadcast_evidence", map[string]interface{}{"evidence": ev}, result) 553 if err != nil { 554 return nil, err 555 } 556 return result, nil 557 } 558 559 //----------------------------------------------------------------------------- 560 // WSEvents 561 562 var errNotRunning = errors.New("client is not running. Use .Start() method to start") 563 564 // WSEvents is a wrapper around WSClient, which implements EventsClient. 565 type WSEvents struct { 566 service.BaseService 567 remote string 568 endpoint string 569 ws *jsonrpcclient.WSClient 570 571 mtx tmsync.RWMutex 572 subscriptions map[string]chan ctypes.ResultEvent // query -> chan 573 } 574 575 func newWSEvents(remote, endpoint string) (*WSEvents, error) { 576 w := &WSEvents{ 577 endpoint: endpoint, 578 remote: remote, 579 subscriptions: make(map[string]chan ctypes.ResultEvent), 580 } 581 w.BaseService = *service.NewBaseService(nil, "WSEvents", w) 582 583 var err error 584 w.ws, err = jsonrpcclient.NewWS(w.remote, w.endpoint, jsonrpcclient.OnReconnect(func() { 585 // resubscribe immediately 586 w.redoSubscriptionsAfter(0 * time.Second) 587 })) 588 if err != nil { 589 return nil, err 590 } 591 w.ws.SetLogger(w.Logger) 592 593 return w, nil 594 } 595 596 // OnStart implements service.Service by starting WSClient and event loop. 597 func (w *WSEvents) OnStart() error { 598 if err := w.ws.Start(); err != nil { 599 return err 600 } 601 602 go w.eventListener() 603 604 return nil 605 } 606 607 // OnStop implements service.Service by stopping WSClient. 608 func (w *WSEvents) OnStop() { 609 if err := w.ws.Stop(); err != nil { 610 w.Logger.Error("Can't stop ws client", "err", err) 611 } 612 } 613 614 // Subscribe implements EventsClient by using WSClient to subscribe given 615 // subscriber to query. By default, returns a channel with cap=1. Error is 616 // returned if it fails to subscribe. 617 // 618 // Channel is never closed to prevent clients from seeing an erroneous event. 619 // 620 // It returns an error if WSEvents is not running. 621 func (w *WSEvents) Subscribe(ctx context.Context, subscriber, query string, 622 outCapacity ...int) (out <-chan ctypes.ResultEvent, err error) { 623 624 if !w.IsRunning() { 625 return nil, errNotRunning 626 } 627 628 if err := w.ws.Subscribe(ctx, query); err != nil { 629 return nil, err 630 } 631 632 outCap := 1 633 if len(outCapacity) > 0 { 634 outCap = outCapacity[0] 635 } 636 637 outc := make(chan ctypes.ResultEvent, outCap) 638 w.mtx.Lock() 639 // subscriber param is ignored because Tendermint will override it with 640 // remote IP anyway. 641 w.subscriptions[query] = outc 642 w.mtx.Unlock() 643 644 return outc, nil 645 } 646 647 // Unsubscribe implements EventsClient by using WSClient to unsubscribe given 648 // subscriber from query. 649 // 650 // It returns an error if WSEvents is not running. 651 func (w *WSEvents) Unsubscribe(ctx context.Context, subscriber, query string) error { 652 if !w.IsRunning() { 653 return errNotRunning 654 } 655 656 if err := w.ws.Unsubscribe(ctx, query); err != nil { 657 return err 658 } 659 660 w.mtx.Lock() 661 _, ok := w.subscriptions[query] 662 if ok { 663 delete(w.subscriptions, query) 664 } 665 w.mtx.Unlock() 666 667 return nil 668 } 669 670 // UnsubscribeAll implements EventsClient by using WSClient to unsubscribe 671 // given subscriber from all the queries. 672 // 673 // It returns an error if WSEvents is not running. 674 func (w *WSEvents) UnsubscribeAll(ctx context.Context, subscriber string) error { 675 if !w.IsRunning() { 676 return errNotRunning 677 } 678 679 if err := w.ws.UnsubscribeAll(ctx); err != nil { 680 return err 681 } 682 683 w.mtx.Lock() 684 w.subscriptions = make(map[string]chan ctypes.ResultEvent) 685 w.mtx.Unlock() 686 687 return nil 688 } 689 690 // After being reconnected, it is necessary to redo subscription to server 691 // otherwise no data will be automatically received. 692 func (w *WSEvents) redoSubscriptionsAfter(d time.Duration) { 693 time.Sleep(d) 694 695 w.mtx.RLock() 696 defer w.mtx.RUnlock() 697 for q := range w.subscriptions { 698 err := w.ws.Subscribe(context.Background(), q) 699 if err != nil { 700 w.Logger.Error("Failed to resubscribe", "err", err) 701 } 702 } 703 } 704 705 func isErrAlreadySubscribed(err error) bool { 706 return strings.Contains(err.Error(), tmpubsub.ErrAlreadySubscribed.Error()) 707 } 708 709 func (w *WSEvents) eventListener() { 710 for { 711 select { 712 case resp, ok := <-w.ws.ResponsesCh: 713 if !ok { 714 return 715 } 716 717 if resp.Error != nil { 718 w.Logger.Error("WS error", "err", resp.Error.Error()) 719 // Error can be ErrAlreadySubscribed or max client (subscriptions per 720 // client) reached or Tendermint exited. 721 // We can ignore ErrAlreadySubscribed, but need to retry in other 722 // cases. 723 if !isErrAlreadySubscribed(resp.Error) { 724 // Resubscribe after 1 second to give Tendermint time to restart (if 725 // crashed). 726 w.redoSubscriptionsAfter(1 * time.Second) 727 } 728 continue 729 } 730 731 result := new(ctypes.ResultEvent) 732 err := tmjson.Unmarshal(resp.Result, result) 733 if err != nil { 734 w.Logger.Error("failed to unmarshal response", "err", err) 735 continue 736 } 737 738 w.mtx.RLock() 739 if out, ok := w.subscriptions[result.Query]; ok { 740 if cap(out) == 0 { 741 out <- *result 742 } else { 743 select { 744 case out <- *result: 745 default: 746 w.Logger.Error("wanted to publish ResultEvent, but out channel is full", "result", result, "query", result.Query) 747 } 748 } 749 } 750 w.mtx.RUnlock() 751 case <-w.Quit(): 752 return 753 } 754 } 755 }