朋友列表与chatjs.net SignalR MVC聊天

时间:2013-08-09 16:59:38

标签: asp.net-mvc chat signalr chatjs

我开始使用chatjs.net实现网络聊天系统。但我不知道朋友列表应该绑定聊天列表。我推荐房间聊天与ROOM_ID_STUB是用户名记录。但在我的情况下,朋友列表将显示在线和离线用户,不像所有示例chatjs.net将只是单人间。

任何人都可以建议我绑定我朋友列表的正确方法,并且每个登录的用户都会有一个聊天室并且他们一起共享房间聊天列表吗?

public class ChatHub : Hub, IChatHub
    {
        /// <summary>
        /// This STUB. In a normal situation, there would be multiple rooms and the user room would have to be 
        /// determined by the user profile
        /// </summary>
        public const string ROOM_ID_STUB = "chatjs-room";

        /// <summary>
        /// Current connections
        /// 1 room has many users that have many connections (2 open browsers from the same user represents 2 connections)
        /// </summary>
        private static readonly Dictionary<string, Dictionary<int, List<string>>> connections = new Dictionary<string, Dictionary<int, List<string>>>();

        /// <summary>
        /// This is STUB. This will SIMULATE a database of chat messages
        /// </summary>
        private static readonly List<DbChatMessageStub> dbChatMessagesStub = new List<DbChatMessageStub>();

        /// <summary>
        /// This method is STUB. This will SIMULATE a database of users
        /// </summary>
        private static readonly List<DbUserStub> dbUsersStub = new List<DbUserStub>();

        /// <summary>
        /// This method is STUB. In a normal situation, the user info would come from the database so this method wouldn't be necessary.
        /// It's only necessary because this class is simulating the database
        /// </summary>
        /// <param name="newUser"></param>
        public static void RegisterNewUser(DbUserStub newUser)
        {
            if (newUser == null) throw new ArgumentNullException("newUser");
            dbUsersStub.Add(newUser);
        }

        /// <summary>
        /// This method is STUB. Returns if a user is registered in the FAKE DB.
        /// Normally this wouldn't be necessary.
        /// </summary>
        /// <param name="user"></param>
        /// <returns></returns>
        public static bool IsUserRegisteredInDbUsersStub(DbUserStub user)
        {
            return dbUsersStub.Any(u => u.Id == user.Id);
        }

        /// <summary>
        /// Tries to find a user with the provided e-mail
        /// </summary>
        /// <param name="email"></param>
        /// <returns></returns>
        public static DbUserStub FindUserByEmail(string email)
        {
            if (email == null) return null;
            return dbUsersStub.FirstOrDefault(u => u.Email == email);
        }

        /// <summary>
        /// If the specified user is connected, return information about the user
        /// </summary>
        public ChatUser GetUserInfo(int userId)
        {
            var user = dbUsersStub.FirstOrDefault(u => u.Id == userId);
            return user == null ? null : GetChatUserFromDbUserId(userId);
        }

        private ChatUser GetChatUserFromDbUserId(int dbUserId)
        {
            var myRoomId = this.GetMyRoomId();

            // this is STUB. Normally you would go to the database get the real user
            var dbUser = dbUsersStub.First(u => u.Id == dbUserId);

            ChatUser.StatusType userStatus;
            lock (connections)
            {
                userStatus = connections.ContainsKey(myRoomId)
                                 ? (connections[myRoomId].ContainsKey(dbUser.Id)
                                        ? ChatUser.StatusType.Online
                                        : ChatUser.StatusType.Offline)
                                 : ChatUser.StatusType.Offline;
            }
            return new ChatUser()
            {
                Id = dbUser.Id,
                Name = dbUser.FullName,
                Status = userStatus,
                ProfilePictureUrl = GravatarHelper.GetGravatarUrl(GravatarHelper.GetGravatarHash(dbUser.Email), GravatarHelper.Size.s32)
            };
        }

        private ChatMessage GetChatMessage(DbChatMessageStub chatMessage, string clientGuid)
        {
            return new ChatMessage()
            {
                Message = chatMessage.Message,
                UserFrom = this.GetChatUserFromDbUserId(chatMessage.UserFromId),
                UserTo = this.GetChatUserFromDbUserId(chatMessage.UserToId),
                ClientGuid = clientGuid
            };
        }

        /// <summary>
        /// Returns my user id
        /// </summary>
        /// <returns></returns>
        private int GetMyUserId()
        {
            // This would normally be done like this:
            //var userPrincipal = this.Context.User as AuthenticatedPrincipal;
            //if (userPrincipal == null)
            //    throw new NotAuthorizedException();

            //var userData = userPrincipal.Profile;
            //return userData.Id;

            // But for this example, it will get my user from the cookie
            return ChatCookieHelperStub.GetDbUserFromCookie(this.Context.Request).Id;
        }

        private string GetMyRoomId()
        {
            // This would normally be done like this:
            //var userPrincipal = this.Context.User as AuthenticatedPrincipal;
            //if (userPrincipal == null)
            //    throw new NotAuthorizedException();

            //var userData = userPrincipal.Profile;
            //return userData.MyTenancyIdentifier;

            // But for this example, it will always return "chatjs-room", because we have only one room.
            return ROOM_ID_STUB;
        }

        /// <summary>
        /// Broadcasts to all users in the same room the new users list
        /// </summary>
        private void BroadcastUsersList()
        {
            var myRoomId = this.GetMyRoomId();
            var connectionIds = new List<string>();
            lock (connections)
            {
                if (connections.ContainsKey(myRoomId))
                    connectionIds = connections[myRoomId].Keys.SelectMany(userId => connections[myRoomId][userId]).ToList();
            }

            // gets the current room user's list

            // this is STUB. You would normally go to the database to get the real room users
            var dbRoomUsers = dbUsersStub.Where(u => u.TenancyId == myRoomId).OrderBy(u => u.FullName).ToList();
            var usersList = dbRoomUsers.Select(u => this.GetChatUserFromDbUserId(u.Id)).ToList();

            foreach (var connectionId in connectionIds)
                this.Clients.Client(connectionId).usersListChanged(usersList);
        }

        private DbChatMessageStub PersistMessage(int otherUserId, string message)
        {
            var myUserId = this.GetMyUserId();

            // this is STUB. Normally you would go to the real database to get the my user and the other user
            var myUser = dbUsersStub.FirstOrDefault(u => u.Id == myUserId);
            var otherUser = dbUsersStub.FirstOrDefault(u => u.Id == otherUserId);

            if (myUser == null || otherUser == null)
                return null;

            var dbChatMessage = new DbChatMessageStub()
            {
                Date = DateTime.UtcNow,
                Message = message,
                UserFromId = myUserId,
                UserToId = otherUserId,
                TenancyId = myUser.TenancyId
            };

            // this is STUB. Normally you would add the dbMessage to the real database
            dbChatMessagesStub.Add(dbChatMessage);

            // normally you would save the database changes
            //this.db.SaveChanges();

            return dbChatMessage;
        }

        /// <summary>
        /// Returns the message history
        /// </summary>
        public List<ChatMessage> GetMessageHistory(int otherUserId)
        {
            var myUserId = this.GetMyUserId();
            // this is STUB. Normally you would go to the real database to get the messages
            var dbMessages = dbChatMessagesStub
                               .Where(
                                   m =>
                                   (m.UserToId == myUserId && m.UserFromId == otherUserId) ||
                                   (m.UserToId == otherUserId && m.UserFromId == myUserId))
                               .OrderByDescending(m => m.Date).Take(30).ToList();

            dbMessages.Reverse();
            return dbMessages.Select(m => this.GetChatMessage(m, null)).ToList();
        }

        /// <summary>
        /// Sends a message to a particular user
        /// </summary>
        public void SendMessage(int otherUserId, string message, string clientGuid)
        {
            var myUserId = this.GetMyUserId();
            var myRoomId = this.GetMyRoomId();


            var dbChatMessage = PersistMessage(otherUserId, message);
            var connectionIds = new List<string>();
            lock (connections)
            {
                if (connections[myRoomId].ContainsKey(otherUserId))
                    connectionIds.AddRange(connections[myRoomId][otherUserId]);
                if (connections[myRoomId].ContainsKey(myUserId))
                    connectionIds.AddRange(connections[myRoomId][myUserId]);
            }
            foreach (var connectionId in connectionIds)
                this.Clients.Client(connectionId).sendMessage(this.GetChatMessage(dbChatMessage, clientGuid));
        }

        /// <summary>
        /// Sends a typing signal to a particular user
        /// </summary>
        public void SendTypingSignal(int otherUserId)
        {
            var myUserId = this.GetMyUserId();
            var myRoomId = this.GetMyRoomId();

            var connectionIds = new List<string>();
            lock (connections)
            {
                if (connections[myRoomId].ContainsKey(otherUserId))
                    connectionIds.AddRange(connections[myRoomId][otherUserId]);
            }
            foreach (var connectionId in connectionIds)
                this.Clients.Client(connectionId).sendTypingSignal(this.GetUserInfo(myUserId));
        }

        public override Task OnConnected()
        {
            var myRoomId = this.GetMyRoomId();
            var myUserId = this.GetMyUserId();

            lock (connections)
            {
                if (!connections.ContainsKey(myRoomId))
                    connections[myRoomId] = new Dictionary<int, List<string>>();

                if (!connections[myRoomId].ContainsKey(myUserId))
                    connections[myRoomId][myUserId] = new List<string>();

                connections[myRoomId][myUserId].Add(this.Context.ConnectionId);
            }

            this.BroadcastUsersList();

            return base.OnConnected();
        }

        public override Task OnDisconnected()
        {
            var myRoomId = this.GetMyRoomId();
            var myUserId = this.GetMyUserId();

            lock (connections)
            {
                if (connections.ContainsKey(myRoomId))
                    if (connections[myRoomId].ContainsKey(myUserId))
                        if (connections[myRoomId][myUserId].Contains(this.Context.ConnectionId))
                        {
                            connections[myRoomId][myUserId].Remove(this.Context.ConnectionId);
                            if (!connections[myRoomId][myUserId].Any())
                            {
                                connections[myRoomId].Remove(myUserId);
                                Task.Factory.StartNew(() =>
                                    {
                                        // this will run in separate thread.
                                        // If the user is away for more than 10 seconds it will be removed from 
                                        // the room.
                                        // In a normal situation this wouldn't be done because normally the users in a
                                        // chat room are fixed, like when you have 1 chat room for each tenancy
                                        Thread.Sleep(10000);
                                        if (!connections[myRoomId].ContainsKey(myUserId))
                                        {
                                            var myDbUser = dbUsersStub.FirstOrDefault(u => u.Id == myUserId);
                                            if (myDbUser != null)
                                            {
                                                dbUsersStub.Remove(myDbUser);
                                                this.BroadcastUsersList();
                                            }
                                        }
                                    });
                            }
                        }
            }

            return base.OnDisconnected();
        }
    }

1 个答案:

答案 0 :(得分:2)

private void BroadcastUsersList()
        {
            var myRoomId = this.GetMyRoomId();
            var connectionIds = new List<string>();
            lock (connections)
            {
                if (connections.ContainsKey(myRoomId))
                    connectionIds = connections[myRoomId].Keys.SelectMany(userId => connections[myRoomId][userId]).ToList();
            }


            List<UserSite> dbRoomUsers = new List<UserSite>();
            int myId = GetMyUserId();
            List<Int>listFriendId = getListUserIdFriendOfUser(myId);
            listFriendId.Add(myId);
            foreach (var item in dbUsersStub)
            {
                if (listFriendId.Contains(item.Id))
                    dbRoomUsers.Add(item);
            }
            var usersList = dbRoomUsers.Select(u => this.GetChatUserFromDbUserId(u.Id)).ToList();

            foreach (var connectionId in connectionIds)
                this.Clients.Client(connectionId).usersListChanged(usersList);
        }