コード例 #1
0
        /// <summary>
        /// 获取历史聊天记录
        /// </summary>
        /// <param name="roomHashid">房间哈希ID</param>
        /// <param name="entryTime">进入房间的时间</param>
        /// <param name="startIndex">此次获取的聊天历史记录的开始序号</param>
        /// <returns>表示获取聊天记录的任务</returns>
        public async Task <List <ChatHistoryDto> > GetChatHistoryAsync(string roomHashid, long entryTime, int startIndex)
        {
            var roomId = HashidsHelper.Decode(roomHashid);
            var query  = await _dbContext.ChatHistory
                         .Where(msg => msg.RoomId == roomId &&
                                msg.UnixTimeMilliseconds < entryTime)
                         .OrderByDescending(msg => msg.UnixTimeMilliseconds)
                         .Skip(startIndex)
                         .Take(20)
                         .ToListAsync();

            var history = new List <ChatHistoryDto>();

            foreach (var msg in query)
            {
                var data = msg.Message;
                if (msg.IsPicture.Value)
                {
                    var path = Path.Combine(_picturesDirectory, msg.RoomId.ToString(), "thumbnails",
                                            $"{msg.UserId}_{msg.UnixTimeMilliseconds}.jpg");
                    data = Convert.ToBase64String(await File.ReadAllBytesAsync(path));
                }
                history.Add(new ChatHistoryDto
                {
                    UserId    = HashidsHelper.Encode(msg.UserId),
                    Username  = msg.Username,
                    Data      = data,
                    Timestamp = msg.UnixTimeMilliseconds,
                    IsPicture = msg.IsPicture.Value
                });
            }
            return(history);
        }
コード例 #2
0
        /// <summary>
        /// 获取用户上一次登录时所在的房间ID
        /// </summary>
        /// <param name="uid">用户ID</param>
        /// <returns>表示获取用户上一次登录时所在的房间ID的任务</returns>
        public async Task <string> GetPreviousRoomIdAsync(int uid)
        {
            var connection = await _dbContext.Connection
                             .Where(conn => conn.UserId == uid && !conn.IsDeleted.Value)
                             .FirstOrDefaultAsync();


            // 连接信息没找到
            if (connection == null)
            {
                return(null);
            }

            var room = await _dbContext.ChatRoom.FindAsync(connection.RoomId);

            if (room == null)
            {
                // 如果房间没找到,但连接信息却找到了,说明之前的数据有问题
                // 删除连接信息
                _dbContext.Remove(connection);
                await _dbContext.SaveChangesAsync();

                return(null);
            }
            return(HashidsHelper.Encode(connection.RoomId));
        }
コード例 #3
0
        /// <summary>
        /// 创建房间
        /// </summary>
        /// <param name="uid">用户ID</param>
        /// <param name="roomDto">用户输入的用于创建房间的信息</param>
        /// <returns>表示异步创建房间的任务,如果创建失败则返回错误信息</returns>
        public async Task <ChatRoomCreateResponseDto> CreateRoomAsync(int uid, ChatRoomDto roomDto)
        {
            // 防止用户打开多个窗口创建房间
            var error = await ApplyForCreatingRoomAsync(uid);

            if (!string.IsNullOrEmpty(error))
            {
                return(new ChatRoomCreateResponseDto
                {
                    Error = error,
                    CloseModalIfError = true
                });
            }
            try
            {
                var room = new ChatRoom
                {
                    OwnerId     = uid,
                    Name        = roomDto.Name,
                    MaxUsers    = roomDto.MaxUsers,
                    IsEncrypted = roomDto.IsEncrypted,
                    IsPermanent = roomDto.IsPermanent,
                    IsHidden    = roomDto.IsHidden,
                    AllowGuest  = roomDto.AllowGuest
                };

                // 如果房间被加密
                if (roomDto.IsEncrypted)
                {
                    Guid salt = Guid.NewGuid();
                    room.Salt         = salt.ToString();
                    room.PasswordHash = PasswordHelper.GeneratePasswordHash(roomDto.Password, room.Salt);
                }

                _dbContext.ChatRoom.Add(room);
                await _dbContext.SaveChangesAsync();

                return(new ChatRoomCreateResponseDto
                {
                    RoomId = HashidsHelper.Encode(room.Id)
                });
            }
            catch (Exception)
            {
                // 因为是多线程,任然可能发生异常
                // 房间名重复
                return(new ChatRoomCreateResponseDto
                {
                    Error = _msg.GetMessage("E003", "房间名"),
                    CloseModalIfError = false
                });
            }
        }
コード例 #4
0
        /// <summary>
        /// 作为游客登录
        /// </summary>
        /// <returns>异步获取Token的任务</returns>
        public async Task <AccessTokenResponseDto> LoginAsGuestAsync()
        {
            var guestId  = Convert.ToInt32(DateTime.Now.ToString("ddHHmmss") + new Random().Next(0, 9));
            var username = $"游客{HttpUtility.UrlDecode(HashidsHelper.Encode(guestId))}";

            var user = new User
            {
                Id       = guestId,
                Username = username,
                RoleId   = (int)Roles.Guest
            };

            return(new AccessTokenResponseDto
            {
                AccessToken = await _tokenAuthService.GenerateAccessTokenAsync(user),
                RefreshToken = await _tokenAuthService.GenerateRefreshTokenAsync(user)
            });
        }
コード例 #5
0
        /// <summary>
        /// 刷新房间成员列表信息
        /// </summary>
        /// <param name="roomHashid">房间哈希ID</param>
        /// <param name="roomId">房间ID</param>
        /// <returns>表示刷新房间成员列表信息的任务</returns>
        private async Task RefreshMemberListAsync(string roomHashid, int roomId)
        {
            var ownerId = await _dbContext.ChatRoom
                          .Where(room => room.Id == roomId)
                          .Select(room => room.OwnerId).FirstOrDefaultAsync();

            // order by is_owner desc, is_online desc, create_time
            var list = await _dbContext.Connection
                       .Where(conn => conn.RoomId == roomId)
                       .OrderBy(conn => conn.CreateTime)
                       .Select(conn => new ChatRoomMemberDto
            {
                UserId   = HashidsHelper.Encode(conn.UserId),
                Username = conn.Username,
                IsOnline = conn.IsOnline.Value,
                IsOwner  = conn.UserId == ownerId
            })
                       .OrderByDescending(x => x.IsOwner)
                       .ThenByDescending(x => x.IsOnline)
                       .ToListAsync();

            await Clients.Group(roomHashid).InvokeAsync("refreshMemberList", list);
        }
コード例 #6
0
        /// <summary>
        /// 失去连接
        /// </summary>
        /// <param name="exception">异常信息</param>
        /// <returns>表示处理失去连接的任务</returns>
        public async override Task OnDisconnectedAsync(Exception exception)
        {
            var connenction = await _dbContext
                              .Connection.FirstOrDefaultAsync(conn => conn.ConnectionId == Context.ConnectionId);

            // 如果用户开了多个窗口的话,这边可能会出问题
            // 或者用户被移出房间
            if (connenction == null)
            {
                return;
            }

            var roomHashid = HashidsHelper.Encode(connenction.RoomId);

            // 检索房主ID
            var ownerId = await _dbContext.ChatRoom
                          .Where(r => r.Id == connenction.RoomId)
                          .Select(r => r.OwnerId)
                          .FirstOrDefaultAsync();

            // 如果当前房间已经被删除,ownerId会得到0
            // 或者该连接被标记为删除,即用户退出聊天室
            if (ownerId == 0 || connenction.IsDeleted.Value)
            {
                // 删除连接信息
                _dbContext.Connection.Remove(connenction);
            }
            else
            {
                // 以下为用户失去连接的情况

                // 消息ID
                string msgId;
                Roles  userRole = (Roles)Convert.ToInt32(Context.User.FindFirst(ClaimTypes.Role).Value);
                // 如果是游客,直接删除链接信息
                if (userRole == Roles.Guest)
                {
                    // 游客直接通知离开房间
                    msgId = "I004";
                    _dbContext.Connection.Remove(connenction);
                }
                else
                {
                    // 通知同一房间里其他人该用户已经离线的ID
                    msgId = "I002";
                    connenction.IsOnline = false;
                    _dbContext.Update(connenction);
                }
                // 通知同一房间里其他人该用户已经离线或游客离开房间
                await Clients.Group(roomHashid).InvokeAsync(
                    "receiveSystemMessage",
                    _msg.GetMessage(msgId,
                                    HttpUtility.UrlDecode(Context.User.Identity.Name)));
            }

            await _dbContext.SaveChangesAsync();

            // 刷新用户列表
            await RefreshMemberListAsync(roomHashid, connenction.RoomId);

            // 从分组中删除当前连接
            // 注意 移除必须是在最后做,否则会报错
            await Groups.RemoveAsync(Context.ConnectionId, roomHashid);

            await base.OnDisconnectedAsync(exception);
        }
コード例 #7
0
        /// <summary>
        /// 加入房间
        /// </summary>
        /// <param name="roomHashid">房间哈希ID</param>
        /// <returns>表示加入房间的任务,返回房间名和加入该房间的时间</returns>
        public async Task <ChatRoomInitialDisplayDto> JoinRoomAsync(string roomHashid)
        {
            var roomId   = HashidsHelper.Decode(roomHashid);
            var userId   = HashidsHelper.Decode(Context.User.FindFirst("uid").Value);
            var username = HttpUtility.UrlDecode(Context.User.Identity.Name);

            // 因为用户可能会尝试用一个账号同时登陆两个房间
            // 这里查询条件不加上房间ID,前一个房间内的用户会被提示在别处登录
            var connection = await _dbContext.Connection
                             .FirstOrDefaultAsync(x => x.UserId == userId);

            string msgId             = null;
            string connIdToBeRemoved = null;

            if (connection == null)
            {
                // 第一次进入该房间
                msgId = "I001";
                _dbContext.Add(new Connection
                {
                    RoomId       = roomId,
                    UserId       = userId,
                    Username     = username,
                    ConnectionId = Context.ConnectionId
                });
            }
            else
            {
                // 如果用户同时打开两个窗口
                if (connection.IsOnline.Value)
                {
                    connIdToBeRemoved = connection.ConnectionId;
                }
                // 重连的情况下
                msgId = "I003";
                connection.IsOnline     = true;
                connection.ConnectionId = Context.ConnectionId;
                // 只保留一条记录
                _dbContext.Update(connection);
            }

            await _dbContext.SaveChangesAsync();

            // 将用户添加到分组
            await Groups.AddAsync(Context.ConnectionId, roomHashid);

            // 只加载加入房间前的消息,避免消息重复显示
            long unixTimeMilliseconds = new DateTimeOffset(DateTime.Now).ToUnixTimeMilliseconds();

            // 显示欢迎用户加入房间的消息
            await Clients.Group(roomHashid).InvokeAsync(
                "receiveSystemMessage",
                _msg.GetMessage(msgId, username));

            if (!string.IsNullOrEmpty(connIdToBeRemoved))
            {
                // 前一个窗口显示消息,告知账号已经在其他地方登陆
                await Clients.Client(connIdToBeRemoved).InvokeAsync("onDuplicateLogin");

                await Groups.RemoveAsync(connIdToBeRemoved, roomHashid);
            }

            // 显示用户列表
            await RefreshMemberListAsync(roomHashid, roomId);

            var room = await _dbContext.ChatRoom
                       .Where(r => r.Id == roomId)
                       .Select(r => new { r.Name, r.OwnerId })
                       .FirstOrDefaultAsync();

            return(new ChatRoomInitialDisplayDto
            {
                OwnerId = HashidsHelper.Encode(room.OwnerId),
                RoomName = room.Name,
                EntryTime = unixTimeMilliseconds
            });
        }
コード例 #8
0
        /// <summary>
        /// 获取房间列表
        /// </summary>
        /// <param name="keyword">关键词</param>
        /// <param name="page">页码</param>
        /// <param name="uid">用户ID</param>
        /// <param name="role">用户角色</param>
        /// <returns>表示异步获取房间列表的任务,如果创建失败则返回错误信息</returns>
        public async Task <ChatRoomSearchResponseDto> GetRoomList(string keyword, int page, int uid, Roles role)
        {
            // 房主和管理员可以像正常房间一样检索隐藏房间
            IQueryable <ChatRoom> query = null;

            if (string.IsNullOrEmpty(keyword))
            {
                query = from room in _dbContext.ChatRoom
                        where !room.IsHidden.Value ||
                        room.OwnerId == uid || role == Roles.Admin
                        select room;
            }
            else if (role == Roles.Admin)
            {
                query = from room in _dbContext.ChatRoom
                        where room.Name.Contains(keyword) ||
                        room.Owner.Username.Contains(keyword)
                        select room;
            }
            else
            {
                // 因为用三元表达式会报错,所以这里暂时这么写
                query = from room in _dbContext.ChatRoom
                        where
                        ((room.IsHidden.Value && room.OwnerId != uid) && room.Name == keyword)
                        ||
                        ((!room.IsHidden.Value || room.OwnerId == uid) &&
                         (room.Name.Contains(keyword) || room.Owner.Username.Contains(keyword)))
                        select room;
            }

            int count = await query.CountAsync();

            int totalPages = (int)Math.Ceiling(((decimal)count / 10));

            page = Math.Min(page, totalPages);

            ChatRoomSearchResponseDto chatRoomListDto = new ChatRoomSearchResponseDto();

            // 小于0的判断是为了防止不正当数据
            if (page <= 0)
            {
                return(chatRoomListDto);
            }

            chatRoomListDto.ChatRoomList = await query
                                           .OrderByDescending(room => room.CreateTime)
                                           .Skip((page - 1) * 10)
                                           .Take(10)
                                           .Select(room => new ChatRoomDto
            {
                Id           = HashidsHelper.Encode(room.Id),
                Name         = room.Name,
                MaxUsers     = room.MaxUsers,
                CurrentUsers = room.CurrentUsers,
                OwnerName    = room.Owner.Username,
                IsEncrypted  = room.IsEncrypted.Value,
                IsHidden     = room.IsHidden.Value,
                AllowGuest   = room.AllowGuest.Value,
                CreateTime   = new DateTimeOffset(room.CreateTime).ToUnixTimeMilliseconds()
            }).ToListAsync();

            chatRoomListDto.Pagination = new PaginationDto
            {
                CurrentPage = page,
                TotalPages  = totalPages,
                TotalItems  = count
            };

            return(chatRoomListDto);
        }