github.com/evdatsion/aphelion-dpos-bft@v0.32.1/abci/client/client.go (about)

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