Обработка сессий в ядре SignalR

Я использую .Net 5, и я делаю игровой сервер с использованием ядра SignalR.

Есть 2 способа внедрить сервис в мои классы.

1- Внедрение конструктора: где я должен разделять функции и данные, даже если они хранятся в памяти, а не в базе данных.

Например: вместо класса Room, содержащего данные и функции, я буду RoomManager сервис и Room для данных.

Здесь я ввожу _masterRepo, _masterHub, _sessionRepo, _logger на службе RoomManager которые имеют срок службы.

Но мне нужно передать классы данных для работы.

        public async Task AddUser(Room room, string userId, string connId)
        {
            var rUser = _sessionRepo.AddRoomUser(userId, connId, room);

            if (room.Capacity == room.RoomUsers.Count)
            {
                _logger.LogInformation("a room is ready and will start");
                await Start(room);
            }
            else
            {
                _sessionRepo.KeepRoom(room);
                await _masterHub.Clients.User(rUser.UserId).SendAsync("RoomIsFilling");
            }
        }

        private async Task Start(Room room)
        {
            var dUsers = _masterRepo.GetRoomDisplayUsersAsync(room);
            var rUsers = room.RoomUsers;

            var tasks = new List<Task>();
            for (int i = 0; i < room.Capacity; i++)
            {
                tasks.Add(_masterHub.Groups.AddToGroupAsync(rUsers[i].ConnectionId, "room" + room.Id));

                rUsers[i].TurnId = i;

                tasks.Add(_masterHub.Clients.User(rUsers[i].UserId).SendAsync("StartRoom", i, dUsers));
            }

            await Task.WhenAll(tasks);

            StartTurn(rUsers[0]);
        }

2- Внедрение функций: где я могу комбинировать данные и функции в одном классе (нормальный дизайн ООП).

Это внутри класса Room, чтобы назвать его: someRoom.AddUser(....)

public async Task AddUser(SessionRepo _sessionRepo, ILogger _logger, IHubContext<MasterHub> _masterHub, string userId, string connId)
{
    var rUser = _sessionRepo.AddRoomUser(userId, connId, room);
    if (roomCapacity == RoomUsers.Count)
    {
        _logger.LogInformation("a room is ready and will start");
        await Start(room);
    }
    else
    {
        _sessionRepo.KeepRoom(room);
        await _masterHub.Clients.User(rUser.UserId).SendAsync("RoomIsFilling");
    }
}
private async Task Start(MasterRepo _masterRepo)
{
    var dUsers = _masterRepo.GetRoomDisplayUsersAsync(room);
    
    var tasks = new List<Task>();
    for (int i = 0; i < room.Capacity; i++)
    {
        tasks.Add(_masterHub.Groups.AddToGroupAsync(RoomUsers[i].ConnectionId, "room" + room.Id))
        RoomUsers[i].TurnId = i
        tasks.Add(_masterHub.Clients.User(RoomUsers[i].UserId).SendAsync("StartRoom", i, dUsers));
    }
    await Task.WhenAll(tasks)
    
    StartTurn(RoomUsers[0]);
}

SessionRepo — это singleton, содержащий все данные с момента загрузки сервера.

    public class SessionRepo : ISessionRepo
    {
        private ConcurrentDictionary<int, Room> Rooms;
        private ConcurrentDictionary<string, RoomUser> RoomUsers;

        private int LastRoomId;
        private int LastRoomUserId;

        private ConcurrentDictionary<(int, int), ConcurrentBag<Room>> PendingRooms;

        private readonly int[] GenrePosses = {0, 1, 2, 3};
        private readonly int[] UserCountPosses = {2, 3, 4};

        public SessionRepo()
        {
            PendingRooms = new ConcurrentDictionary<(int, int), ConcurrentBag<Room>>();
            for (int i = 0; i < GenrePosses.Length; i++)
            {
                for (int j = 0; j < UserCountPosses.Length; j++)
                {
                    PendingRooms.TryAdd((i, j), new ConcurrentBag<Room>());
                }
            }
        }

        #region room

        public Room DeleteRoom(int roomId)
        {
            Rooms.TryRemove(roomId, out Room room);
            return room;
        }

        #endregion

        #region pending room

        public Room GetPendingRoom(int genre, int userCount)
        {
            PendingRooms[(genre, userCount)].TryTake(out Room room);
            return room;
        }

        /// <summary>
        /// if the room is still pending 
        /// </summary>
        public void KeepRoom(Room room)
        {
            PendingRooms[(room.Genre, room.Capacity)].Add(room);
        }

        public RoomUser AddRoomUser(string id, string connId, Room room)
        {
            var rUser = new RoomUser {UserId = id, ConnectionId = connId, Room = room};

            room.RoomUsers.Add(rUser);
            RoomUsers.TryAdd(id, rUser);

            return rUser;
        }

        public Room MakeRoom(int genre, int userCount)
        {
            var room = new Room {Genre = genre, Capacity = userCount};

            Rooms.Append(ref LastRoomId, room);

            return room;
        }

        #endregion

        #region room user

        public RoomUser GetRoomUserWithId(string id)
        {
            RoomUsers.TryGetValue(id, out RoomUser roomUser);
            return roomUser;
        }

        #endregion
    }

Я использовал внедрение функции, затем обнаружил, что сервер не должен иметь статуса, поэтому я сохранил данные сеанса в БД, но я подумал об этом, данные сеанса действительно малы для каждого пользователя и часто используются, потому что (на самом деле это только внутри игрового процесса). И если сервер выходит из строя, нет ничего, что нужно делать, чтобы сеансы продолжали работать, потому что есть рассчитанные по времени действия (например, тайм-аут), которых не произойдет, когда сервер умирает на несколько секунд, поэтому точка без статистики в сеансах не имеет значения, я думаю .

Я много узнал / искал, но не могу решить, я не могу найти достаточно сложный репозиторий SignalR, чтобы учиться. Мне некому просматривать мой код, извините, если это много, пожалуйста, поделитесь своими мыслями.

0

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *