github.com/loomnetwork/gamechain@v0.0.0-20200406110549-36c47eb97a92/tools/gamechain-logger/cmd/handler.go (about) 1 package cmd 2 3 import ( 4 "encoding/json" 5 "fmt" 6 "github.com/loomnetwork/gamechain/types/zb/zb_calls" 7 "github.com/loomnetwork/gamechain/types/zb/zb_data" 8 "log" 9 "time" 10 11 "github.com/gogo/protobuf/proto" 12 "github.com/jinzhu/gorm" 13 "github.com/loomnetwork/go-loom/plugin/types" 14 "github.com/loomnetwork/gamechain/tools/gamechain-logger/models" 15 "github.com/pkg/errors" 16 ) 17 18 const ( 19 TopicMatchEventPrefix = "match:" 20 ) 21 22 type TopicHandler func(eventData *types.EventData, db *gorm.DB) error 23 24 func FindMatchHandler(eventData *types.EventData, db *gorm.DB) error { 25 var event zb_data.PlayerActionEvent 26 if err := proto.Unmarshal(eventData.EncodedBody, &event); err != nil { 27 return err 28 } 29 30 match := event.Match 31 if match == nil { 32 return fmt.Errorf("match is nil") 33 } 34 if len(match.PlayerStates) < 2 { 35 return fmt.Errorf("expected player state length 2") 36 } 37 38 m := models.Match{ 39 ID: match.Id, 40 Player1ID: match.PlayerStates[0].Id, 41 Player2ID: match.PlayerStates[1].Id, 42 Player1Accepted: match.PlayerStates[0].MatchAccepted, 43 Player2Accepted: match.PlayerStates[1].MatchAccepted, 44 Player1DeckID: match.PlayerStates[0].Deck.Id, 45 Player2DeckID: match.PlayerStates[1].Deck.Id, 46 Status: match.Status.String(), 47 Version: match.Version, 48 RandomSeed: match.RandomSeed, 49 BlockHeight: eventData.BlockHeight, 50 BlockTime: time.Unix(eventData.BlockTime, 0), 51 CreatedAt: time.Now(), 52 } 53 54 if err := db.Save(&m).Error; err != nil { 55 return err 56 } 57 58 return nil 59 } 60 61 func AcceptMatchHandler(eventData *types.EventData, db *gorm.DB) error { 62 var event zb_data.PlayerActionEvent 63 if err := proto.Unmarshal(eventData.EncodedBody, &event); err != nil { 64 return err 65 } 66 67 match := event.Match 68 if match == nil { 69 return fmt.Errorf("match is nil") 70 } 71 if len(match.PlayerStates) < 2 { 72 return fmt.Errorf("expected player state length 2") 73 } 74 75 m := models.Match{ 76 ID: match.Id, 77 Player1ID: match.PlayerStates[0].Id, 78 Player2ID: match.PlayerStates[1].Id, 79 Player1Accepted: match.PlayerStates[0].MatchAccepted, 80 Player2Accepted: match.PlayerStates[1].MatchAccepted, 81 Player1DeckID: match.PlayerStates[0].Deck.Id, 82 Player2DeckID: match.PlayerStates[1].Deck.Id, 83 Status: match.Status.String(), 84 Version: match.Version, 85 RandomSeed: match.RandomSeed, 86 BlockHeight: eventData.BlockHeight, 87 BlockTime: time.Unix(eventData.BlockTime, 0), 88 } 89 if err := db.Omit("created_at").Save(&m).Error; err != nil { 90 return err 91 } 92 93 return nil 94 } 95 96 func CreateDeckHandler(eventData *types.EventData, db *gorm.DB) error { 97 var event zb_calls.CreateDeckEvent 98 if err := proto.Unmarshal(eventData.EncodedBody, &event); err != nil { 99 return err 100 } 101 102 deck := event.Deck 103 if deck == nil { 104 return fmt.Errorf("deck is nil") 105 } 106 107 log.Printf("Saving deck with deck ID %d, userid %s, name %s to DB", event.Deck.Id, event.UserId, event.Deck.Name) 108 109 cards, err := json.Marshal(event.Deck.Cards) 110 if err != nil { 111 return err 112 } 113 114 d := models.Deck{ 115 UserID: event.UserId, 116 DeckID: deck.Id, 117 Name: deck.Name, 118 HeroID: deck.OverlordId, 119 Cards: cards, 120 PrimarySkillID: int(deck.PrimarySkill), 121 SecondarySkillID: int(deck.SecondarySkill), 122 Version: event.Version, 123 SenderAddress: event.SenderAddress, 124 BlockHeight: eventData.BlockHeight, 125 IsDeleted: false, 126 } 127 if err := db.Save(&d).Error; err != nil { 128 return err 129 } 130 131 return nil 132 } 133 134 func EditDeckHandler(eventData *types.EventData, db *gorm.DB) error { 135 var event zb_calls.EditDeckEvent 136 137 if err := proto.Unmarshal(eventData.EncodedBody, &event); err != nil { 138 return err 139 } 140 deck := event.Deck 141 if deck == nil { 142 return fmt.Errorf("deck is nil") 143 } 144 145 cards, err := json.Marshal(event.Deck.Cards) 146 if err != nil { 147 return err 148 } 149 150 d := models.Deck{ 151 UserID: event.UserId, 152 DeckID: deck.Id, 153 Name: deck.Name, 154 HeroID: deck.OverlordId, 155 Cards: cards, 156 PrimarySkillID: int(deck.PrimarySkill), 157 SecondarySkillID: int(deck.SecondarySkill), 158 Version: event.Version, 159 SenderAddress: event.SenderAddress, 160 BlockHeight: eventData.BlockHeight, 161 IsDeleted: false, 162 } 163 if err := db.Save(&d).Error; err != nil { 164 return err 165 } 166 167 return nil 168 } 169 170 func DeleteDeckHandler(eventData *types.EventData, db *gorm.DB) error { 171 var event zb_calls.DeleteDeckEvent 172 if err := proto.Unmarshal(eventData.EncodedBody, &event); err != nil { 173 return err 174 } 175 log.Printf("Deleting deck with deck ID %d, userid %s from DB", event.DeckId, event.UserId) 176 177 err := db.Model(&models.Deck{}). 178 Where(&models.Deck{UserID: event.UserId, DeckID: event.DeckId}). 179 Updates(models.Deck{IsDeleted: true}). 180 Error 181 if err != nil { 182 return err 183 } 184 185 return nil 186 } 187 188 // TODO: seems this is not used anymore at all? can it be removed? 189 func EndgameHandler(eventData *types.EventData, db *gorm.DB) error { 190 var event zb_data.PlayerActionEvent 191 if err := proto.Unmarshal(eventData.EncodedBody, &event); err != nil { 192 return err 193 } 194 195 match := models.Match{} 196 err := db.Where(&models.Match{ID: event.Match.Id}).First(&match).Error 197 if err != nil { 198 return err 199 } 200 201 match.WinnerID = event.Block.List[0].GetEndGame().WinnerId 202 match.Status = event.Match.Status.String() 203 match.BlockHeight = eventData.BlockHeight 204 205 if err := db.Omit("created_at").Save(&match).Error; err != nil { 206 return err 207 } 208 209 return nil 210 } 211 212 func MatchHandler(eventData *types.EventData, db *gorm.DB) error { 213 var event zb_data.PlayerActionEvent 214 if err := proto.Unmarshal(eventData.EncodedBody, &event); err != nil { 215 return err 216 } 217 218 match := event.Match 219 if match == nil { 220 return fmt.Errorf("match is nil") 221 } 222 topic := fmt.Sprintf(TopicMatchEventPrefix + ":%d", match.Id) 223 replay, err := writeReplayFile(topic, event) 224 if err != nil { 225 return errors.Wrap(err, "Error writing replay file: ") 226 } 227 228 // update match status 229 var winnerID string 230 if event.Block != nil && len(event.Block.List) > 0 && event.Block.List[0].GetEndGame() != nil { 231 winnerID = event.Block.List[0].GetEndGame().WinnerId 232 } 233 234 var existingMatch models.Match 235 notfound := db.Where(&models.Match{ID: match.Id}). 236 First(&existingMatch). 237 RecordNotFound() 238 239 if !notfound { 240 existingMatch.WinnerID = winnerID 241 existingMatch.Status = match.Status.String() 242 // since we just add blocktime, hav to check for compatibility 243 if existingMatch.BlockTime.IsZero() { 244 existingMatch.BlockTime = time.Unix(eventData.BlockTime, 0) 245 } 246 if err := db.Save(&existingMatch).Error; err != nil { 247 return err 248 } 249 } 250 251 dbReplay := models.Replay{} 252 err = db.Where(&models.Replay{MatchID: match.Id}).First(&dbReplay).Error 253 if err == nil { 254 if replay != nil { 255 dbReplay.ReplayJSON = replay 256 } 257 dbReplay.BlockHeight = eventData.BlockHeight 258 dbReplay.BlockTime = time.Unix(eventData.BlockTime, 0) 259 db.Save(&dbReplay) 260 } else if gorm.IsRecordNotFoundError(err) { 261 // insert 262 dbReplay.MatchID = match.Id 263 if replay != nil { 264 dbReplay.ReplayJSON = replay 265 } 266 dbReplay.BlockHeight = eventData.BlockHeight 267 dbReplay.BlockTime = time.Unix(eventData.BlockTime, 0) 268 db.Create(&dbReplay) 269 } else { 270 return err 271 } 272 273 return nil 274 }