diff --git a/internal/core/services/events/events_forwarder_service.go b/internal/core/services/events/events_forwarder_service.go index 85af87665..3c0bf31c6 100644 --- a/internal/core/services/events/events_forwarder_service.go +++ b/internal/core/services/events/events_forwarder_service.go @@ -222,6 +222,8 @@ func (es *EventsForwarderService) forwardPlayerEvent( es.logger.Error(fmt.Sprintf("Failed to forward player events for room %s and scheduler %s", event.RoomID, event.SchedulerID), zap.Error(err)) return err } + + es.updatePlayerState(ctx, event, playerAttributes) reportPlayerEventForwardingSuccess(scheduler.Game, event.SchedulerID) return nil } @@ -327,3 +329,36 @@ func (es *EventsForwarderService) isRoomInUnreliableState(event *events.Event) b return false } + +func (es *EventsForwarderService) updatePlayerState(ctx context.Context, event *events.Event, playerAttributes events.PlayerEventAttributes) { + room, err := es.roomStorage.GetRoom(ctx, event.SchedulerID, event.RoomID) + if err != nil { + es.logger.Error(fmt.Sprintf("Failed to get room %s from storage", event.RoomID), zap.Error(err)) + return + } + + if room.IsValidationRoom { + return + } + + if room.Metadata == nil { + room.Metadata = make(map[string]interface{}) + } + + var players int + if key, ok := room.Metadata["players"]; ok { + players = key.(int) + } + + switch playerAttributes.EventType { + case events.PlayerJoin: + room.Metadata["players"] = players + 1 + case events.PlayerLeft: + room.Metadata["players"] = players - 1 + } + + err = es.roomStorage.UpdateRoom(ctx, room) + if err != nil { + es.logger.Error(fmt.Sprintf("Failed to update room %s in storage", event.RoomID), zap.Error(err)) + } +} diff --git a/internal/core/services/events/events_forwarder_service_test.go b/internal/core/services/events/events_forwarder_service_test.go index 682893a52..f6a3bf87f 100644 --- a/internal/core/services/events/events_forwarder_service_test.go +++ b/internal/core/services/events/events_forwarder_service_test.go @@ -172,7 +172,76 @@ func TestEventsForwarderService_ProduceEvent(t *testing.T) { }) t.Run("should succeed when event is PlayerEvent", func(t *testing.T) { - eventsForwarderService, config, eventsForwarder, schedulerStorage, _, instanceStorage, schedulerCache := testSetup(t) + eventsForwarderService, config, eventsForwarder, schedulerStorage, roomStorage, instanceStorage, schedulerCache := testSetup(t) + + event := &events.Event{ + Name: events.PlayerEvent, + SchedulerID: expectedScheduler.Name, + RoomID: "room", + Attributes: map[string]interface{}{ + "eventType": "playerLeft", + "playerId": "player", + }, + } + + room := &game_room.GameRoom{ + ID: event.RoomID, + SchedulerID: event.SchedulerID, + IsValidationRoom: false, + } + + schedulerCache.EXPECT().GetScheduler(context.Background(), event.SchedulerID).Return(nil, nil) + schedulerStorage.EXPECT().GetScheduler(context.Background(), event.SchedulerID).Return(expectedScheduler, nil) + instanceStorage.EXPECT().GetInstance(context.Background(), event.SchedulerID, event.RoomID).Return(expectedGameRoomInstance, nil).Times(0) + schedulerCache.EXPECT().SetScheduler(context.Background(), expectedScheduler, config.SchedulerCacheTtl).Return(nil) + eventsForwarder.EXPECT().ForwardPlayerEvent(context.Background(), gomock.Any(), gomock.Any()).Return(nil) + roomStorage.EXPECT().GetRoom(gomock.Any(), event.SchedulerID, event.RoomID).Return(room, nil) + roomStorage.EXPECT().UpdateRoom(gomock.Any(), gomock.Any()).Return(nil) + + err := eventsForwarderService.ProduceEvent(context.Background(), event) + require.NoError(t, err) + require.Empty(t, event.Attributes["ports"]) + }) + + t.Run("should increase room player count when event is PlayerEvent and event type is playerJoin", func(t *testing.T) { + eventsForwarderService, config, eventsForwarder, schedulerStorage, roomStorage, instanceStorage, schedulerCache := testSetup(t) + + event := &events.Event{ + Name: events.PlayerEvent, + SchedulerID: expectedScheduler.Name, + RoomID: "room", + Attributes: map[string]interface{}{ + "eventType": "playerJoin", + "playerId": "player", + }, + } + + room := &game_room.GameRoom{ + ID: event.RoomID, + SchedulerID: event.SchedulerID, + IsValidationRoom: false, + Metadata: map[string]interface{}{ + "players": 5, + }, + } + + schedulerCache.EXPECT().GetScheduler(context.Background(), event.SchedulerID).Return(nil, nil) + schedulerStorage.EXPECT().GetScheduler(context.Background(), event.SchedulerID).Return(expectedScheduler, nil) + instanceStorage.EXPECT().GetInstance(context.Background(), event.SchedulerID, event.RoomID).Return(expectedGameRoomInstance, nil).Times(0) + schedulerCache.EXPECT().SetScheduler(context.Background(), expectedScheduler, config.SchedulerCacheTtl).Return(nil) + eventsForwarder.EXPECT().ForwardPlayerEvent(context.Background(), gomock.Any(), gomock.Any()).Return(nil) + roomStorage.EXPECT().GetRoom(gomock.Any(), event.SchedulerID, event.RoomID).Return(room, nil) + + room.Metadata["players"] = 6 + roomStorage.EXPECT().UpdateRoom(gomock.Any(), room).Return(nil) + + err := eventsForwarderService.ProduceEvent(context.Background(), event) + require.NoError(t, err) + require.Empty(t, event.Attributes["ports"]) + }) + + t.Run("should decrease room player count when event is PlayerEvent and event type is playerLeft", func(t *testing.T) { + eventsForwarderService, config, eventsForwarder, schedulerStorage, roomStorage, instanceStorage, schedulerCache := testSetup(t) event := &events.Event{ Name: events.PlayerEvent, @@ -184,11 +253,56 @@ func TestEventsForwarderService_ProduceEvent(t *testing.T) { }, } + room := &game_room.GameRoom{ + ID: event.RoomID, + SchedulerID: event.SchedulerID, + IsValidationRoom: false, + Metadata: map[string]interface{}{ + "players": 5, + }, + } + schedulerCache.EXPECT().GetScheduler(context.Background(), event.SchedulerID).Return(nil, nil) schedulerStorage.EXPECT().GetScheduler(context.Background(), event.SchedulerID).Return(expectedScheduler, nil) instanceStorage.EXPECT().GetInstance(context.Background(), event.SchedulerID, event.RoomID).Return(expectedGameRoomInstance, nil).Times(0) schedulerCache.EXPECT().SetScheduler(context.Background(), expectedScheduler, config.SchedulerCacheTtl).Return(nil) eventsForwarder.EXPECT().ForwardPlayerEvent(context.Background(), gomock.Any(), gomock.Any()).Return(nil) + roomStorage.EXPECT().GetRoom(gomock.Any(), event.SchedulerID, event.RoomID).Return(room, nil) + + room.Metadata["players"] = 4 + roomStorage.EXPECT().UpdateRoom(gomock.Any(), room).Return(nil) + + err := eventsForwarderService.ProduceEvent(context.Background(), event) + require.NoError(t, err) + require.Empty(t, event.Attributes["ports"]) + }) + + t.Run("should not update room player count when event is PlayerEvent and room is validationRoom", func(t *testing.T) { + eventsForwarderService, config, eventsForwarder, schedulerStorage, roomStorage, instanceStorage, schedulerCache := testSetup(t) + + event := &events.Event{ + Name: events.PlayerEvent, + SchedulerID: expectedScheduler.Name, + RoomID: "room", + Attributes: map[string]interface{}{ + "eventType": "playerLeft", + "playerId": "player", + }, + } + + room := &game_room.GameRoom{ + ID: event.RoomID, + SchedulerID: event.SchedulerID, + IsValidationRoom: true, + } + + schedulerCache.EXPECT().GetScheduler(context.Background(), event.SchedulerID).Return(nil, nil) + schedulerStorage.EXPECT().GetScheduler(context.Background(), event.SchedulerID).Return(expectedScheduler, nil) + instanceStorage.EXPECT().GetInstance(context.Background(), event.SchedulerID, event.RoomID).Return(expectedGameRoomInstance, nil).Times(0) + schedulerCache.EXPECT().SetScheduler(context.Background(), expectedScheduler, config.SchedulerCacheTtl).Return(nil) + eventsForwarder.EXPECT().ForwardPlayerEvent(context.Background(), gomock.Any(), gomock.Any()).Return(nil) + roomStorage.EXPECT().GetRoom(gomock.Any(), event.SchedulerID, event.RoomID).Return(room, nil) + roomStorage.EXPECT().UpdateRoom(gomock.Any(), room).MaxTimes(0) err := eventsForwarderService.ProduceEvent(context.Background(), event) require.NoError(t, err)