From 5f69d8ac80e29895d52472439fa85adb116436b8 Mon Sep 17 00:00:00 2001 From: LittleSheep Date: Thu, 29 May 2025 01:29:15 +0800 Subject: [PATCH] :zap: Better cloud file allocation and free in chat --- DysonNetwork.Sphere/Chat/ChatController.cs | 47 +++++---------- DysonNetwork.Sphere/Chat/ChatService.cs | 70 +++++++++++++++++++++- 2 files changed, 82 insertions(+), 35 deletions(-) diff --git a/DysonNetwork.Sphere/Chat/ChatController.cs b/DysonNetwork.Sphere/Chat/ChatController.cs index 46c5ea2..bc612fc 100644 --- a/DysonNetwork.Sphere/Chat/ChatController.cs +++ b/DysonNetwork.Sphere/Chat/ChatController.cs @@ -229,27 +229,22 @@ public partial class ChatController(AppDatabase db, ChatService cs, FileService var message = await db.ChatMessages .Include(m => m.Sender) .Include(m => m.Sender.Account) - .Include(m => m.Sender.Account.Profile).Include(message => message.Attachments) + .Include(m => m.Sender.Account.Profile) + .Include(message => message.Attachments) .Include(message => message.ChatRoom) .FirstOrDefaultAsync(m => m.Id == messageId && m.ChatRoomId == roomId); + if (message == null) return NotFound(); if (message.Sender.AccountId != currentUser.Id) return StatusCode(403, "You can only edit your own messages."); - if (request.Content is not null) - message.Content = request.Content; - if (request.Meta is not null) - message.Meta = request.Meta; - if (request.RepliedMessageId.HasValue) { var repliedMessage = await db.ChatMessages .FirstOrDefaultAsync(m => m.Id == request.RepliedMessageId.Value && m.ChatRoomId == roomId); if (repliedMessage == null) return BadRequest("The message you're replying to does not exist."); - - message.RepliedMessageId = repliedMessage.Id; } if (request.ForwardedMessageId.HasValue) @@ -258,24 +253,16 @@ public partial class ChatController(AppDatabase db, ChatService cs, FileService .FirstOrDefaultAsync(m => m.Id == request.ForwardedMessageId.Value); if (forwardedMessage == null) return BadRequest("The message you're forwarding does not exist."); - - message.ForwardedMessageId = forwardedMessage.Id; } - if (request.AttachmentsId is not null) - { - message.Attachments = (await fs.DiffAndMarkFilesAsync(request.AttachmentsId, message.Attachments)).current; - await fs.DiffAndSetExpiresAsync(request.AttachmentsId, Duration.FromDays(30), message.Attachments); - } - - message.EditedAt = SystemClock.Instance.GetCurrentInstant(); - db.Update(message); - await db.SaveChangesAsync(); - _ = cs.DeliverMessageAsync( - message, - message.Sender, - message.ChatRoom, - WebSocketPacketType.MessageUpdate + // Call service method to update the message + await cs.UpdateMessageAsync( + message, + request.Meta, + request.Content, + request.RepliedMessageId, + request.ForwardedMessageId, + request.AttachmentsId ); return Ok(message); @@ -290,20 +277,16 @@ public partial class ChatController(AppDatabase db, ChatService cs, FileService var message = await db.ChatMessages .Include(m => m.Sender) .Include(m => m.ChatRoom) + .Include(m => m.Attachments) .FirstOrDefaultAsync(m => m.Id == messageId && m.ChatRoomId == roomId); + if (message == null) return NotFound(); if (message.Sender.AccountId != currentUser.Id) return StatusCode(403, "You can only delete your own messages."); - db.ChatMessages.Remove(message); - await db.SaveChangesAsync(); - _ = cs.DeliverMessageAsync( - message, - message.Sender, - message.ChatRoom, - WebSocketPacketType.MessageDelete - ); + // Call service method to delete the message + await cs.DeleteMessageAsync(message); return Ok(); } diff --git a/DysonNetwork.Sphere/Chat/ChatService.cs b/DysonNetwork.Sphere/Chat/ChatService.cs index b5eaca0..ad68038 100644 --- a/DysonNetwork.Sphere/Chat/ChatService.cs +++ b/DysonNetwork.Sphere/Chat/ChatService.cs @@ -14,6 +14,8 @@ public class ChatService( IRealtimeService realtime ) { + private const string ChatFileUsageIdentifier = "chat"; + public async Task SendMessageAsync(Message message, ChatMember sender, ChatRoom room) { if (string.IsNullOrWhiteSpace(message.Nonce)) message.Nonce = Guid.NewGuid().ToString(); @@ -29,12 +31,11 @@ public class ChatService( { await fs.MarkUsageRangeAsync(files, 1); await fs.SetExpiresRangeAsync(files, Duration.FromDays(30)); + await fs.SetUsageRangeAsync(files, ChatFileUsageIdentifier); } // Then start the delivery process - // Using ConfigureAwait(false) is correct here since we don't need context to flow - _ = Task.Run(() => DeliverMessageAsync(message, sender, room)) - .ConfigureAwait(false); + _ = Task.Run(() => DeliverMessageAsync(message, sender, room)); return message; } @@ -276,6 +277,69 @@ public class ChatService( CurrentTimestamp = SystemClock.Instance.GetCurrentInstant() }; } + + public async Task UpdateMessageAsync( + Message message, + Dictionary? meta = null, + string? content = null, + Guid? repliedMessageId = null, + Guid? forwardedMessageId = null, + List? attachmentsId = null + ) + { + if (content is not null) + message.Content = content; + + if (meta is not null) + message.Meta = meta; + + if (repliedMessageId.HasValue) + message.RepliedMessageId = repliedMessageId; + + if (forwardedMessageId.HasValue) + message.ForwardedMessageId = forwardedMessageId; + + if (attachmentsId is not null) + { + message.Attachments = (await fs.DiffAndMarkFilesAsync(attachmentsId, message.Attachments)).current; + await fs.DiffAndSetExpiresAsync(attachmentsId, Duration.FromDays(30), message.Attachments); + await fs.DiffAndSetUsageAsync(attachmentsId, ChatFileUsageIdentifier, message.Attachments); + } + + message.EditedAt = SystemClock.Instance.GetCurrentInstant(); + db.Update(message); + await db.SaveChangesAsync(); + + _ = DeliverMessageAsync( + message, + message.Sender, + message.ChatRoom, + WebSocketPacketType.MessageUpdate + ); + + return message; + } + + /// + /// Deletes a message and notifies other chat members + /// + /// The message to delete + public async Task DeleteMessageAsync(Message message) + { + var files = message.Attachments.Distinct().ToList(); + if (files.Count != 0) + await fs.MarkUsageRangeAsync(files, -1); + + db.ChatMessages.Remove(message); + await db.SaveChangesAsync(); + + _ = DeliverMessageAsync( + message, + message.Sender, + message.ChatRoom, + WebSocketPacketType.MessageDelete + ); + } } public class MessageChangeAction