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  }