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.

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