Optimize caching on chat member

🐛 Trying to fix uploading file permission check
This commit is contained in:
LittleSheep 2025-05-25 20:18:27 +08:00
parent cbe913e535
commit 33767a6d7f
6 changed files with 37 additions and 46 deletions

View File

@ -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;

View File

@ -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>

View File

@ -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(

View File

@ -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(

View File

@ -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();

View File

@ -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 =>