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 }