github.com/lazyledger/lazyledger-core@v0.35.0-dev.0.20210613111200-4c651f053571/abci/client/client.go (about)

     1  package abcicli
     2  
     3  import (
     4  	"context"
     5  
     6  	"sync"
     7  
     8  	"github.com/lazyledger/lazyledger-core/abci/types"
     9  	"github.com/lazyledger/lazyledger-core/libs/service"
    10  	tmsync "github.com/lazyledger/lazyledger-core/libs/sync"
    11  )
    12  
    13  //go:generate mockery --case underscore --name Client
    14  
    15  // Client defines an interface for an ABCI client.
    16  //
    17  // All `Async` methods return a `ReqRes` object and an error.
    18  // All `Sync` methods return the appropriate protobuf ResponseXxx struct and an error.
    19  //
    20  // NOTE these are client errors, eg. ABCI socket connectivity issues.
    21  // Application-related errors are reflected in response via ABCI error codes
    22  // and logs.
    23  type Client interface {
    24  	service.Service
    25  
    26  	SetResponseCallback(Callback)
    27  	Error() error
    28  
    29  	// Asynchronous requests
    30  	FlushAsync(context.Context) (*ReqRes, error)
    31  	EchoAsync(ctx context.Context, msg string) (*ReqRes, error)
    32  	InfoAsync(context.Context, types.RequestInfo) (*ReqRes, error)
    33  	DeliverTxAsync(context.Context, types.RequestDeliverTx) (*ReqRes, error)
    34  	CheckTxAsync(context.Context, types.RequestCheckTx) (*ReqRes, error)
    35  	QueryAsync(context.Context, types.RequestQuery) (*ReqRes, error)
    36  	CommitAsync(context.Context) (*ReqRes, error)
    37  	InitChainAsync(context.Context, types.RequestInitChain) (*ReqRes, error)
    38  	BeginBlockAsync(context.Context, types.RequestBeginBlock) (*ReqRes, error)
    39  	EndBlockAsync(context.Context, types.RequestEndBlock) (*ReqRes, error)
    40  	ListSnapshotsAsync(context.Context, types.RequestListSnapshots) (*ReqRes, error)
    41  	OfferSnapshotAsync(context.Context, types.RequestOfferSnapshot) (*ReqRes, error)
    42  	LoadSnapshotChunkAsync(context.Context, types.RequestLoadSnapshotChunk) (*ReqRes, error)
    43  	ApplySnapshotChunkAsync(context.Context, types.RequestApplySnapshotChunk) (*ReqRes, error)
    44  	PreprocessTxsAsync(context.Context, types.RequestPreprocessTxs) (*ReqRes, error)
    45  
    46  	// Synchronous requests
    47  	FlushSync(context.Context) error
    48  	EchoSync(ctx context.Context, msg string) (*types.ResponseEcho, error)
    49  	InfoSync(context.Context, types.RequestInfo) (*types.ResponseInfo, error)
    50  	DeliverTxSync(context.Context, types.RequestDeliverTx) (*types.ResponseDeliverTx, error)
    51  	CheckTxSync(context.Context, types.RequestCheckTx) (*types.ResponseCheckTx, error)
    52  	QuerySync(context.Context, types.RequestQuery) (*types.ResponseQuery, error)
    53  	CommitSync(context.Context) (*types.ResponseCommit, error)
    54  	InitChainSync(context.Context, types.RequestInitChain) (*types.ResponseInitChain, error)
    55  	BeginBlockSync(context.Context, types.RequestBeginBlock) (*types.ResponseBeginBlock, error)
    56  	EndBlockSync(context.Context, types.RequestEndBlock) (*types.ResponseEndBlock, error)
    57  	ListSnapshotsSync(context.Context, types.RequestListSnapshots) (*types.ResponseListSnapshots, error)
    58  	OfferSnapshotSync(context.Context, types.RequestOfferSnapshot) (*types.ResponseOfferSnapshot, error)
    59  	LoadSnapshotChunkSync(context.Context, types.RequestLoadSnapshotChunk) (*types.ResponseLoadSnapshotChunk, error)
    60  	ApplySnapshotChunkSync(context.Context, types.RequestApplySnapshotChunk) (*types.ResponseApplySnapshotChunk, error)
    61  	PreprocessTxsSync(context.Context, types.RequestPreprocessTxs) (*types.ResponsePreprocessTxs, error)
    62  }
    63  
    64  type Callback func(*types.Request, *types.Response)
    65  
    66  //----------------------------------------
    67  
    68  type ReqRes struct {
    69  	*types.Request
    70  	*sync.WaitGroup
    71  	*types.Response // Not set atomically, so be sure to use WaitGroup.
    72  
    73  	mtx  tmsync.Mutex
    74  	done bool                  // Gets set to true once *after* WaitGroup.Done().
    75  	cb   func(*types.Response) // A single callback that may be set.
    76  }
    77  
    78  func NewReqRes(req *types.Request) *ReqRes {
    79  	return &ReqRes{
    80  		Request:   req,
    81  		WaitGroup: waitGroup1(),
    82  		Response:  nil,
    83  
    84  		done: false,
    85  		cb:   nil,
    86  	}
    87  }
    88  
    89  // Sets the callback for this ReqRes atomically.
    90  // If reqRes is already done, calls cb immediately.
    91  // NOTE: reqRes.cb should not change if reqRes.done.
    92  // NOTE: only one callback is supported.
    93  func (reqRes *ReqRes) SetCallback(cb func(res *types.Response)) {
    94  	reqRes.mtx.Lock()
    95  
    96  	if reqRes.done {
    97  		reqRes.mtx.Unlock()
    98  		cb(reqRes.Response)
    99  		return
   100  	}
   101  
   102  	reqRes.cb = cb
   103  	reqRes.mtx.Unlock()
   104  }
   105  
   106  func (reqRes *ReqRes) GetCallback() func(*types.Response) {
   107  	reqRes.mtx.Lock()
   108  	defer reqRes.mtx.Unlock()
   109  	return reqRes.cb
   110  }
   111  
   112  // NOTE: it should be safe to read reqRes.cb without locks after this.
   113  func (reqRes *ReqRes) SetDone() {
   114  	reqRes.mtx.Lock()
   115  	reqRes.done = true
   116  	reqRes.mtx.Unlock()
   117  }
   118  
   119  func waitGroup1() (wg *sync.WaitGroup) {
   120  	wg = &sync.WaitGroup{}
   121  	wg.Add(1)
   122  	return
   123  }