public virtual void CleanConnection(string connectionId) { Log.SignalR(LogTag.TextChatHub_CleaningConnection, new { connectionId }); // Remove Message Queue for this connection. Queues are created only when needed, so they might not always exists if (MessageQueues.ContainsKey(connectionId)) { MessageQueues[connectionId].Reset(); MessageQueues.Remove(connectionId); } // Remove all connections to rooms RoomsConnections.RemoveConnectionFromAllRooms(connectionId); // Remove User's Connection, and leave chat if this was the last connection if (UsersConnections.ContainsValue(connectionId)) { UserId userId = UsersConnections.GetFromValue(connectionId); UsersConnections.Remove(connectionId); if (!UsersConnections.ContainsKey(userId)) { ChatCtrl.LeaveChat(userId); } } else { Log.Info(LogTag.TextChatHub_AlreadyCleaned); } // Also remove LastSeen Info for this connection if (LastSeenConnections.ContainsKey(connectionId)) { LastSeenConnections.Remove(connectionId); } }
// Get the partner's connections related to a specific private room, along with the active connections to the room private IEnumerable <ConnectionId> GetPartnerAndActiveConnections(RoomId roomId, UserId thisUserId, ConnectionId exceptConnection = null) { var roomConnIds = RoomsConnections.GetConnections(roomId, exceptConnection); var userConnIds = GetPartnerConnections(roomId, thisUserId); return(roomConnIds.Union(userConnIds).Where(c => c != exceptConnection)); }
//========== Background Methods ====================================================================================== private void HeartbeatCheck() { try { // Try catch needed because errors are otherwised silenced, somehow :-( // Remove dead connections (Ping not received timely) foreach (var kvp in LastSeenConnections.ToList()) { if (kvp.Value < DateTime.Now.AddSeconds(-CleanZombieAfter)) { var connectionId = kvp.Key; Log.SignalR(LogTag.CleaningZombieConnection, new { connectionId }); CleanConnection(connectionId); } } // Remove inactive members from "crowded" rooms var chatState = ChatCtrl.GetState(); foreach (var roomKvp in chatState.Rooms) { if (roomKvp.Key.IsMonoLang() && roomKvp.Value.Count > BootAboveUserCount) { var mostInactiveUserKvp = roomKvp.Value.Aggregate((l, r) => l.Value.LastActive < r.Value.LastActive ? l : r); if (mostInactiveUserKvp.Value.LastActive < DateTime.Now.AddMinutes(-BootOutOfRoomAfter)) { Log.SignalR(LogTag.KickSlackerOutOfRoom, new { roomId = roomKvp.Key, userId = mostInactiveUserKvp.Key }); // Get the list of connections that have to leave the room var userConnectionIds = UsersConnections.GetFromKey(mostInactiveUserKvp.Key) .Where(connId => RoomsConnections.HasConnection(roomKvp.Key, connId)) .Select(connId => connId.ToString()).ToList(); Clients.Clients(userConnectionIds).LeaveRoom(roomKvp.Key); } } } // Check for inactive members foreach (var chatUser in chatState.AllUsers.Values) { if (chatUser.LastActivity < DateTime.Now.AddMinutes(-UserIdleAfter)) { ChatCtrl.SetIdleStatus(chatUser.Id); Log.SignalR(LogTag.SetChatUserIdle, new { userId = chatUser.Id }); } } Log.SignalR(LogTag.HubHeartbeatCheckCompleted); } catch (Exception e) { Log.Error(LogTag.HeartbeatCheckError, e); } }