github.com/loomnetwork/gamechain@v0.0.0-20200406110549-36c47eb97a92/tools/gamechain-logger/cmd/runner.go (about) 1 package cmd 2 3 import ( 4 "log" 5 "strings" 6 "time" 7 8 raven "github.com/getsentry/raven-go" 9 "github.com/jinzhu/gorm" 10 "github.com/loomnetwork/gamechain/battleground" 11 "github.com/loomnetwork/go-loom/client" 12 "github.com/loomnetwork/go-loom/plugin/types" 13 "github.com/loomnetwork/gamechain/tools/gamechain-logger/models" 14 "github.com/pkg/errors" 15 ) 16 17 type Config struct { 18 ChainID string 19 ReadURI string 20 WriteURI string 21 ReconnectInterval time.Duration 22 PollInterval time.Duration 23 BlockInterval int 24 ContractName string 25 } 26 27 type Runner struct { 28 db *gorm.DB 29 stopC chan struct{} 30 errC chan error 31 cfg *Config 32 dappchainClient *client.DAppChainRPCClient 33 } 34 35 func NewRunner(db *gorm.DB, config *Config) *Runner { 36 return &Runner{ 37 db: db, 38 cfg: config, 39 stopC: make(chan struct{}), 40 errC: make(chan error), 41 dappchainClient: client.NewDAppChainRPCClient(config.ChainID, config.WriteURI, config.ReadURI), 42 } 43 } 44 45 // Start runs the loop to watch topic. It's a blocking call. 46 func (r *Runner) Start() { 47 for { 48 err := r.watchTopic() 49 if err == nil { 50 break 51 } 52 log.Printf("error: %v", err) 53 raven.CaptureErrorAndWait(err, map[string]string{}) 54 // delay before connecting again 55 time.Sleep(r.cfg.ReconnectInterval) 56 } 57 } 58 59 func (r *Runner) Stop() { 60 close(r.stopC) 61 } 62 63 func (r *Runner) Error() chan error { 64 return r.errC 65 } 66 67 func (r *Runner) watchTopic() error { 68 ticker := time.NewTicker(r.cfg.PollInterval) 69 for { 70 select { 71 case <-ticker.C: 72 height := models.ZbHeightCheck{} 73 err := r.db.Where(&models.ZbHeightCheck{Key: 1}). 74 Attrs(models.ZbHeightCheck{Key: 1}). 75 FirstOrCreate(&height). 76 Error 77 if err != nil { 78 return err 79 } 80 81 fromBlock := height.LastBlockHeight + 1 82 toBlock := fromBlock + uint64(r.cfg.BlockInterval) - 1 83 84 lastBlockHeight, err := r.dappchainClient.GetBlockHeight() 85 if err != nil { 86 return err 87 } 88 89 if toBlock > lastBlockHeight { 90 continue 91 } 92 result, err := r.dappchainClient.GetContractEvents(fromBlock, toBlock, r.cfg.ContractName) 93 if err != nil { 94 return err 95 } 96 97 tx := r.db.Begin() 98 if err := r.batchProcessEvents(tx, result.Events); err != nil { 99 tx.Rollback() 100 return err 101 } 102 103 height.LastBlockHeight = result.ToBlock 104 err = tx.Model(&models.ZbHeightCheck{}). 105 Update(height). 106 Error 107 if err != nil { 108 tx.Rollback() 109 return err 110 } 111 112 tx.Commit() 113 case <-r.stopC: 114 ticker.Stop() 115 return nil 116 } 117 118 } 119 } 120 121 func (r *Runner) batchProcessEvents(db *gorm.DB, events []*types.EventData) error { 122 if len(events) == 0 { 123 return nil 124 } 125 for _, event := range events { 126 for _, topic := range event.Topics { 127 var topicHandler TopicHandler 128 switch topic { 129 case battleground.TopicFindMatchEvent: 130 topicHandler = FindMatchHandler 131 case battleground.TopicAcceptMatchEvent: 132 topicHandler = AcceptMatchHandler 133 case battleground.TopicCreateDeckEvent: 134 topicHandler = CreateDeckHandler 135 case battleground.TopicEditDeckEvent: 136 topicHandler = EditDeckHandler 137 case battleground.TopicDeleteDeckEvent: 138 topicHandler = DeleteDeckHandler 139 default: 140 if strings.HasPrefix(topic, "match:") { 141 topicHandler = MatchHandler 142 } 143 } 144 145 if topicHandler != nil { 146 err := topicHandler(event, db) 147 if err != nil { 148 err = errors.Wrapf(err, "error calling topic handler") 149 log.Printf("error: %s from event: %+v", err, event) 150 return err 151 } 152 } 153 } 154 } 155 156 return nil 157 }