[backend/api] Improve notifications endpoint performance when rendering multiple custom emojis

This commit is contained in:
Laura Hausmann 2025-03-23 14:02:47 +01:00
parent 1af21062fb
commit ccf93a06aa
No known key found for this signature in database
GPG key ID: D044E84C5BE01605

View file

@ -1,8 +1,11 @@
using Iceshrimp.Backend.Core.Configuration; using Iceshrimp.Backend.Core.Configuration;
using Iceshrimp.Backend.Core.Database;
using Iceshrimp.Backend.Core.Database.Tables; using Iceshrimp.Backend.Core.Database.Tables;
using Iceshrimp.Backend.Core.Extensions; using Iceshrimp.Backend.Core.Extensions;
using Iceshrimp.Backend.Core.Services; using Iceshrimp.Backend.Core.Services;
using Iceshrimp.EntityFrameworkCore.Extensions;
using Iceshrimp.Shared.Schemas.Web; using Iceshrimp.Shared.Schemas.Web;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Options; using Microsoft.Extensions.Options;
using static Iceshrimp.Shared.Schemas.Web.NotificationResponse; using static Iceshrimp.Shared.Schemas.Web.NotificationResponse;
@ -12,7 +15,7 @@ public class NotificationRenderer(
IOptions<Config.InstanceSection> instance, IOptions<Config.InstanceSection> instance,
UserRenderer userRenderer, UserRenderer userRenderer,
NoteRenderer noteRenderer, NoteRenderer noteRenderer,
EmojiService emojiSvc DatabaseContext db
) : IScopedService ) : IScopedService
{ {
private static NotificationResponse Render(Notification notification, NotificationRendererDto data) private static NotificationResponse Render(Notification notification, NotificationRendererDto data)
@ -114,21 +117,44 @@ public class NotificationRenderer(
Sensitive = false Sensitive = false
}) })
.ToList(); .ToList();
var custom = reactions.Where(EmojiService.IsCustomEmoji).ToArray();
var custom = reactions.Where(EmojiService.IsCustomEmoji)
.Select(p =>
{
var parts = p.Trim(':').Split('@');
return (name: parts[0], host: parts.Length > 1 ? parts[1] : null);
})
.Distinct()
.ToArray();
var expr = ExpressionExtensions.False<Emoji>();
expr = custom.Aggregate(expr, (current, part) => current.Or(p => p.Name == part.name && p.Host == part.host));
// https://github.com/dotnet/efcore/issues/31492
var emojiUrls = await db.Emojis
.Where(expr)
.Select(e => new
{
Name = $":{e.Name}{(e.Host != null ? "@" + e.Host : "")}:",
Url = e.GetAccessUrl(instance.Value),
e.Sensitive
})
.ToDictionaryAsync(e => e.Name, e => new { e.Url, e.Sensitive });
foreach (var s in custom) foreach (var s in custom)
{ {
var emoji = await emojiSvc.ResolveEmojiAsync(s); var name = s.host != null ? $":{s.name}@{s.host}:" : $":{s.name}:";
emojiUrls.TryGetValue(name, out var emoji);
var reaction = emoji != null var reaction = emoji != null
? new ReactionResponse ? new ReactionResponse
{ {
Name = s, Name = name,
Url = emoji.GetAccessUrl(instance.Value), Url = emoji.Url,
Sensitive = emoji.Sensitive Sensitive = emoji.Sensitive
} }
: new ReactionResponse : new ReactionResponse
{ {
Name = s, Name = name,
Url = null, Url = null,
Sensitive = false Sensitive = false
}; };