You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

301 lines
8.8 KiB

8 years ago
8 years ago
8 years ago
9 years ago
8 years ago
8 years ago
8 years ago
8 years ago
9 years ago
9 years ago
9 years ago
8 years ago
8 years ago
9 years ago
8 years ago
7 years ago
9 years ago
9 years ago
9 years ago
9 years ago
7 years ago
7 years ago
7 years ago
  1. package abcicli
  2. import (
  3. "fmt"
  4. "net"
  5. "sync"
  6. "time"
  7. "github.com/pkg/errors"
  8. context "golang.org/x/net/context"
  9. grpc "google.golang.org/grpc"
  10. "github.com/tendermint/abci/types"
  11. cmn "github.com/tendermint/tmlibs/common"
  12. )
  13. var _ Client = (*grpcClient)(nil)
  14. // A stripped copy of the remoteClient that makes
  15. // synchronous calls using grpc
  16. type grpcClient struct {
  17. cmn.BaseService
  18. mustConnect bool
  19. client types.ABCIApplicationClient
  20. mtx sync.Mutex
  21. addr string
  22. err error
  23. resCb func(*types.Request, *types.Response) // listens to all callbacks
  24. }
  25. func NewGRPCClient(addr string, mustConnect bool) *grpcClient {
  26. cli := &grpcClient{
  27. addr: addr,
  28. mustConnect: mustConnect,
  29. }
  30. cli.BaseService = *cmn.NewBaseService(nil, "grpcClient", cli)
  31. return cli
  32. }
  33. func dialerFunc(addr string, timeout time.Duration) (net.Conn, error) {
  34. return cmn.Connect(addr)
  35. }
  36. func (cli *grpcClient) OnStart() error {
  37. if err := cli.BaseService.OnStart(); err != nil {
  38. return err
  39. }
  40. RETRY_LOOP:
  41. for {
  42. conn, err := grpc.Dial(cli.addr, grpc.WithInsecure(), grpc.WithDialer(dialerFunc))
  43. if err != nil {
  44. if cli.mustConnect {
  45. return err
  46. }
  47. cli.Logger.Error(fmt.Sprintf("abci.grpcClient failed to connect to %v. Retrying...\n", cli.addr))
  48. time.Sleep(time.Second * dialRetryIntervalSeconds)
  49. continue RETRY_LOOP
  50. }
  51. client := types.NewABCIApplicationClient(conn)
  52. ENSURE_CONNECTED:
  53. for {
  54. _, err := client.Echo(context.Background(), &types.RequestEcho{"hello"}, grpc.FailFast(true))
  55. if err == nil {
  56. break ENSURE_CONNECTED
  57. }
  58. time.Sleep(time.Second * echoRetryIntervalSeconds)
  59. }
  60. cli.client = client
  61. return nil
  62. }
  63. }
  64. func (cli *grpcClient) OnStop() {
  65. cli.BaseService.OnStop()
  66. cli.mtx.Lock()
  67. defer cli.mtx.Unlock()
  68. // TODO: how to close conn? its not a net.Conn and grpc doesn't expose a Close()
  69. /*if cli.conn != nil {
  70. cli.conn.Close()
  71. }*/
  72. }
  73. func (cli *grpcClient) StopForError(err error) {
  74. cli.mtx.Lock()
  75. if !cli.IsRunning() {
  76. return
  77. }
  78. if cli.err == nil {
  79. cli.err = err
  80. }
  81. cli.mtx.Unlock()
  82. cli.Logger.Error(fmt.Sprintf("Stopping abci.grpcClient for error: %v", err.Error()))
  83. cli.Stop()
  84. }
  85. func (cli *grpcClient) Error() error {
  86. cli.mtx.Lock()
  87. defer cli.mtx.Unlock()
  88. return errors.Wrap(cli.err, types.HumanCode(types.CodeType_InternalError))
  89. }
  90. // Set listener for all responses
  91. // NOTE: callback may get internally generated flush responses.
  92. func (cli *grpcClient) SetResponseCallback(resCb Callback) {
  93. cli.mtx.Lock()
  94. defer cli.mtx.Unlock()
  95. cli.resCb = resCb
  96. }
  97. //----------------------------------------
  98. // GRPC calls are synchronous, but some callbacks expect to be called asynchronously
  99. // (eg. the mempool expects to be able to lock to remove bad txs from cache).
  100. // To accommodate, we finish each call in its own go-routine,
  101. // which is expensive, but easy - if you want something better, use the socket protocol!
  102. // maybe one day, if people really want it, we use grpc streams,
  103. // but hopefully not :D
  104. func (cli *grpcClient) EchoAsync(msg string) *ReqRes {
  105. req := types.ToRequestEcho(msg)
  106. res, err := cli.client.Echo(context.Background(), req.GetEcho(), grpc.FailFast(true))
  107. if err != nil {
  108. cli.StopForError(err)
  109. }
  110. return cli.finishAsyncCall(req, &types.Response{&types.Response_Echo{res}})
  111. }
  112. func (cli *grpcClient) FlushAsync() *ReqRes {
  113. req := types.ToRequestFlush()
  114. res, err := cli.client.Flush(context.Background(), req.GetFlush(), grpc.FailFast(true))
  115. if err != nil {
  116. cli.StopForError(err)
  117. }
  118. return cli.finishAsyncCall(req, &types.Response{&types.Response_Flush{res}})
  119. }
  120. func (cli *grpcClient) InfoAsync(params types.RequestInfo) *ReqRes {
  121. req := types.ToRequestInfo(params)
  122. res, err := cli.client.Info(context.Background(), req.GetInfo(), grpc.FailFast(true))
  123. if err != nil {
  124. cli.StopForError(err)
  125. }
  126. return cli.finishAsyncCall(req, &types.Response{&types.Response_Info{res}})
  127. }
  128. func (cli *grpcClient) SetOptionAsync(params types.RequestSetOption) *ReqRes {
  129. req := types.ToRequestSetOption(params)
  130. res, err := cli.client.SetOption(context.Background(), req.GetSetOption(), grpc.FailFast(true))
  131. if err != nil {
  132. cli.StopForError(err)
  133. }
  134. return cli.finishAsyncCall(req, &types.Response{&types.Response_SetOption{res}})
  135. }
  136. func (cli *grpcClient) DeliverTxAsync(tx []byte) *ReqRes {
  137. req := types.ToRequestDeliverTx(tx)
  138. res, err := cli.client.DeliverTx(context.Background(), req.GetDeliverTx(), grpc.FailFast(true))
  139. if err != nil {
  140. cli.StopForError(err)
  141. }
  142. return cli.finishAsyncCall(req, &types.Response{&types.Response_DeliverTx{res}})
  143. }
  144. func (cli *grpcClient) CheckTxAsync(tx []byte) *ReqRes {
  145. req := types.ToRequestCheckTx(tx)
  146. res, err := cli.client.CheckTx(context.Background(), req.GetCheckTx(), grpc.FailFast(true))
  147. if err != nil {
  148. cli.StopForError(err)
  149. }
  150. return cli.finishAsyncCall(req, &types.Response{&types.Response_CheckTx{res}})
  151. }
  152. func (cli *grpcClient) QueryAsync(params types.RequestQuery) *ReqRes {
  153. req := types.ToRequestQuery(params)
  154. res, err := cli.client.Query(context.Background(), req.GetQuery(), grpc.FailFast(true))
  155. if err != nil {
  156. cli.StopForError(err)
  157. }
  158. return cli.finishAsyncCall(req, &types.Response{&types.Response_Query{res}})
  159. }
  160. func (cli *grpcClient) CommitAsync() *ReqRes {
  161. req := types.ToRequestCommit()
  162. res, err := cli.client.Commit(context.Background(), req.GetCommit(), grpc.FailFast(true))
  163. if err != nil {
  164. cli.StopForError(err)
  165. }
  166. return cli.finishAsyncCall(req, &types.Response{&types.Response_Commit{res}})
  167. }
  168. func (cli *grpcClient) InitChainAsync(params types.RequestInitChain) *ReqRes {
  169. req := types.ToRequestInitChain(params)
  170. res, err := cli.client.InitChain(context.Background(), req.GetInitChain(), grpc.FailFast(true))
  171. if err != nil {
  172. cli.StopForError(err)
  173. }
  174. return cli.finishAsyncCall(req, &types.Response{&types.Response_InitChain{res}})
  175. }
  176. func (cli *grpcClient) BeginBlockAsync(params types.RequestBeginBlock) *ReqRes {
  177. req := types.ToRequestBeginBlock(params)
  178. res, err := cli.client.BeginBlock(context.Background(), req.GetBeginBlock(), grpc.FailFast(true))
  179. if err != nil {
  180. cli.StopForError(err)
  181. }
  182. return cli.finishAsyncCall(req, &types.Response{&types.Response_BeginBlock{res}})
  183. }
  184. func (cli *grpcClient) EndBlockAsync(params types.RequestEndBlock) *ReqRes {
  185. req := types.ToRequestEndBlock(params)
  186. res, err := cli.client.EndBlock(context.Background(), req.GetEndBlock(), grpc.FailFast(true))
  187. if err != nil {
  188. cli.StopForError(err)
  189. }
  190. return cli.finishAsyncCall(req, &types.Response{&types.Response_EndBlock{res}})
  191. }
  192. func (cli *grpcClient) finishAsyncCall(req *types.Request, res *types.Response) *ReqRes {
  193. reqres := NewReqRes(req)
  194. reqres.Response = res // Set response
  195. reqres.Done() // Release waiters
  196. reqres.SetDone() // so reqRes.SetCallback will run the callback
  197. // go routine for callbacks
  198. go func() {
  199. // Notify reqRes listener if set
  200. if cb := reqres.GetCallback(); cb != nil {
  201. cb(res)
  202. }
  203. // Notify client listener if set
  204. if cli.resCb != nil {
  205. cli.resCb(reqres.Request, res)
  206. }
  207. }()
  208. return reqres
  209. }
  210. //----------------------------------------
  211. func (cli *grpcClient) FlushSync() error {
  212. return nil
  213. }
  214. func (cli *grpcClient) EchoSync(msg string) (*types.ResponseEcho, error) {
  215. reqres := cli.EchoAsync(msg)
  216. // StopForError should already have been called if error is set
  217. return reqres.Response.GetEcho(), cli.Error()
  218. }
  219. func (cli *grpcClient) InfoSync(req types.RequestInfo) (*types.ResponseInfo, error) {
  220. reqres := cli.InfoAsync(req)
  221. return reqres.Response.GetInfo(), cli.Error()
  222. }
  223. func (cli *grpcClient) SetOptionSync(req types.RequestSetOption) (*types.ResponseSetOption, error) {
  224. reqres := cli.SetOptionAsync(req)
  225. return reqres.Response.GetSetOption(), cli.Error()
  226. }
  227. func (cli *grpcClient) DeliverTxSync(tx []byte) (*types.ResponseDeliverTx, error) {
  228. reqres := cli.DeliverTxAsync(tx)
  229. return reqres.Response.GetDeliverTx(), cli.Error()
  230. }
  231. func (cli *grpcClient) CheckTxSync(tx []byte) (*types.ResponseCheckTx, error) {
  232. reqres := cli.CheckTxAsync(tx)
  233. return reqres.Response.GetCheckTx(), cli.Error()
  234. }
  235. func (cli *grpcClient) QuerySync(req types.RequestQuery) (*types.ResponseQuery, error) {
  236. reqres := cli.QueryAsync(req)
  237. return reqres.Response.GetQuery(), cli.Error()
  238. }
  239. func (cli *grpcClient) CommitSync() (*types.ResponseCommit, error) {
  240. reqres := cli.CommitAsync()
  241. return reqres.Response.GetCommit(), cli.Error()
  242. }
  243. func (cli *grpcClient) InitChainSync(params types.RequestInitChain) (*types.ResponseInitChain, error) {
  244. reqres := cli.InitChainAsync(params)
  245. return reqres.Response.GetInitChain(), cli.Error()
  246. }
  247. func (cli *grpcClient) BeginBlockSync(params types.RequestBeginBlock) (*types.ResponseBeginBlock, error) {
  248. reqres := cli.BeginBlockAsync(params)
  249. return reqres.Response.GetBeginBlock(), cli.Error()
  250. }
  251. func (cli *grpcClient) EndBlockSync(params types.RequestEndBlock) (*types.ResponseEndBlock, error) {
  252. reqres := cli.EndBlockAsync(params)
  253. return reqres.Response.GetEndBlock(), cli.Error()
  254. }