/// <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); }
public ActionResult GetCallsAsJson(string contactId) { var calls = _callService.GetAllByContactIdWithUsers(HashidsHelper.Decrypt(contactId)); var vm = calls.Select(x => x.MapTo <CallVm>()); return(Json(new { success = true, data = vm })); }
/// <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)); }
public ActionResult GetCallAsJson(string id) { var call = _callService.GetById(HashidsHelper.Decrypt(id)); var vm = call.MapTo <CallVm>(); return(Json(new { success = true, data = vm })); }
public ActionResult Profile(string id) { var user = _userService.GetByIdWithRoles(HashidsHelper.Decrypt(id)); var vm = user.MapTo <UserVm>(); return(View(vm)); }
public async Task DeleteRoomAsync(string roomHashid) { var roomId = HashidsHelper.Decode(roomHashid); var room = await _dbContext.ChatRoom.FindAsync(roomId); // 当前房间已经被删除则不做处理 if (room == null) { return; } Roles userRole = (Roles)Convert.ToInt32( Context.User.FindFirst(ClaimTypes.Role).Value); int userId = HashidsHelper.Decode(Context.User.FindFirst("uid").Value); // 为了安全做一次判断 // 如果不是房主或者管理员则无权进行删除处理 if (userId != room.OwnerId && userRole != Roles.Admin) { return; } using (var tran = await _dbContext.Database.BeginTransactionAsync()) { try { // 删除房间 _dbContext.ChatRoom.Remove(room); await _dbContext.SaveChangesAsync(); // 删除历史聊天信息 await _dbContext.Database.ExecuteSqlCommandAsync( $"delete from chat_history where room_id = {room.Id}"); // 删除已经离线的用户的连接信息 await _dbContext.Database.ExecuteSqlCommandAsync( $"delete from connection where room_id = {room.Id} and is_online = false"); // 删除存放聊天图片的文件夹 var path = Path.Combine(_picturesDirectory, roomId.ToString()); if (Directory.Exists(path)) { Directory.Delete(path, true); } tran.Commit(); await Clients.Group(roomHashid).InvokeAsync("onRoomDeleted", _msg.GetMessage("E008")); } catch { tran.Rollback(); } } }
public async Task <JsonResult> RefreshTokenAsync() { string hashid = User.FindFirst("uid").Value; return(Json(new { AccessToken = await _tokenAuthService.RefreshTokenAsync(HashidsHelper.Decode(hashid)) })); }
/// <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 }); } }
public CallVm MapToCallVm(Call call) { // Call sınıfında User virtual bir property olduğu için database sorgusunda açıkca include edilmezse // call nesnesinde bu property tanımı olmaz ve buna erişmeye çalışıldığında hata fırlatır. string userFullName; try { userFullName = call.User?.Fullname; } catch { userFullName = null; } return(call == null ? null : new CallVm { Id = HashidsHelper.Encrypt(call.Id), ContactId = HashidsHelper.Encrypt(call.ContactId), UserId = HashidsHelper.Encrypt(call.UserId), UserFullname = userFullName, IsAccess = call.IsAccess, Date = call.Date }); }
/// <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) }); }
public async Task RemoveMemberAsync(string roomHashid, string memberHashid) { int roomId = HashidsHelper.Decode(roomHashid); int userId = HashidsHelper.Decode(Context.User.FindFirst("uid").Value); // 判断用户是否为房主,只有房主才有删除成员的权限 var count = await _dbContext.ChatRoom .CountAsync(room => room.Id == roomId && room.OwnerId == userId); if (count == 0) { return; } int memberId = HashidsHelper.Decode(memberHashid); var connection = await _dbContext.Connection .FirstOrDefaultAsync(conn => conn.UserId == memberId); // 从数据库中删除 _dbContext.Remove(connection); await _dbContext.SaveChangesAsync(); // 通知被删除的用户 await Clients.Client(connection.ConnectionId) .InvokeAsync("onRemoved", _msg.GetMessage("I005", "你")); // 通知房间内其他用户 await Clients.Group(roomHashid) .InvokeAsync("receiveSystemMessage", _msg.GetMessage("I005", connection.Username)); // 刷新成员列表 await RefreshMemberListAsync(roomHashid, roomId); await Groups.RemoveAsync(connection.ConnectionId, roomHashid); }
/// <summary> /// 发送消息 /// </summary> /// <param name="roomHashid">房间哈希ID</param> /// <param name="message">消息</param> /// <returns>表示发送消息的任务</returns> public async Task SendMessageAsync(string roomHashid, string message) { var userHashId = Context.User.FindFirst("uid").Value; var username = HttpUtility.UrlDecode(Context.User.Identity.Name); var unixTimeMilliseconds = new DateTimeOffset(DateTime.Now).ToUnixTimeMilliseconds(); await Clients.Group(roomHashid) .InvokeAsync("receiveMessage", userHashId, username, message, unixTimeMilliseconds, false); // 将消息保存到数据库 var history = new ChatHistory { RoomId = HashidsHelper.Decode(roomHashid), UserId = HashidsHelper.Decode(userHashId), UnixTimeMilliseconds = unixTimeMilliseconds, Username = username, Message = message }; _dbContext.ChatHistory.Add(history); await _dbContext.SaveChangesAsync(); }
/// <summary> /// 离开房间 /// </summary> /// <param name="roomHashid">房间哈希ID</param> /// <returns>表示离开房间的任务</returns> public async Task LeaveRoomAsync(string roomHashid) { var roomId = HashidsHelper.Decode(roomHashid); int userId = HashidsHelper.Decode(Context.User.FindFirst("uid").Value); var count = await _dbContext .Connection .CountAsync(conn => conn.RoomId == roomId && conn.UserId == userId && conn.ConnectionId == Context.ConnectionId); // 如果用户开了多个窗口的话,这边可能会出问题 // 或者用户被移出房间 if (count == 0) { return; } // 通知同一房间里其他人该用户已经离开房间 await Clients.Group(roomHashid).InvokeAsync( "receiveSystemMessage", _msg.GetMessage("I004", HttpUtility.UrlDecode(Context.User.Identity.Name))); var room = await _dbContext.ChatRoom.FirstOrDefaultAsync(x => x.Id == roomId); // 如果该房间已经被删除的话 if (room == null) { return; } // 如果不是永久房,则房主离开,就意味着房间要被解散 if (room.OwnerId == userId && !room.IsPermanent.Value) { await DeleteRoomAsync(roomHashid); } }
/// <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); }
public ContactVm MapToContactVm(Contact contact) { return(contact == null ? null : new ContactVm { Id = HashidsHelper.Encrypt(contact.Id), Phone = contact.Phone, CallReason = contact.CallReason, CallResult = contact.CallResult, Date = contact.Date }); }
/// <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); }
public async Task <string> GetRegistrationTimeAsync() { string hashid = User.FindFirst("uid").Value; return(await _userProfileService.GetRegistrationTimeAsync(HashidsHelper.Decode(hashid))); }
public Call MapToCall(CallVm vm) { return(vm == null ? null : new Call { Id = HashidsHelper.Decrypt(vm.Id), ContactId = HashidsHelper.Decrypt(vm.ContactId), Date = vm.Date, IsAccess = vm.IsAccess }); }
public Contact MapToContact(ContactVm vm) { return(vm == null ? null : new Contact { Id = HashidsHelper.Decrypt(vm.Id), Phone = vm.Phone, CallReason = vm.CallReason, CallResult = vm.CallResult, Date = vm.Date }); }
public ActionResult GetContactAsJson(string id) { var vm = _contactService.GetById(HashidsHelper.Decrypt(id)).MapTo <ContactVm>(); return(Json(new { success = true, data = vm }, JsonRequestBehavior.AllowGet)); }
public ActionResult Delete(string id) { _contactService.DeleteById(HashidsHelper.Decrypt(id)); return(Json(new { success = true, message = C.Message.Success })); }
public ActionResult Create(ContactVm model) { var contact = _contactService.Add(model.MapTo <Contact>()); return(Json(new { success = true, message = C.Message.Success, contactId = HashidsHelper.Encrypt(contact.Id) })); }
public async Task <AccessTokenResponseDto> UpdatePasswordAsync([FromBody] UserUpdatePasswordRequestDto passwordDto) { string hashid = User.FindFirst("uid").Value; return(await _userProfileService.UpdatePasswordAsync(HashidsHelper.Decode(hashid), passwordDto.NewPassword)); }
/// <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 }); }
/// <summary> /// 发送图片 /// </summary> /// <param name="roomHashid">房间哈希ID</param> /// <param name="base64String">图片数据对应的base64String字符串</param> /// <returns>表示发送图片的任务</returns> public async Task SendPictureAsync(string roomHashid, string base64String) { var roomId = HashidsHelper.Decode(roomHashid); var userHashId = Context.User.FindFirst("uid").Value; var userId = HashidsHelper.Decode(userHashId); var username = HttpUtility.UrlDecode(Context.User.Identity.Name); var unixTimeMilliseconds = new DateTimeOffset(DateTime.Now).ToUnixTimeMilliseconds(); string dirOriginal = Path.Combine(_picturesDirectory, roomId.ToString(), "originals"); string dirThumbnail = Path.Combine(_picturesDirectory, roomId.ToString(), "thumbnails"); Directory.CreateDirectory(dirOriginal); Directory.CreateDirectory(dirThumbnail); // 获取图片数据 var bytes = Convert.FromBase64String(base64String); var img = Image.FromStream(new MemoryStream(bytes)); var isGif = _imageService.IsGif(img); var extension = isGif ? ".gif" : ".jpg"; var pathOriginal = Path.Combine(dirOriginal, $"{userId}_{unixTimeMilliseconds}{extension}"); var pathThumbnail = Path.Combine(dirThumbnail, $"{userId}_{unixTimeMilliseconds}.jpg"); // 保存图片 if (isGif) { // 如果是gif则直接保存 await File.WriteAllBytesAsync(pathOriginal, bytes); } else { // 不是gif则进行适当压缩后保存 _imageService.SaveAsThumbnailImage(bytes, pathOriginal, 1920, 1080, 95); } // 保存缩略图 _imageService.SaveAsThumbnailImage(bytes, pathThumbnail, 250, 250, 95); // 会自动进行base64的转换 await Clients.Group(roomHashid) .InvokeAsync("receiveMessage", userHashId, username, await File.ReadAllBytesAsync(pathThumbnail), unixTimeMilliseconds, true); // 将消息保存到数据库 var history = new ChatHistory { RoomId = roomId, UserId = userId, UnixTimeMilliseconds = unixTimeMilliseconds, Username = username, IsPicture = true }; _dbContext.ChatHistory.Add(history); await _dbContext.SaveChangesAsync(); // 后台执行图片压缩任务 // 不等待 if (isGif) { Task noWarning = _imageService.TinifyAsync(pathThumbnail); } else { Task noWarning = _imageService.TinifyAsync(pathOriginal, pathThumbnail); } }
/// <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); }