⚡ Optimize caching on chat member
🐛 Trying to fix uploading file permission check
			
			
This commit is contained in:
		| @@ -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<List<ChatMember>> ListRoomMembers(Guid roomId) | ||||
|     { | ||||
| @@ -31,6 +32,25 @@ public class ChatRoomService(AppDatabase db, ICacheService cache) | ||||
|         return members; | ||||
|     } | ||||
|      | ||||
|     public async Task<ChatMember?> GetChannelMember(Guid accountId, Guid chatRoomId) | ||||
|     { | ||||
|         var cacheKey = string.Format(ChatMemberCacheKey, accountId, chatRoomId); | ||||
|         var member = await cache.GetAsync<ChatMember?>(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; | ||||
|   | ||||
| @@ -228,6 +228,11 @@ public class CallParticipant | ||||
|     /// </summary> | ||||
|     public Guid? AccountId { get; set; } | ||||
|      | ||||
|     /// <summary> | ||||
|     /// The participant's profile in the chat | ||||
|     /// </summary> | ||||
|     public ChatMember? Profile { get; set; } | ||||
|      | ||||
|     /// <summary> | ||||
|     /// When the participant joined the call | ||||
|     /// </summary> | ||||
|   | ||||
| @@ -44,23 +44,7 @@ public class MessageReadHandler( | ||||
|             return; | ||||
|         } | ||||
|  | ||||
|         var cacheKey = string.Format(ChatMemberCacheKey, currentUser.Id, request.ChatRoomId); | ||||
|         var sender = await cache.GetAsync<ChatMember?>(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( | ||||
|   | ||||
| @@ -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<ChatMember?>(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( | ||||
|   | ||||
| @@ -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(); | ||||
|   | ||||
| @@ -46,7 +46,7 @@ builder.WebHost.ConfigureKestrel(options => options.Limits.MaxRequestBodySize = | ||||
| builder.Services.AddLocalization(options => options.ResourcesPath = "Resources"); | ||||
|  | ||||
| builder.Services.AddDbContext<AppDatabase>(); | ||||
| builder.Services.AddSingleton<IConnectionMultiplexer>(_ =>  | ||||
| builder.Services.AddSingleton<IConnectionMultiplexer>(_ => | ||||
| { | ||||
|     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<ReadReceiptFlushJob>(opts => opts.WithIdentity(readReceiptFlushJob)); | ||||
|     q.AddTrigger(opts => opts | ||||
| @@ -286,15 +286,13 @@ app.MapTus("/files/tus", _ => Task.FromResult<DefaultTusConfiguration>(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<PermissionService>(); | ||||
|             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<PermissionService>(); | ||||
|                 var allowed = await pm.HasPermissionAsync($"user:{user.Id}", "global", "files.create"); | ||||
|                 if (!allowed) | ||||
|                     eventContext.FailRequest(HttpStatusCode.Forbidden); | ||||
|             } | ||||
|         }, | ||||
|         OnFileCompleteAsync = async eventContext => | ||||
|   | ||||
		Reference in New Issue
	
	Block a user