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  }