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