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