github.com/gnolang/gno@v0.0.0-20240520182011-228e9d0192ce/tm2/pkg/bft/abci/client/client.go (about)

     1  package abcicli
     2  
     3  import (
     4  	"sync"
     5  
     6  	abci "github.com/gnolang/gno/tm2/pkg/bft/abci/types"
     7  	"github.com/gnolang/gno/tm2/pkg/service"
     8  )
     9  
    10  // Client defines an interface for an ABCI client.
    11  // All `Async` methods return a `ReqRes` object.
    12  // All `Sync` methods return the appropriate protobuf ResponseXxx struct and an error.
    13  // Note these are client errors, eg. ABCI socket connectivity issues.
    14  // Application-related errors are reflected in response via ABCI error codes and logs.
    15  type Client interface {
    16  	service.Service
    17  
    18  	SetResponseCallback(Callback)
    19  	Error() error
    20  
    21  	FlushAsync() *ReqRes
    22  	EchoAsync(msg string) *ReqRes
    23  	InfoAsync(abci.RequestInfo) *ReqRes
    24  	SetOptionAsync(abci.RequestSetOption) *ReqRes
    25  	DeliverTxAsync(abci.RequestDeliverTx) *ReqRes
    26  	CheckTxAsync(abci.RequestCheckTx) *ReqRes
    27  	QueryAsync(abci.RequestQuery) *ReqRes
    28  	CommitAsync() *ReqRes
    29  	InitChainAsync(abci.RequestInitChain) *ReqRes
    30  	BeginBlockAsync(abci.RequestBeginBlock) *ReqRes
    31  	EndBlockAsync(abci.RequestEndBlock) *ReqRes
    32  
    33  	FlushSync() error
    34  	EchoSync(msg string) (abci.ResponseEcho, error)
    35  	InfoSync(abci.RequestInfo) (abci.ResponseInfo, error)
    36  	SetOptionSync(abci.RequestSetOption) (abci.ResponseSetOption, error)
    37  	DeliverTxSync(abci.RequestDeliverTx) (abci.ResponseDeliverTx, error)
    38  	CheckTxSync(abci.RequestCheckTx) (abci.ResponseCheckTx, error)
    39  	QuerySync(abci.RequestQuery) (abci.ResponseQuery, error)
    40  	CommitSync() (abci.ResponseCommit, error)
    41  	InitChainSync(abci.RequestInitChain) (abci.ResponseInitChain, error)
    42  	BeginBlockSync(abci.RequestBeginBlock) (abci.ResponseBeginBlock, error)
    43  	EndBlockSync(abci.RequestEndBlock) (abci.ResponseEndBlock, error)
    44  }
    45  
    46  // ----------------------------------------
    47  
    48  type Callback func(abci.Request, abci.Response)
    49  
    50  // ----------------------------------------
    51  
    52  type ReqRes struct {
    53  	abci.Request
    54  	wg *sync.WaitGroup
    55  
    56  	mtx sync.Mutex
    57  	abci.Response
    58  	cb func(abci.Response) // A single callback that may be set.
    59  }
    60  
    61  func NewReqRes(req abci.Request) *ReqRes {
    62  	return &ReqRes{
    63  		Request:  req,
    64  		wg:       waitGroup1(),
    65  		Response: nil,
    66  
    67  		cb: nil,
    68  	}
    69  }
    70  
    71  // Sets the callback for this ReqRes atomically.
    72  // If reqRes is already done, calls cb immediately.
    73  // NOTE: reqRes.cb should not change if reqRes.done.
    74  // NOTE: only one callback is supported.
    75  func (reqRes *ReqRes) SetCallback(cb func(res abci.Response)) {
    76  	reqRes.mtx.Lock()
    77  
    78  	if reqRes.Response != nil {
    79  		reqRes.mtx.Unlock()
    80  		cb(reqRes.Response)
    81  		return
    82  	}
    83  
    84  	reqRes.cb = cb
    85  	reqRes.mtx.Unlock()
    86  }
    87  
    88  func (reqRes *ReqRes) GetCallback() func(abci.Response) {
    89  	reqRes.mtx.Lock()
    90  	defer reqRes.mtx.Unlock()
    91  	return reqRes.cb
    92  }
    93  
    94  // Wait will wait until SetResponse() is called.
    95  func (reqRes *ReqRes) Wait() {
    96  	reqRes.wg.Wait()
    97  }
    98  
    99  func (reqRes *ReqRes) SetResponse(res abci.Response) {
   100  	reqRes.mtx.Lock()
   101  	if reqRes.Response != nil {
   102  		panic("should not happen")
   103  	}
   104  	reqRes.Response = res
   105  	reqRes.mtx.Unlock()
   106  
   107  	reqRes.wg.Done()
   108  }
   109  
   110  // NOTE: it should be safe to read reqRes.cb without locks after this.
   111  func (reqRes *ReqRes) Done() {
   112  	// Finally, release the hounds.
   113  	reqRes.wg.Done()
   114  }
   115  
   116  func waitGroup1() (wg *sync.WaitGroup) {
   117  	wg = &sync.WaitGroup{}
   118  	wg.Add(1)
   119  	return
   120  }