github.com/okex/exchain@v1.8.0/libs/tendermint/state/txindex/indexer_service.go (about) 1 package txindex 2 3 import ( 4 "context" 5 6 "github.com/okex/exchain/libs/tendermint/libs/service" 7 "github.com/okex/exchain/libs/tendermint/state/indexer" 8 9 "github.com/okex/exchain/libs/tendermint/types" 10 ) 11 12 const ( 13 subscriber = "IndexerService" 14 ) 15 16 // IndexerService connects event bus and transaction indexer together in order 17 // to index transactions coming from event bus. 18 type IndexerService struct { 19 service.BaseService 20 21 idr TxIndexer 22 blockIdxr indexer.BlockIndexer 23 eventBus *types.EventBus 24 quit chan struct{} 25 } 26 27 // NewIndexerService returns a new service instance. 28 func NewIndexerService(idr TxIndexer, bidr indexer.BlockIndexer, eventBus *types.EventBus) *IndexerService { 29 is := &IndexerService{idr: idr, eventBus: eventBus} 30 is.blockIdxr = bidr 31 is.BaseService = *service.NewBaseService(nil, "IndexerService", is) 32 is.quit = make(chan struct{}) 33 return is 34 } 35 36 // OnStart implements service.Service by subscribing for all transactions 37 // and indexing them by events. 38 func (is *IndexerService) OnStart() error { 39 // Use SubscribeUnbuffered here to ensure both subscriptions does not get 40 // cancelled due to not pulling messages fast enough. Cause this might 41 // sometimes happen when there are no other subscribers. 42 43 blockHeadersSub, err := is.eventBus.SubscribeUnbuffered( 44 context.Background(), 45 subscriber, 46 types.EventQueryNewBlockHeader) 47 if err != nil { 48 return err 49 } 50 51 txsSub, err := is.eventBus.SubscribeUnbuffered(context.Background(), subscriber, types.EventQueryTx) 52 if err != nil { 53 return err 54 } 55 56 go func() { 57 for { 58 select { 59 case msg := <-blockHeadersSub.Out(): 60 eventDataHeader := msg.Data().(types.EventDataNewBlockHeader) 61 height := eventDataHeader.Header.Height 62 batch := NewBatch(eventDataHeader.NumTxs) 63 for i := int64(0); i < eventDataHeader.NumTxs; i++ { 64 msg2 := <-txsSub.Out() 65 txResult := msg2.Data().(types.EventDataTx).TxResult 66 if err = batch.Add(&txResult); err != nil { 67 is.Logger.Error("Can't add tx to batch", 68 "height", height, 69 "index", txResult.Index, 70 "err", err) 71 } 72 } 73 74 if err := is.blockIdxr.Index(eventDataHeader); err != nil { 75 is.Logger.Error("failed to index block", "height", height, "err", err) 76 } else { 77 is.Logger.Info("indexed block", "height", height) 78 } 79 80 if err = is.idr.AddBatch(batch); err != nil { 81 is.Logger.Error("Failed to index block", "height", height, "err", err) 82 } else { 83 is.Logger.Info("Indexed block", "height", height) 84 } 85 case <-blockHeadersSub.Cancelled(): 86 close(is.quit) 87 return 88 } 89 90 } 91 }() 92 return nil 93 } 94 95 // OnStop implements service.Service by unsubscribing from all transactions. 96 func (is *IndexerService) OnStop() { 97 if is.eventBus.IsRunning() { 98 _ = is.eventBus.UnsubscribeAll(context.Background(), subscriber) 99 } 100 } 101 102 func (is *IndexerService) Wait() { 103 <-is.quit 104 } 105 106 func (is *IndexerService) GetBlockIndexer() indexer.BlockIndexer { 107 return is.blockIdxr 108 }