github.com/noirx94/tendermintmp@v0.0.1/abci/client/client.go (about)

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