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);
            }
        }
 public void SignIn(string name)
 {
     lock (_lockObj10)
     {
         UsersConnections.Add(Context.ConnectionId, name);
         UsersNames.Add(name, Context.ConnectionId);
         foreach (var user in UsersWithStatus.Where(u => u.UserName == name))
         {
             user.Status = StatusOfConnection.Available;
         }
         UpdateAllUsersNamesAndConnectionStatus();
     }
 }
        //========== 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);
            }
        }
        public override Task OnDisconnected(bool stopCalled)
        {
            if (stopCalled)
            {
                var    con          = Context.ConnectionId;
                string nameToRemove = UsersConnections[con];
                UsersNames.Remove(nameToRemove);
                UsersConnections.Remove(Clients.Caller);

                foreach (var item in UsersWithStatus)
                {
                    if ((item.UserName).Equals(nameToRemove))
                    {
                        item.Status = StatusOfConnection.Offline;
                    }
                }
                UpdateAllUsersNamesAndConnectionStatus();
            }
            return(base.OnDisconnected(stopCalled));
        }
        //========== Connection Helpers  ======================================================================================

        // Get users's connections to the chat
        private IEnumerable <ConnectionId> GetUserConnections(UserId partnerId)
        {
            return(UsersConnections.GetFromKey(partnerId));
        }