github.com/number571/tendermint@v0.34.11-gost/abci/client/client.go (about)

     1  package abcicli
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  	"sync"
     7  
     8  	"github.com/number571/tendermint/abci/types"
     9  	tmsync "github.com/number571/tendermint/internal/libs/sync"
    10  	"github.com/number571/tendermint/libs/service"
    11  )
    12  
    13  const (
    14  	dialRetryIntervalSeconds = 3
    15  	echoRetryIntervalSeconds = 1
    16  )
    17  
    18  //go:generate mockery --case underscore --name Client
    19  
    20  // Client defines an interface for an ABCI client.
    21  //
    22  // All `Async` methods return a `ReqRes` object and an error.
    23  // All `Sync` methods return the appropriate protobuf ResponseXxx struct and an error.
    24  //
    25  // NOTE these are client errors, eg. ABCI socket connectivity issues.
    26  // Application-related errors are reflected in response via ABCI error codes
    27  // and logs.
    28  type Client interface {
    29  	service.Service
    30  
    31  	SetResponseCallback(Callback)
    32  	Error() error
    33  
    34  	// Asynchronous requests
    35  	FlushAsync(context.Context) (*ReqRes, error)
    36  	EchoAsync(ctx context.Context, msg string) (*ReqRes, error)
    37  	InfoAsync(context.Context, types.RequestInfo) (*ReqRes, error)
    38  	DeliverTxAsync(context.Context, types.RequestDeliverTx) (*ReqRes, error)
    39  	CheckTxAsync(context.Context, types.RequestCheckTx) (*ReqRes, error)
    40  	QueryAsync(context.Context, types.RequestQuery) (*ReqRes, error)
    41  	CommitAsync(context.Context) (*ReqRes, error)
    42  	InitChainAsync(context.Context, types.RequestInitChain) (*ReqRes, error)
    43  	BeginBlockAsync(context.Context, types.RequestBeginBlock) (*ReqRes, error)
    44  	EndBlockAsync(context.Context, types.RequestEndBlock) (*ReqRes, error)
    45  	ListSnapshotsAsync(context.Context, types.RequestListSnapshots) (*ReqRes, error)
    46  	OfferSnapshotAsync(context.Context, types.RequestOfferSnapshot) (*ReqRes, error)
    47  	LoadSnapshotChunkAsync(context.Context, types.RequestLoadSnapshotChunk) (*ReqRes, error)
    48  	ApplySnapshotChunkAsync(context.Context, types.RequestApplySnapshotChunk) (*ReqRes, error)
    49  
    50  	// Synchronous requests
    51  	FlushSync(context.Context) error
    52  	EchoSync(ctx context.Context, msg string) (*types.ResponseEcho, error)
    53  	InfoSync(context.Context, types.RequestInfo) (*types.ResponseInfo, error)
    54  	DeliverTxSync(context.Context, types.RequestDeliverTx) (*types.ResponseDeliverTx, error)
    55  	CheckTxSync(context.Context, types.RequestCheckTx) (*types.ResponseCheckTx, error)
    56  	QuerySync(context.Context, types.RequestQuery) (*types.ResponseQuery, error)
    57  	CommitSync(context.Context) (*types.ResponseCommit, error)
    58  	InitChainSync(context.Context, types.RequestInitChain) (*types.ResponseInitChain, error)
    59  	BeginBlockSync(context.Context, types.RequestBeginBlock) (*types.ResponseBeginBlock, error)
    60  	EndBlockSync(context.Context, types.RequestEndBlock) (*types.ResponseEndBlock, error)
    61  	ListSnapshotsSync(context.Context, types.RequestListSnapshots) (*types.ResponseListSnapshots, error)
    62  	OfferSnapshotSync(context.Context, types.RequestOfferSnapshot) (*types.ResponseOfferSnapshot, error)
    63  	LoadSnapshotChunkSync(context.Context, types.RequestLoadSnapshotChunk) (*types.ResponseLoadSnapshotChunk, error)
    64  	ApplySnapshotChunkSync(context.Context, types.RequestApplySnapshotChunk) (*types.ResponseApplySnapshotChunk, error)
    65  }
    66  
    67  //----------------------------------------
    68  
    69  // NewClient returns a new ABCI client of the specified transport type.
    70  // It returns an error if the transport is not "socket" or "grpc"
    71  func NewClient(addr, transport string, mustConnect bool) (client Client, err error) {
    72  	switch transport {
    73  	case "socket":
    74  		client = NewSocketClient(addr, mustConnect)
    75  	case "grpc":
    76  		client = NewGRPCClient(addr, mustConnect)
    77  	default:
    78  		err = fmt.Errorf("unknown abci transport %s", transport)
    79  	}
    80  	return
    81  }
    82  
    83  type Callback func(*types.Request, *types.Response)
    84  
    85  type ReqRes struct {
    86  	*types.Request
    87  	*sync.WaitGroup
    88  	*types.Response // Not set atomically, so be sure to use WaitGroup.
    89  
    90  	mtx  tmsync.RWMutex
    91  	done bool                  // Gets set to true once *after* WaitGroup.Done().
    92  	cb   func(*types.Response) // A single callback that may be set.
    93  }
    94  
    95  func NewReqRes(req *types.Request) *ReqRes {
    96  	return &ReqRes{
    97  		Request:   req,
    98  		WaitGroup: waitGroup1(),
    99  		Response:  nil,
   100  
   101  		done: false,
   102  		cb:   nil,
   103  	}
   104  }
   105  
   106  // Sets sets the callback. If reqRes is already done, it will call the cb
   107  // immediately. Note, reqRes.cb should not change if reqRes.done and only one
   108  // callback is supported.
   109  func (r *ReqRes) SetCallback(cb func(res *types.Response)) {
   110  	r.mtx.Lock()
   111  
   112  	if r.done {
   113  		r.mtx.Unlock()
   114  		cb(r.Response)
   115  		return
   116  	}
   117  
   118  	r.cb = cb
   119  	r.mtx.Unlock()
   120  }
   121  
   122  // InvokeCallback invokes a thread-safe execution of the configured callback
   123  // if non-nil.
   124  func (r *ReqRes) InvokeCallback() {
   125  	r.mtx.Lock()
   126  	defer r.mtx.Unlock()
   127  
   128  	if r.cb != nil {
   129  		r.cb(r.Response)
   130  	}
   131  }
   132  
   133  // GetCallback returns the configured callback of the ReqRes object which may be
   134  // nil. Note, it is not safe to concurrently call this in cases where it is
   135  // marked done and SetCallback is called before calling GetCallback as that
   136  // will invoke the callback twice and create a potential race condition.
   137  //
   138  // ref: https://github.com/number571/tendermint/issues/5439
   139  func (r *ReqRes) GetCallback() func(*types.Response) {
   140  	r.mtx.RLock()
   141  	defer r.mtx.RUnlock()
   142  	return r.cb
   143  }
   144  
   145  // SetDone marks the ReqRes object as done.
   146  func (r *ReqRes) SetDone() {
   147  	r.mtx.Lock()
   148  	defer r.mtx.Unlock()
   149  	r.done = true
   150  }
   151  
   152  func waitGroup1() (wg *sync.WaitGroup) {
   153  	wg = &sync.WaitGroup{}
   154  	wg.Add(1)
   155  	return
   156  }