From 33767a6d7fc3d2a469198e8f429c2b29ba9f9806 Mon Sep 17 00:00:00 2001 From: LittleSheep Date: Sun, 25 May 2025 20:18:27 +0800 Subject: [PATCH] :zap: Optimize caching on chat member :bug: Trying to fix uploading file permission check --- DysonNetwork.Sphere/Chat/ChatRoomService.cs | 20 +++++++++++++++++++ .../Chat/RealtimeCallController.cs | 5 +++++ .../Connection/Handlers/MessageReadHandler.cs | 18 +---------------- .../Handlers/MessageTypingHandler.cs | 18 +---------------- .../Permission/PermissionService.cs | 4 ++-- DysonNetwork.Sphere/Program.cs | 18 ++++++++--------- 6 files changed, 37 insertions(+), 46 deletions(-) diff --git a/DysonNetwork.Sphere/Chat/ChatRoomService.cs b/DysonNetwork.Sphere/Chat/ChatRoomService.cs index f723660..b232990 100644 --- a/DysonNetwork.Sphere/Chat/ChatRoomService.cs +++ b/DysonNetwork.Sphere/Chat/ChatRoomService.cs @@ -9,6 +9,7 @@ public class ChatRoomService(AppDatabase db, ICacheService cache) { public const string ChatRoomGroupPrefix = "ChatRoom_"; private const string RoomMembersCacheKeyPrefix = "ChatRoomMembers_"; + private const string ChatMemberCacheKey = "ChatMember_{0}_{1}"; public async Task> ListRoomMembers(Guid roomId) { @@ -31,6 +32,25 @@ public class ChatRoomService(AppDatabase db, ICacheService cache) return members; } + public async Task GetChannelMember(Guid accountId, Guid chatRoomId) + { + var cacheKey = string.Format(ChatMemberCacheKey, accountId, chatRoomId); + var member = await cache.GetAsync(cacheKey); + if (member is not null) return member; + + member = await db.ChatMembers + .Where(m => m.AccountId == accountId && m.ChatRoomId == chatRoomId) + .FirstOrDefaultAsync(); + + if (member == null) return member; + var chatRoomGroup = ChatRoomGroupPrefix + chatRoomId; + await cache.SetWithGroupsAsync(cacheKey, member, + [chatRoomGroup], + TimeSpan.FromMinutes(5)); + + return member; + } + public async Task PurgeRoomMembersCache(Guid roomId) { var chatRoomGroup = ChatRoomGroupPrefix + roomId; diff --git a/DysonNetwork.Sphere/Chat/RealtimeCallController.cs b/DysonNetwork.Sphere/Chat/RealtimeCallController.cs index 7088223..dac62ee 100644 --- a/DysonNetwork.Sphere/Chat/RealtimeCallController.cs +++ b/DysonNetwork.Sphere/Chat/RealtimeCallController.cs @@ -228,6 +228,11 @@ public class CallParticipant /// public Guid? AccountId { get; set; } + /// + /// The participant's profile in the chat + /// + public ChatMember? Profile { get; set; } + /// /// When the participant joined the call /// diff --git a/DysonNetwork.Sphere/Connection/Handlers/MessageReadHandler.cs b/DysonNetwork.Sphere/Connection/Handlers/MessageReadHandler.cs index 625cff0..4b5742b 100644 --- a/DysonNetwork.Sphere/Connection/Handlers/MessageReadHandler.cs +++ b/DysonNetwork.Sphere/Connection/Handlers/MessageReadHandler.cs @@ -44,23 +44,7 @@ public class MessageReadHandler( return; } - var cacheKey = string.Format(ChatMemberCacheKey, currentUser.Id, request.ChatRoomId); - var sender = await cache.GetAsync(cacheKey); - if (sender is null) - { - sender = await db.ChatMembers - .Where(m => m.AccountId == currentUser.Id && m.ChatRoomId == request.ChatRoomId) - .FirstOrDefaultAsync(); - - if (sender != null) - { - var chatRoomGroup = ChatRoomService.ChatRoomGroupPrefix + request.ChatRoomId; - await cache.SetWithGroupsAsync(cacheKey, sender, - [chatRoomGroup], - TimeSpan.FromMinutes(5)); - } - } - + var sender = await crs.GetChannelMember(currentUser.Id, request.ChatRoomId); if (sender is null) { await socket.SendAsync( diff --git a/DysonNetwork.Sphere/Connection/Handlers/MessageTypingHandler.cs b/DysonNetwork.Sphere/Connection/Handlers/MessageTypingHandler.cs index 11e4dd9..4018e53 100644 --- a/DysonNetwork.Sphere/Connection/Handlers/MessageTypingHandler.cs +++ b/DysonNetwork.Sphere/Connection/Handlers/MessageTypingHandler.cs @@ -33,23 +33,7 @@ public class MessageTypingHandler(AppDatabase db, ChatRoomService crs, ICacheSer return; } - var cacheKey = string.Format(MessageReadHandler.ChatMemberCacheKey, currentUser.Id, request.ChatRoomId); - var sender = await cache.GetAsync(cacheKey); - if (sender is null) - { - sender = await db.ChatMembers - .Where(m => m.AccountId == currentUser.Id && m.ChatRoomId == request.ChatRoomId) - .FirstOrDefaultAsync(); - - if (sender != null) - { - var chatRoomGroup = ChatRoomService.ChatRoomGroupPrefix + request.ChatRoomId; - await cache.SetWithGroupsAsync(cacheKey, sender, - [chatRoomGroup], - TimeSpan.FromMinutes(5)); - } - } - + var sender = await crs.GetChannelMember(currentUser.Id, request.ChatRoomId); if (sender is null) { await socket.SendAsync( diff --git a/DysonNetwork.Sphere/Permission/PermissionService.cs b/DysonNetwork.Sphere/Permission/PermissionService.cs index 2c5be15..a3e49ba 100644 --- a/DysonNetwork.Sphere/Permission/PermissionService.cs +++ b/DysonNetwork.Sphere/Permission/PermissionService.cs @@ -48,7 +48,7 @@ public class PermissionService( if (groupsId == null) { groupsId = await db.PermissionGroupMembers - .Where(n => n.Actor == "user:" + actor) + .Where(n => n.Actor == actor) .Where(n => n.ExpiredAt == null || n.ExpiredAt < now) .Where(n => n.AffectedAt == null || n.AffectedAt >= now) .Select(e => e.GroupId) @@ -61,7 +61,7 @@ public class PermissionService( var permission = await db.PermissionNodes .Where(n => n.GroupId == null || groupsId.Contains(n.GroupId.Value)) - .Where(n => (n.Key == key || n.Key == "*") && (n.GroupId != null || n.Actor == actor) && n.Area == area) + .Where(n => n.Key == key && (n.GroupId != null || n.Actor == actor) && n.Area == area) .Where(n => n.ExpiredAt == null || n.ExpiredAt < now) .Where(n => n.AffectedAt == null || n.AffectedAt >= now) .FirstOrDefaultAsync(); diff --git a/DysonNetwork.Sphere/Program.cs b/DysonNetwork.Sphere/Program.cs index 0f0984a..d7d468a 100644 --- a/DysonNetwork.Sphere/Program.cs +++ b/DysonNetwork.Sphere/Program.cs @@ -46,7 +46,7 @@ builder.WebHost.ConfigureKestrel(options => options.Limits.MaxRequestBodySize = builder.Services.AddLocalization(options => options.ResourcesPath = "Resources"); builder.Services.AddDbContext(); -builder.Services.AddSingleton(_ => +builder.Services.AddSingleton(_ => { var connection = builder.Configuration.GetConnectionString("FastRetrieve")!; return ConnectionMultiplexer.Connect(connection); @@ -209,7 +209,7 @@ builder.Services.AddQuartz(q => .WithIntervalInMinutes(5) .RepeatForever()) ); - + var readReceiptFlushJob = new JobKey("ReadReceiptFlush"); q.AddJob(opts => opts.WithIdentity(readReceiptFlushJob)); q.AddTrigger(opts => opts @@ -286,15 +286,13 @@ app.MapTus("/files/tus", _ => Task.FromResult(new() return; } - var userId = httpContext.User.FindFirst("user_id")?.Value; - if (userId == null) return; - - using var scope = httpContext.RequestServices.CreateScope(); - var pm = scope.ServiceProvider.GetRequiredService(); - var allowed = await pm.HasPermissionAsync($"user:{userId}", "global", "files.create"); - if (!allowed) + if (!user.IsSuperuser) { - eventContext.FailRequest(HttpStatusCode.Forbidden); + using var scope = httpContext.RequestServices.CreateScope(); + var pm = scope.ServiceProvider.GetRequiredService(); + var allowed = await pm.HasPermissionAsync($"user:{user.Id}", "global", "files.create"); + if (!allowed) + eventContext.FailRequest(HttpStatusCode.Forbidden); } }, OnFileCompleteAsync = async eventContext =>