github.com/line/ostracon@v1.0.10-0.20230328032236-7f20145f065d/abci/client/socket_client.go (about) 1 package abcicli 2 3 import ( 4 "bufio" 5 "container/list" 6 "errors" 7 "fmt" 8 "io" 9 "net" 10 "reflect" 11 "time" 12 13 "github.com/tendermint/tendermint/abci/types" 14 15 ocabci "github.com/line/ostracon/abci/types" 16 tmnet "github.com/line/ostracon/libs/net" 17 "github.com/line/ostracon/libs/service" 18 tmsync "github.com/line/ostracon/libs/sync" 19 "github.com/line/ostracon/libs/timer" 20 ) 21 22 const ( 23 reqQueueSize = 256 // TODO make configurable 24 flushThrottleMS = 20 // Don't wait longer than... 25 ) 26 27 // This is goroutine-safe, but users should beware that the application in 28 // general is not meant to be interfaced with concurrent callers. 29 type socketClient struct { 30 service.BaseService 31 32 addr string 33 mustConnect bool 34 conn net.Conn 35 36 reqQueue chan *ReqRes 37 flushTimer *timer.ThrottleTimer 38 39 mtx tmsync.Mutex 40 err error 41 reqSent *list.List // list of requests sent, waiting for response 42 43 globalCbMtx tmsync.Mutex 44 globalCb GlobalCallback 45 } 46 47 var _ Client = (*socketClient)(nil) 48 49 // NewSocketClient creates a new socket client, which connects to a given 50 // address. If mustConnect is true, the client will return an error upon start 51 // if it fails to connect. 52 func NewSocketClient(addr string, mustConnect bool) Client { 53 cli := &socketClient{ 54 reqQueue: make(chan *ReqRes, reqQueueSize), 55 flushTimer: timer.NewThrottleTimer("socketClient", flushThrottleMS), 56 mustConnect: mustConnect, 57 58 addr: addr, 59 reqSent: list.New(), 60 globalCb: nil, 61 } 62 cli.BaseService = *service.NewBaseService(nil, "socketClient", cli) 63 return cli 64 } 65 66 // OnStart implements Service by connecting to the server and spawning reading 67 // and writing goroutines. 68 func (cli *socketClient) OnStart() error { 69 var ( 70 err error 71 conn net.Conn 72 ) 73 74 for { 75 conn, err = tmnet.Connect(cli.addr) 76 if err != nil { 77 if cli.mustConnect { 78 return err 79 } 80 cli.Logger.Error(fmt.Sprintf("abci.socketClient failed to connect to %v. Retrying after %vs...", 81 cli.addr, dialRetryIntervalSeconds), "err", err) 82 time.Sleep(time.Second * dialRetryIntervalSeconds) 83 continue 84 } 85 cli.conn = conn 86 87 go cli.sendRequestsRoutine(conn) 88 go cli.recvResponseRoutine(conn) 89 90 return nil 91 } 92 } 93 94 // OnStop implements Service by closing connection and flushing all queues. 95 func (cli *socketClient) OnStop() { 96 if cli.conn != nil { 97 cli.conn.Close() 98 } 99 100 cli.flushQueue() 101 cli.flushTimer.Stop() 102 } 103 104 // Error returns an error if the client was stopped abruptly. 105 func (cli *socketClient) Error() error { 106 cli.mtx.Lock() 107 defer cli.mtx.Unlock() 108 return cli.err 109 } 110 111 func (cli *socketClient) SetGlobalCallback(globalCb GlobalCallback) { 112 cli.globalCbMtx.Lock() 113 defer cli.globalCbMtx.Unlock() 114 cli.globalCb = globalCb 115 } 116 117 func (cli *socketClient) GetGlobalCallback() (cb GlobalCallback) { 118 cli.globalCbMtx.Lock() 119 defer cli.globalCbMtx.Unlock() 120 cb = cli.globalCb 121 return cb 122 } 123 124 //---------------------------------------- 125 126 func (cli *socketClient) sendRequestsRoutine(conn io.Writer) { 127 w := bufio.NewWriter(conn) 128 for { 129 select { 130 case reqres := <-cli.reqQueue: 131 // cli.Logger.Debug("Sent request", "requestType", reflect.TypeOf(reqres.Request), "request", reqres.Request) 132 133 cli.willSendReq(reqres) 134 err := ocabci.WriteMessage(reqres.Request, w) 135 if err != nil { 136 cli.stopForError(fmt.Errorf("write to buffer: %w", err)) 137 return 138 } 139 140 // If it's a flush request, flush the current buffer. 141 if _, ok := reqres.Request.Value.(*ocabci.Request_Flush); ok { 142 err = w.Flush() 143 if err != nil { 144 cli.stopForError(fmt.Errorf("flush buffer: %w", err)) 145 return 146 } 147 } 148 case <-cli.flushTimer.Ch: // flush queue 149 select { 150 case cli.reqQueue <- NewReqRes(ocabci.ToRequestFlush(), nil): 151 default: 152 // Probably will fill the buffer, or retry later. 153 } 154 case <-cli.Quit(): 155 return 156 } 157 } 158 } 159 160 func (cli *socketClient) recvResponseRoutine(conn io.Reader) { 161 r := bufio.NewReader(conn) 162 for { 163 var res = &ocabci.Response{} 164 err := ocabci.ReadMessage(r, res) 165 if err != nil { 166 cli.stopForError(fmt.Errorf("read message: %w", err)) 167 return 168 } 169 170 // cli.Logger.Debug("Received response", "responseType", reflect.TypeOf(res), "response", res) 171 172 switch r := res.Value.(type) { 173 case *ocabci.Response_Exception: // app responded with error 174 // XXX After setting cli.err, release waiters (e.g. reqres.Done()) 175 cli.stopForError(errors.New(r.Exception.Error)) 176 return 177 default: 178 err := cli.didRecvResponse(res) 179 if err != nil { 180 cli.stopForError(err) 181 return 182 } 183 } 184 } 185 } 186 187 func (cli *socketClient) willSendReq(reqres *ReqRes) { 188 cli.mtx.Lock() 189 defer cli.mtx.Unlock() 190 cli.reqSent.PushBack(reqres) 191 } 192 193 func (cli *socketClient) didRecvResponse(res *ocabci.Response) error { 194 cli.mtx.Lock() 195 defer cli.mtx.Unlock() 196 197 // Get the first ReqRes. 198 next := cli.reqSent.Front() 199 if next == nil { 200 return fmt.Errorf("unexpected %v when nothing expected", reflect.TypeOf(res.Value)) 201 } 202 203 reqres := next.Value.(*ReqRes) 204 if !resMatchesReq(reqres.Request, res) { 205 return fmt.Errorf("unexpected %v when response to %v expected", 206 reflect.TypeOf(res.Value), reflect.TypeOf(reqres.Request.Value)) 207 } 208 209 reqres.Response = res 210 reqres.wg.Done() // release waiters 211 cli.reqSent.Remove(next) // pop first item from linked list 212 213 // Notify client listener if set (global callback). 214 if cli.globalCb != nil { 215 cli.globalCb(reqres.Request, res) 216 } 217 218 // Notify reqRes listener if set (request specific callback). 219 // 220 // NOTE: It is possible this callback isn't set on the reqres object. At this 221 // point, in which case it will be called after, when it is set. 222 reqres.InvokeCallback() 223 224 return nil 225 } 226 227 //---------------------------------------- 228 229 func (cli *socketClient) EchoAsync(msg string, cb ResponseCallback) *ReqRes { 230 return cli.queueRequest(ocabci.ToRequestEcho(msg), cb) 231 } 232 233 func (cli *socketClient) FlushAsync(cb ResponseCallback) *ReqRes { 234 return cli.queueRequest(ocabci.ToRequestFlush(), cb) 235 } 236 237 func (cli *socketClient) InfoAsync(req types.RequestInfo, cb ResponseCallback) *ReqRes { 238 return cli.queueRequest(ocabci.ToRequestInfo(req), cb) 239 } 240 241 func (cli *socketClient) SetOptionAsync(req types.RequestSetOption, cb ResponseCallback) *ReqRes { 242 return cli.queueRequest(ocabci.ToRequestSetOption(req), cb) 243 } 244 245 func (cli *socketClient) DeliverTxAsync(req types.RequestDeliverTx, cb ResponseCallback) *ReqRes { 246 return cli.queueRequest(ocabci.ToRequestDeliverTx(req), cb) 247 } 248 249 func (cli *socketClient) CheckTxAsync(req types.RequestCheckTx, cb ResponseCallback) *ReqRes { 250 return cli.queueRequest(ocabci.ToRequestCheckTx(req), cb) 251 } 252 253 func (cli *socketClient) QueryAsync(req types.RequestQuery, cb ResponseCallback) *ReqRes { 254 return cli.queueRequest(ocabci.ToRequestQuery(req), cb) 255 } 256 257 func (cli *socketClient) CommitAsync(cb ResponseCallback) *ReqRes { 258 return cli.queueRequest(ocabci.ToRequestCommit(), cb) 259 } 260 261 func (cli *socketClient) InitChainAsync(req types.RequestInitChain, cb ResponseCallback) *ReqRes { 262 return cli.queueRequest(ocabci.ToRequestInitChain(req), cb) 263 } 264 265 func (cli *socketClient) BeginBlockAsync(req ocabci.RequestBeginBlock, cb ResponseCallback) *ReqRes { 266 return cli.queueRequest(ocabci.ToRequestBeginBlock(req), cb) 267 } 268 269 func (cli *socketClient) EndBlockAsync(req types.RequestEndBlock, cb ResponseCallback) *ReqRes { 270 return cli.queueRequest(ocabci.ToRequestEndBlock(req), cb) 271 } 272 273 func (cli *socketClient) BeginRecheckTxAsync(req ocabci.RequestBeginRecheckTx, cb ResponseCallback) *ReqRes { 274 return cli.queueRequest(ocabci.ToRequestBeginRecheckTx(req), cb) 275 } 276 277 func (cli *socketClient) EndRecheckTxAsync(req ocabci.RequestEndRecheckTx, cb ResponseCallback) *ReqRes { 278 return cli.queueRequest(ocabci.ToRequestEndRecheckTx(req), cb) 279 } 280 281 func (cli *socketClient) ListSnapshotsAsync(req types.RequestListSnapshots, cb ResponseCallback) *ReqRes { 282 return cli.queueRequest(ocabci.ToRequestListSnapshots(req), cb) 283 } 284 285 func (cli *socketClient) OfferSnapshotAsync(req types.RequestOfferSnapshot, cb ResponseCallback) *ReqRes { 286 return cli.queueRequest(ocabci.ToRequestOfferSnapshot(req), cb) 287 } 288 289 func (cli *socketClient) LoadSnapshotChunkAsync(req types.RequestLoadSnapshotChunk, cb ResponseCallback) *ReqRes { 290 return cli.queueRequest(ocabci.ToRequestLoadSnapshotChunk(req), cb) 291 } 292 293 func (cli *socketClient) ApplySnapshotChunkAsync(req types.RequestApplySnapshotChunk, cb ResponseCallback) *ReqRes { 294 return cli.queueRequest(ocabci.ToRequestApplySnapshotChunk(req), cb) 295 } 296 297 //---------------------------------------- 298 299 func (cli *socketClient) FlushSync() (*types.ResponseFlush, error) { 300 reqRes := cli.queueRequest(ocabci.ToRequestFlush(), nil) 301 if err := cli.Error(); err != nil { 302 return nil, err 303 } 304 reqRes.Wait() // NOTE: if we don't flush the queue, its possible to get stuck here 305 return reqRes.Response.GetFlush(), cli.Error() 306 } 307 308 func (cli *socketClient) EchoSync(msg string) (*types.ResponseEcho, error) { 309 reqres := cli.queueRequest(ocabci.ToRequestEcho(msg), nil) 310 if _, err := cli.FlushSync(); err != nil { 311 return nil, err 312 } 313 314 return reqres.Response.GetEcho(), cli.Error() 315 } 316 317 func (cli *socketClient) InfoSync(req types.RequestInfo) (*types.ResponseInfo, error) { 318 reqres := cli.queueRequest(ocabci.ToRequestInfo(req), nil) 319 if _, err := cli.FlushSync(); err != nil { 320 return nil, err 321 } 322 323 return reqres.Response.GetInfo(), cli.Error() 324 } 325 326 func (cli *socketClient) SetOptionSync(req types.RequestSetOption) (*types.ResponseSetOption, error) { 327 reqres := cli.queueRequest(ocabci.ToRequestSetOption(req), nil) 328 if _, err := cli.FlushSync(); err != nil { 329 return nil, err 330 } 331 332 return reqres.Response.GetSetOption(), cli.Error() 333 } 334 335 func (cli *socketClient) DeliverTxSync(req types.RequestDeliverTx) (*types.ResponseDeliverTx, error) { 336 reqres := cli.queueRequest(ocabci.ToRequestDeliverTx(req), nil) 337 if _, err := cli.FlushSync(); err != nil { 338 return nil, err 339 } 340 341 return reqres.Response.GetDeliverTx(), cli.Error() 342 } 343 344 func (cli *socketClient) CheckTxSync(req types.RequestCheckTx) (*ocabci.ResponseCheckTx, error) { 345 reqres := cli.queueRequest(ocabci.ToRequestCheckTx(req), nil) 346 if _, err := cli.FlushSync(); err != nil { 347 return nil, err 348 } 349 350 return reqres.Response.GetCheckTx(), cli.Error() 351 } 352 353 func (cli *socketClient) QuerySync(req types.RequestQuery) (*types.ResponseQuery, error) { 354 reqres := cli.queueRequest(ocabci.ToRequestQuery(req), nil) 355 if _, err := cli.FlushSync(); err != nil { 356 return nil, err 357 } 358 359 return reqres.Response.GetQuery(), cli.Error() 360 } 361 362 func (cli *socketClient) CommitSync() (*types.ResponseCommit, error) { 363 reqres := cli.queueRequest(ocabci.ToRequestCommit(), nil) 364 if _, err := cli.FlushSync(); err != nil { 365 return nil, err 366 } 367 368 return reqres.Response.GetCommit(), cli.Error() 369 } 370 371 func (cli *socketClient) InitChainSync(req types.RequestInitChain) (*types.ResponseInitChain, error) { 372 reqres := cli.queueRequest(ocabci.ToRequestInitChain(req), nil) 373 if _, err := cli.FlushSync(); err != nil { 374 return nil, err 375 } 376 377 return reqres.Response.GetInitChain(), cli.Error() 378 } 379 380 func (cli *socketClient) BeginBlockSync(req ocabci.RequestBeginBlock) (*types.ResponseBeginBlock, error) { 381 reqres := cli.queueRequest(ocabci.ToRequestBeginBlock(req), nil) 382 if _, err := cli.FlushSync(); err != nil { 383 return nil, err 384 } 385 386 return reqres.Response.GetBeginBlock(), cli.Error() 387 } 388 389 func (cli *socketClient) EndBlockSync(req types.RequestEndBlock) (*types.ResponseEndBlock, error) { 390 reqres := cli.queueRequest(ocabci.ToRequestEndBlock(req), nil) 391 if _, err := cli.FlushSync(); err != nil { 392 return nil, err 393 } 394 395 return reqres.Response.GetEndBlock(), cli.Error() 396 } 397 398 func (cli *socketClient) BeginRecheckTxSync(req ocabci.RequestBeginRecheckTx) (*ocabci.ResponseBeginRecheckTx, error) { 399 reqres := cli.queueRequest(ocabci.ToRequestBeginRecheckTx(req), nil) 400 if _, err := cli.FlushSync(); err != nil { 401 return nil, err 402 } 403 404 return reqres.Response.GetBeginRecheckTx(), cli.Error() 405 } 406 407 func (cli *socketClient) EndRecheckTxSync(req ocabci.RequestEndRecheckTx) (*ocabci.ResponseEndRecheckTx, error) { 408 reqres := cli.queueRequest(ocabci.ToRequestEndRecheckTx(req), nil) 409 if _, err := cli.FlushSync(); err != nil { 410 return nil, err 411 } 412 413 return reqres.Response.GetEndRecheckTx(), cli.Error() 414 } 415 416 func (cli *socketClient) ListSnapshotsSync(req types.RequestListSnapshots) (*types.ResponseListSnapshots, error) { 417 reqres := cli.queueRequest(ocabci.ToRequestListSnapshots(req), nil) 418 if _, err := cli.FlushSync(); err != nil { 419 return nil, err 420 } 421 422 return reqres.Response.GetListSnapshots(), cli.Error() 423 } 424 425 func (cli *socketClient) OfferSnapshotSync(req types.RequestOfferSnapshot) (*types.ResponseOfferSnapshot, error) { 426 reqres := cli.queueRequest(ocabci.ToRequestOfferSnapshot(req), nil) 427 if _, err := cli.FlushSync(); err != nil { 428 return nil, err 429 } 430 431 return reqres.Response.GetOfferSnapshot(), cli.Error() 432 } 433 434 func (cli *socketClient) LoadSnapshotChunkSync( 435 req types.RequestLoadSnapshotChunk) (*types.ResponseLoadSnapshotChunk, error) { 436 reqres := cli.queueRequest(ocabci.ToRequestLoadSnapshotChunk(req), nil) 437 if _, err := cli.FlushSync(); err != nil { 438 return nil, err 439 } 440 441 return reqres.Response.GetLoadSnapshotChunk(), cli.Error() 442 } 443 444 func (cli *socketClient) ApplySnapshotChunkSync( 445 req types.RequestApplySnapshotChunk) (*types.ResponseApplySnapshotChunk, error) { 446 reqres := cli.queueRequest(ocabci.ToRequestApplySnapshotChunk(req), nil) 447 if _, err := cli.FlushSync(); err != nil { 448 return nil, err 449 } 450 return reqres.Response.GetApplySnapshotChunk(), cli.Error() 451 } 452 453 //---------------------------------------- 454 455 func (cli *socketClient) queueRequest(req *ocabci.Request, cb ResponseCallback) *ReqRes { 456 reqres := NewReqRes(req, cb) 457 458 // TODO: set cli.err if reqQueue times out 459 cli.reqQueue <- reqres 460 461 // Maybe auto-flush, or unset auto-flush 462 switch req.Value.(type) { 463 case *ocabci.Request_Flush: 464 cli.flushTimer.Unset() 465 default: 466 cli.flushTimer.Set() 467 } 468 469 return reqres 470 } 471 472 func (cli *socketClient) flushQueue() { 473 cli.mtx.Lock() 474 defer cli.mtx.Unlock() 475 476 // mark all in-flight messages as resolved (they will get cli.Error()) 477 for req := cli.reqSent.Front(); req != nil; req = req.Next() { 478 reqres := req.Value.(*ReqRes) 479 reqres.wg.Done() 480 } 481 482 // mark all queued messages as resolved 483 LOOP: 484 for { 485 select { 486 case reqres := <-cli.reqQueue: 487 reqres.wg.Done() 488 default: 489 break LOOP 490 } 491 } 492 } 493 494 //---------------------------------------- 495 496 func resMatchesReq(req *ocabci.Request, res *ocabci.Response) (ok bool) { 497 switch req.Value.(type) { 498 case *ocabci.Request_Echo: 499 _, ok = res.Value.(*ocabci.Response_Echo) 500 case *ocabci.Request_Flush: 501 _, ok = res.Value.(*ocabci.Response_Flush) 502 case *ocabci.Request_Info: 503 _, ok = res.Value.(*ocabci.Response_Info) 504 case *ocabci.Request_SetOption: 505 _, ok = res.Value.(*ocabci.Response_SetOption) 506 case *ocabci.Request_DeliverTx: 507 _, ok = res.Value.(*ocabci.Response_DeliverTx) 508 case *ocabci.Request_CheckTx: 509 _, ok = res.Value.(*ocabci.Response_CheckTx) 510 case *ocabci.Request_Commit: 511 _, ok = res.Value.(*ocabci.Response_Commit) 512 case *ocabci.Request_Query: 513 _, ok = res.Value.(*ocabci.Response_Query) 514 case *ocabci.Request_InitChain: 515 _, ok = res.Value.(*ocabci.Response_InitChain) 516 case *ocabci.Request_BeginBlock: 517 _, ok = res.Value.(*ocabci.Response_BeginBlock) 518 case *ocabci.Request_EndBlock: 519 _, ok = res.Value.(*ocabci.Response_EndBlock) 520 case *ocabci.Request_BeginRecheckTx: 521 _, ok = res.Value.(*ocabci.Response_BeginRecheckTx) 522 case *ocabci.Request_EndRecheckTx: 523 _, ok = res.Value.(*ocabci.Response_EndRecheckTx) 524 case *ocabci.Request_ApplySnapshotChunk: 525 _, ok = res.Value.(*ocabci.Response_ApplySnapshotChunk) 526 case *ocabci.Request_LoadSnapshotChunk: 527 _, ok = res.Value.(*ocabci.Response_LoadSnapshotChunk) 528 case *ocabci.Request_ListSnapshots: 529 _, ok = res.Value.(*ocabci.Response_ListSnapshots) 530 case *ocabci.Request_OfferSnapshot: 531 _, ok = res.Value.(*ocabci.Response_OfferSnapshot) 532 } 533 return ok 534 } 535 536 func (cli *socketClient) stopForError(err error) { 537 if !cli.IsRunning() { 538 return 539 } 540 541 cli.mtx.Lock() 542 if cli.err == nil { 543 cli.err = err 544 } 545 cli.mtx.Unlock() 546 547 cli.Logger.Error(fmt.Sprintf("Stopping abci.socketClient for error: %v", err.Error())) 548 if err := cli.Stop(); err != nil { 549 cli.Logger.Error("Error stopping abci.socketClient", "err", err) 550 } 551 }