github.com/line/ostracon@v1.0.10-0.20230328032236-7f20145f065d/abci/client/client.go (about)

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