diff --git a/go.mod b/go.mod index aeae659..8642a2c 100644 --- a/go.mod +++ b/go.mod @@ -3,8 +3,7 @@ module game-player-data go 1.23 require ( - github.com/emortalmc/proto-specs/gen/go v0.0.0-20240905105617-8c6a55ee2bae - github.com/gogo/protobuf v1.3.2 + github.com/emortalmc/proto-specs/gen/go v0.0.0-20240920201852-8d931ec7a9aa github.com/google/uuid v1.3.0 github.com/grpc-ecosystem/go-grpc-middleware v1.4.0 github.com/segmentio/kafka-go v0.4.39 @@ -12,6 +11,7 @@ require ( go.mongodb.org/mongo-driver v1.11.6 go.uber.org/zap v1.24.0 google.golang.org/grpc v1.55.0 + google.golang.org/protobuf v1.30.0 ) require ( @@ -43,7 +43,6 @@ require ( golang.org/x/sys v0.8.0 // indirect golang.org/x/text v0.9.0 // indirect google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1 // indirect - google.golang.org/protobuf v1.30.0 // indirect gopkg.in/ini.v1 v1.67.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/go.sum b/go.sum index 6d85612..7daac21 100644 --- a/go.sum +++ b/go.sum @@ -51,16 +51,10 @@ github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnht github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/emortalmc/proto-specs/gen/go v0.0.0-20230602153610-3e1cd1adcd5a h1:8Koes2hRKavzHtFB6+mgjlZesdkCnZ4RQ7kWK+xv83M= -github.com/emortalmc/proto-specs/gen/go v0.0.0-20230602153610-3e1cd1adcd5a/go.mod h1:se+tHcK9FWxeadkxLF5uj+SPauEye0X+Iq6cGczXGJY= -github.com/emortalmc/proto-specs/gen/go v0.0.0-20230916193435-6abf652a5c2f h1:DvOyf+SLgDoqLwDlV3IqDetZO7DwANJZm9clQGHD67g= -github.com/emortalmc/proto-specs/gen/go v0.0.0-20230916193435-6abf652a5c2f/go.mod h1:se+tHcK9FWxeadkxLF5uj+SPauEye0X+Iq6cGczXGJY= -github.com/emortalmc/proto-specs/gen/go v0.0.0-20230916202652-8975e470ce34 h1:q095naqNtgsBaI8o1TgkIo3U1pkSbIEnRW1KqWWu8Ww= -github.com/emortalmc/proto-specs/gen/go v0.0.0-20230916202652-8975e470ce34/go.mod h1:se+tHcK9FWxeadkxLF5uj+SPauEye0X+Iq6cGczXGJY= -github.com/emortalmc/proto-specs/gen/go v0.0.0-20240905105043-b1abec6eb8cf h1:IdMv84dOIWFMLeIYifQKxc1EmQybknwtiyTbBDrUnvc= -github.com/emortalmc/proto-specs/gen/go v0.0.0-20240905105043-b1abec6eb8cf/go.mod h1:se+tHcK9FWxeadkxLF5uj+SPauEye0X+Iq6cGczXGJY= -github.com/emortalmc/proto-specs/gen/go v0.0.0-20240905105617-8c6a55ee2bae h1:Y9ofcDfHuJbXUjTP/5+jMKOPpIysHhDWibpG0nYhy98= -github.com/emortalmc/proto-specs/gen/go v0.0.0-20240905105617-8c6a55ee2bae/go.mod h1:se+tHcK9FWxeadkxLF5uj+SPauEye0X+Iq6cGczXGJY= +github.com/emortalmc/proto-specs/gen/go v0.0.0-20240909152322-b05808d73899 h1:iz2XOymnELhMCFCmRd3CyhkbOPaqhpK8vaLfn1dN2XI= +github.com/emortalmc/proto-specs/gen/go v0.0.0-20240909152322-b05808d73899/go.mod h1:se+tHcK9FWxeadkxLF5uj+SPauEye0X+Iq6cGczXGJY= +github.com/emortalmc/proto-specs/gen/go v0.0.0-20240920201852-8d931ec7a9aa h1:twr+Yjdt3DCPnawjyEzi9ij/SXHk0IUY8i/EkVxNoew= +github.com/emortalmc/proto-specs/gen/go v0.0.0-20240920201852-8d931ec7a9aa/go.mod h1:se+tHcK9FWxeadkxLF5uj+SPauEye0X+Iq6cGczXGJY= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= diff --git a/internal/app/game_player_data.go b/internal/app/game_player_data.go index 5b03066..df7562a 100644 --- a/internal/app/game_player_data.go +++ b/internal/app/game_player_data.go @@ -20,22 +20,16 @@ func Run(cfg *config.Config, logger *zap.SugaredLogger) { repoCtx, repoCancel := context.WithCancel(ctx) repoWg := &sync.WaitGroup{} - repo, err := repository.NewMongoRepository(repoCtx, logger, repoWg, cfg.MongoDB) + mongoDB, err := repository.CreateDatabase(repoCtx, cfg.MongoDB, repoWg, logger) if err != nil { - logger.Fatalw("failed to create repository", err) + logger.Fatalw("failed to create database", err) } - //if err := repo.SaveBlockSumoPlayer(ctx, &model.BlockSumoData{ - // PlayerId: uuid.MustParse("8d36737e-1c0a-4a71-87de-9906f577845e"), - // BlockSlot: 1, - // ShearsSlot: 2, - //}); err != nil { - // panic(err) - //} + repoColl := repository.NewGamePlayerDataRepoColl(mongoDB) - kafka.NewConsumer(ctx, wg, cfg.Kafka, logger, repo) + kafka.NewConsumer(ctx, wg, cfg.Kafka, logger, repoColl) - service.RunServices(ctx, logger, wg, cfg, repo) + service.RunServices(ctx, logger, wg, cfg, repoColl) wg.Wait() logger.Info("shutting down") diff --git a/internal/config/gamemode.go b/internal/config/gamemode.go deleted file mode 100644 index 1b21cae..0000000 --- a/internal/config/gamemode.go +++ /dev/null @@ -1,14 +0,0 @@ -package config - -import ( - "game-player-data/internal/repository/model" - "github.com/google/uuid" -) - -func CreateDefaultBlockSumoData(playerId uuid.UUID) *model.BlockSumoData { - return &model.BlockSumoData{ - PlayerId: playerId, - BlockSlot: 2, - ShearsSlot: 1, - } -} diff --git a/internal/kafka/consumer.go b/internal/kafka/consumer.go index 68b57e0..4da9cee 100644 --- a/internal/kafka/consumer.go +++ b/internal/kafka/consumer.go @@ -2,16 +2,15 @@ package kafka import ( "context" - "errors" "fmt" "game-player-data/internal/config" "game-player-data/internal/repository" + "game-player-data/internal/repository/model" pbmsg "github.com/emortalmc/proto-specs/gen/go/message/gameplayerdata" pbmodel "github.com/emortalmc/proto-specs/gen/go/model/gameplayerdata" "github.com/emortalmc/proto-specs/gen/go/nongenerated/kafkautils" "github.com/google/uuid" "github.com/segmentio/kafka-go" - "go.mongodb.org/mongo-driver/mongo" "go.uber.org/zap" "google.golang.org/protobuf/proto" "google.golang.org/protobuf/types/known/anypb" @@ -22,13 +21,13 @@ const GamePlayerDataTopic = "game-player-data" type consumer struct { logger *zap.SugaredLogger - repo repository.Repository + repos *repository.GameDataRepoColl reader *kafka.Reader } func NewConsumer(ctx context.Context, wg *sync.WaitGroup, cfg *config.KafkaConfig, logger *zap.SugaredLogger, - repo repository.Repository) { + repos *repository.GameDataRepoColl) { reader := kafka.NewReader(kafka.ReaderConfig{ Brokers: []string{fmt.Sprintf("%s:%d", cfg.Host, cfg.Port)}, @@ -45,7 +44,7 @@ func NewConsumer(ctx context.Context, wg *sync.WaitGroup, cfg *config.KafkaConfi c := &consumer{ logger: logger, - repo: repo, + repos: repos, reader: reader, } @@ -77,6 +76,11 @@ func (c *consumer) handleUpdateGamePlayerDataMessage(ctx context.Context, _ *kaf switch msg.GameMode { case pbmodel.GameDataGameMode_BLOCK_SUMO: err = c.handleBlockSumoUpdate(ctx, pId, msg) + case pbmodel.GameDataGameMode_MARATHON: + err = c.handleMarathonUpdate(ctx, pId, msg) + + default: + c.logger.Errorw("unsupported game mode", "gameMode", msg.GameMode) } if err != nil { @@ -85,15 +89,34 @@ func (c *consumer) handleUpdateGamePlayerDataMessage(ctx context.Context, _ *kaf } } -func (c *consumer) handleBlockSumoUpdate(ctx context.Context, pId uuid.UUID, msg *pbmsg.UpdateGamePlayerDataMessage) error { - player, err := c.repo.GetBlockSumoData(ctx, pId) - +func (c *consumer) handleMarathonUpdate(ctx context.Context, pId uuid.UUID, msg *pbmsg.UpdateGamePlayerDataMessage) error { + gameData, err := c.repos.Marathon.GetOrDefault(ctx, pId, &model.MarathonData{BaseGameData: model.BaseGameData{PlayerId: pId}}) if err != nil { - if !errors.Is(err, mongo.ErrNoDocuments) { - return fmt.Errorf("failed to get block sumo data: %w", err) + return fmt.Errorf("failed to get block sumo data: %w", err) + + } + + msgData := &pbmodel.V1MarathonData{} + + if err := anypb.UnmarshalTo(msg.Data, msgData, proto.UnmarshalOptions{}); err != nil { + return fmt.Errorf("failed to unmarshal data: %w", err) + } + + for _, path := range msg.DataMask.Paths { + switch path { + case "block_palette": + gameData.BlockPalette = msgData.BlockPalette + case "time": + gameData.Time = msgData.Time } + } - player = config.CreateDefaultBlockSumoData(pId) + return c.repos.Marathon.Save(ctx, gameData) +} +func (c *consumer) handleBlockSumoUpdate(ctx context.Context, pId uuid.UUID, msg *pbmsg.UpdateGamePlayerDataMessage) error { + gameData, err := c.repos.BlockSumo.GetOrDefault(ctx, pId, &model.BlockSumoData{BaseGameData: model.BaseGameData{PlayerId: pId}}) + if err != nil { + return fmt.Errorf("failed to get block sumo data: %w", err) } msgData := &pbmodel.V1BlockSumoPlayerData{} @@ -105,11 +128,11 @@ func (c *consumer) handleBlockSumoUpdate(ctx context.Context, pId uuid.UUID, msg for _, path := range msg.DataMask.Paths { switch path { case "block_slot": - player.BlockSlot = msgData.BlockSlot + gameData.BlockSlot = msgData.BlockSlot case "shears_slot": - player.ShearsSlot = msgData.ShearsSlot + gameData.ShearsSlot = msgData.ShearsSlot } } - return c.repo.SaveBlockSumoPlayer(ctx, player) + return c.repos.BlockSumo.Save(ctx, gameData) } diff --git a/internal/repository/game_data_mongo.go b/internal/repository/game_data_mongo.go new file mode 100644 index 0000000..82fbd9c --- /dev/null +++ b/internal/repository/game_data_mongo.go @@ -0,0 +1,104 @@ +package repository + +import ( + "context" + "errors" + "fmt" + "game-player-data/internal/repository/model" + "game-player-data/internal/utils" + "github.com/google/uuid" + "go.mongodb.org/mongo-driver/bson" + "go.mongodb.org/mongo-driver/mongo" + "go.mongodb.org/mongo-driver/mongo/options" + "reflect" + "time" +) + +const ( + blockSumoCollection = "blockSumo" + towerDefenceCollection = "towerDefence" + minesweeperCollection = "minesweeper" + marathonCollection = "marathon" +) + +var typeToCollection = map[reflect.Type]string{ + reflect.TypeOf(&model.BlockSumoData{}): blockSumoCollection, + reflect.TypeOf(&model.TowerDefenceData{}): towerDefenceCollection, + reflect.TypeOf(&model.MinesweeperData{}): minesweeperCollection, + reflect.TypeOf(&model.MarathonData{}): marathonCollection, +} + +type mongoGameDataRepository[T model.GameData] struct { + coll *mongo.Collection + + example T +} + +func NewMongoGameDataRepository[T model.GameData](db *mongo.Database, example T) GameDataRepository[T] { + collName, ok := typeToCollection[reflect.TypeOf(example)] + if !ok { + panic(fmt.Sprintf("no collection found for type %T", example)) + } + + return &mongoGameDataRepository[T]{ + coll: db.Collection(collName), + } +} + +func (m *mongoGameDataRepository[T]) Get(ctx context.Context, playerID uuid.UUID) (T, error) { + ctx, cancel := context.WithTimeout(ctx, 5*time.Second) + defer cancel() + + example := reflect.New(reflect.TypeOf(m.example).Elem()).Interface().(T) + + res := m.coll.FindOne(ctx, bson.M{"_id": playerID}) + if err := res.Decode(&example); err != nil { + return example, fmt.Errorf("failed to decode data: %w", err) + } + + return example, nil +} + +func (m *mongoGameDataRepository[T]) GetOrDefault(ctx context.Context, playerID uuid.UUID, defaultData T) (T, error) { + res, err := m.Get(ctx, playerID) + if err != nil { + if errors.Is(err, mongo.ErrNoDocuments) { + return defaultData, nil + } + + return m.example, err + } + + return res, nil +} + +func (m *mongoGameDataRepository[T]) GetMultiple(ctx context.Context, playerIds []uuid.UUID) ([]T, error) { + ctx, cancel := context.WithTimeout(ctx, 5*time.Second) + defer cancel() + + cursor, err := m.coll.Find(ctx, bson.M{"_id": bson.M{"$in": playerIds}}) + if err != nil { + return nil, err + } + + exampleType := reflect.TypeOf(m.example) + sliceType := reflect.SliceOf(exampleType) + data := reflect.MakeSlice(sliceType, 0, 0).Interface().([]T) + if err := cursor.All(ctx, &data); err != nil { + return nil, err + } + + return data, nil +} + +func (m *mongoGameDataRepository[T]) Save(ctx context.Context, data T) error { + ctx, cancel := context.WithTimeout(ctx, 5*time.Second) + defer cancel() + + _, err := m.coll.ReplaceOne(ctx, bson.M{"_id": data.PlayerID()}, data, &options.ReplaceOptions{Upsert: utils.PointerOf(true)}) + if err != nil { + return fmt.Errorf("failed to insert data: %w", err) + } + + return nil +} diff --git a/internal/repository/model/model.go b/internal/repository/model/model.go index 78d39b5..0b76949 100644 --- a/internal/repository/model/model.go +++ b/internal/repository/model/model.go @@ -8,10 +8,19 @@ import ( type GameData interface { ToAnyProto() (*anypb.Any, error) + PlayerID() uuid.UUID } -type BlockSumoData struct { +type BaseGameData struct { PlayerId uuid.UUID `bson:"_id"` +} + +func (d *BaseGameData) PlayerID() uuid.UUID { + return d.PlayerId +} + +type BlockSumoData struct { + BaseGameData `bson:",inline"` BlockSlot uint32 `bson:"blockSlot"` ShearsSlot uint32 `bson:"shearsSlot"` @@ -30,9 +39,23 @@ func (d *BlockSumoData) FromProto(pId uuid.UUID, data *gameplayerdata.V1BlockSum d.ShearsSlot = data.ShearsSlot } +type MarathonData struct { + BaseGameData `bson:",inline"` + + Time string + BlockPalette string +} + +func (d *MarathonData) ToAnyProto() (*anypb.Any, error) { + return anypb.New(&gameplayerdata.V1MarathonData{ + Time: d.Time, + BlockPalette: d.BlockPalette, + }) +} + // MinesweeperData TODO type MinesweeperData struct { - PlayerId uuid.UUID `bson:"_id"` + BaseGameData `bson:",inline"` } // TODO diff --git a/internal/repository/mongo.go b/internal/repository/mongo.go index 2e9ac5f..80cd4fe 100644 --- a/internal/repository/mongo.go +++ b/internal/repository/mongo.go @@ -3,49 +3,25 @@ package repository import ( "context" "game-player-data/internal/config" - "game-player-data/internal/repository/model" "game-player-data/internal/repository/registrytypes" - "game-player-data/internal/utils" - "github.com/google/uuid" "go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/bson/bsoncodec" "go.mongodb.org/mongo-driver/mongo" "go.mongodb.org/mongo-driver/mongo/options" "go.uber.org/zap" "sync" - "time" ) const ( databaseName = "game-player-data" - - blockSumoCollection = "blockSumo" - towerDefenceCollection = "towerDefence" - minesweeperCollection = "minesweeper" ) -type mongoRepository struct { - database *mongo.Database - - blockSumoCollection *mongo.Collection - towerDefenceCollection *mongo.Collection - minesweeperCollection *mongo.Collection -} - -func NewMongoRepository(ctx context.Context, logger *zap.SugaredLogger, wg *sync.WaitGroup, cfg *config.MongoDBConfig) (Repository, error) { +func CreateDatabase(ctx context.Context, cfg *config.MongoDBConfig, wg *sync.WaitGroup, logger *zap.SugaredLogger) (*mongo.Database, error) { client, err := mongo.Connect(ctx, options.Client().ApplyURI(cfg.URI).SetRegistry(createCodecRegistry())) if err != nil { return nil, err } - database := client.Database(databaseName) - repo := &mongoRepository{ - database: database, - blockSumoCollection: database.Collection(blockSumoCollection), - towerDefenceCollection: database.Collection(towerDefenceCollection), - minesweeperCollection: database.Collection(minesweeperCollection), - } - wg.Add(1) go func() { defer wg.Done() @@ -55,89 +31,7 @@ func NewMongoRepository(ctx context.Context, logger *zap.SugaredLogger, wg *sync } }() - return repo, nil -} - -func (m *mongoRepository) GetBlockSumoData(ctx context.Context, playerId uuid.UUID) (*model.BlockSumoData, error) { - result := m.getData(ctx, playerId, m.blockSumoCollection) - - var data model.BlockSumoData - if err := result.Decode(&data); err != nil { - return nil, err - } - - return &data, nil -} - -func (m *mongoRepository) GetBlockSumoDataForPlayers(ctx context.Context, playerIds []uuid.UUID) ([]*model.BlockSumoData, error) { - ctx, cancel := context.WithTimeout(ctx, 5*time.Second) - defer cancel() - - cursor, err := m.blockSumoCollection.Find(ctx, bson.M{"_id": bson.M{"$in": playerIds}}) - if err != nil { - return nil, err - } - - var data []*model.BlockSumoData - if err := cursor.All(ctx, &data); err != nil { - return nil, err - } - - return data, nil -} - -func (m *mongoRepository) SaveBlockSumoPlayer(ctx context.Context, data *model.BlockSumoData) error { - return m.saveData(ctx, data.PlayerId, data, m.blockSumoCollection) -} - -func (m *mongoRepository) GetTowerDefencePlayer(ctx context.Context, playerId uuid.UUID) (*model.TowerDefenceData, error) { - result := m.getData(ctx, playerId, m.blockSumoCollection) - - var data model.TowerDefenceData - if err := result.Decode(&data); err != nil { - return nil, err - } - - return &data, nil -} - -func (m *mongoRepository) SaveTowerDefencePlayer(ctx context.Context, data *model.TowerDefenceData) error { - return m.saveData(ctx, data.PlayerId, data, m.towerDefenceCollection) -} - -func (m *mongoRepository) GetMinesweeperPlayer(ctx context.Context, playerId uuid.UUID) (*model.MinesweeperData, error) { - result := m.getData(ctx, playerId, m.blockSumoCollection) - - var data model.MinesweeperData - if err := result.Decode(&data); err != nil { - return nil, err - } - - return &data, nil -} - -func (m *mongoRepository) SaveMinesweeperPlayer(ctx context.Context, data *model.MinesweeperData) error { - return m.saveData(ctx, data.PlayerId, data, m.minesweeperCollection) -} - -func (m *mongoRepository) getData(ctx context.Context, playerId uuid.UUID, collection *mongo.Collection) *mongo.SingleResult { - ctx, cancel := context.WithTimeout(ctx, 5*time.Second) - defer cancel() - - return collection.FindOne(ctx, bson.M{"_id": playerId}) -} - -func (m *mongoRepository) saveData(ctx context.Context, playerId uuid.UUID, data interface{}, collection *mongo.Collection) error { - ctx, cancel := context.WithTimeout(ctx, 5*time.Second) - defer cancel() - - filter := bson.M{"_id": playerId} - - if _, err := collection.ReplaceOne(ctx, filter, data, &options.ReplaceOptions{Upsert: utils.PointerOf(true)}); err != nil { - return err - } - - return nil + return client.Database(databaseName), nil } func createCodecRegistry() *bsoncodec.Registry { diff --git a/internal/repository/public.go b/internal/repository/public.go index 1317150..e35546a 100644 --- a/internal/repository/public.go +++ b/internal/repository/public.go @@ -4,16 +4,24 @@ import ( "context" "game-player-data/internal/repository/model" "github.com/google/uuid" + "go.mongodb.org/mongo-driver/mongo" ) -type Repository interface { - GetBlockSumoData(ctx context.Context, playerId uuid.UUID) (*model.BlockSumoData, error) - GetBlockSumoDataForPlayers(ctx context.Context, playerIds []uuid.UUID) ([]*model.BlockSumoData, error) - SaveBlockSumoPlayer(ctx context.Context, data *model.BlockSumoData) error +type GameDataRepository[T model.GameData] interface { + Get(ctx context.Context, playerID uuid.UUID) (T, error) + GetOrDefault(ctx context.Context, playerID uuid.UUID, defaultData T) (T, error) + GetMultiple(ctx context.Context, playerIds []uuid.UUID) ([]T, error) + Save(ctx context.Context, data T) error +} - GetTowerDefencePlayer(ctx context.Context, playerId uuid.UUID) (*model.TowerDefenceData, error) - SaveTowerDefencePlayer(ctx context.Context, data *model.TowerDefenceData) error +type GameDataRepoColl struct { + BlockSumo GameDataRepository[*model.BlockSumoData] + Marathon GameDataRepository[*model.MarathonData] +} - GetMinesweeperPlayer(ctx context.Context, playerId uuid.UUID) (*model.MinesweeperData, error) - SaveMinesweeperPlayer(ctx context.Context, data *model.MinesweeperData) error +func NewGamePlayerDataRepoColl(db *mongo.Database) *GameDataRepoColl { + return &GameDataRepoColl{ + BlockSumo: NewMongoGameDataRepository(db, &model.BlockSumoData{}), + Marathon: NewMongoGameDataRepository(db, &model.MarathonData{}), + } } diff --git a/internal/service/game_player_data.go b/internal/service/game_player_data.go index dece0fc..2934bac 100644 --- a/internal/service/game_player_data.go +++ b/internal/service/game_player_data.go @@ -9,6 +9,7 @@ import ( "github.com/emortalmc/proto-specs/gen/go/model/gameplayerdata" "github.com/google/uuid" "go.mongodb.org/mongo-driver/mongo" + "go.uber.org/zap" "google.golang.org/grpc/codes" "google.golang.org/grpc/status" "google.golang.org/protobuf/types/known/anypb" @@ -17,12 +18,14 @@ import ( type gamePlayerDataService struct { pb.UnimplementedGamePlayerDataServiceServer - repo repository.Repository + repos *repository.GameDataRepoColl + log *zap.SugaredLogger } -func newGamePlayerDataService(repo repository.Repository) pb.GamePlayerDataServiceServer { +func newGamePlayerDataService(repos *repository.GameDataRepoColl, log *zap.SugaredLogger) pb.GamePlayerDataServiceServer { return &gamePlayerDataService{ - repo: repo, + repos: repos, + log: log, } } @@ -33,14 +36,17 @@ func (s *gamePlayerDataService) GetGamePlayerData(ctx context.Context, req *pb.G } var data model.GameData - switch req.GameMode { case gameplayerdata.GameDataGameMode_BLOCK_SUMO: - data, err = s.repo.GetBlockSumoData(ctx, pId) + data, err = s.repos.BlockSumo.Get(ctx, pId) + case gameplayerdata.GameDataGameMode_MARATHON: + data, err = s.repos.Marathon.Get(ctx, pId) + default: + return nil, status.Error(codes.InvalidArgument, "unsupported game mode") } if err != nil { - return nil, createDbErr(err) + return nil, s.createDbErr(err) } anyData, err := data.ToAnyProto() @@ -63,23 +69,38 @@ func (s *gamePlayerDataService) GetMultipleGamePlayerData(ctx context.Context, r pIds[i] = pId } - data := make(map[string]*anypb.Any, len(pIds)) + var genericData = make([]model.GameData, 0) switch req.GameMode { case gameplayerdata.GameDataGameMode_BLOCK_SUMO: - bsData, err := s.repo.GetBlockSumoDataForPlayers(ctx, pIds) + uncastData, err := s.repos.BlockSumo.GetMultiple(ctx, pIds) + if err != nil { + return nil, s.createDbErr(err) + } + + for _, d := range uncastData { + genericData = append(genericData, d) + } + case gameplayerdata.GameDataGameMode_MARATHON: + uncastData, err := s.repos.Marathon.GetMultiple(ctx, pIds) if err != nil { - return nil, createDbErr(err) + return nil, s.createDbErr(err) } - for _, d := range bsData { - anypb, err := d.ToAnyProto() - if err != nil { - return nil, status.Error(codes.Internal, "failed to convert data to proto") - } + for _, d := range uncastData { + genericData = append(genericData, d) + } + } + + data := make(map[string]*anypb.Any, len(genericData)) - data[d.PlayerId.String()] = anypb + for _, d := range genericData { + anypb, err := d.ToAnyProto() + if err != nil { + return nil, status.Error(codes.Internal, "failed to convert data to proto") } + + data[d.PlayerID().String()] = anypb } return &pb.GetMultipleGamePlayerDataResponse{ @@ -88,10 +109,11 @@ func (s *gamePlayerDataService) GetMultipleGamePlayerData(ctx context.Context, r } -func createDbErr(err error) error { +func (s *gamePlayerDataService) createDbErr(err error) error { if errors.Is(err, mongo.ErrNoDocuments) { return status.Error(codes.NotFound, "player not found") } else { + s.log.Errorw("failed to get player data", "error", err) return status.Error(codes.Internal, "failed to get player data") } } diff --git a/internal/service/public.go b/internal/service/public.go index 4efee7d..8d983c1 100644 --- a/internal/service/public.go +++ b/internal/service/public.go @@ -17,7 +17,7 @@ import ( ) func RunServices(ctx context.Context, logger *zap.SugaredLogger, wg *sync.WaitGroup, cfg *config.Config, - repo repository.Repository) { + repos *repository.GameDataRepoColl) { lis, err := net.Listen("tcp", fmt.Sprintf(":%d", cfg.Port)) if err != nil { @@ -38,7 +38,7 @@ func RunServices(ctx context.Context, logger *zap.SugaredLogger, wg *sync.WaitGr reflection.Register(s) } - gameplayerdata.RegisterGamePlayerDataServiceServer(s, newGamePlayerDataService(repo)) + gameplayerdata.RegisterGamePlayerDataServiceServer(s, newGamePlayerDataService(repos, logger)) logger.Infow("listening for gRPC requests", "port", cfg.Port) go func() {