Lookup stickers and open directly

 Optimize lookup stickers' performance
This commit is contained in:
LittleSheep 2025-05-11 22:27:50 +08:00
parent 3d5d4db3e3
commit b20bc3c443
2 changed files with 68 additions and 13 deletions

View File

@ -165,17 +165,20 @@ public class StickerController(AppDatabase db, StickerService st) : ControllerBa
[HttpGet("lookup/{identifier}")]
public async Task<ActionResult<Sticker>> GetStickerByIdentifier(string identifier)
{
IQueryable<Sticker> query = db.Stickers
.Include(e => e.Pack)
.Include(e => e.Image);
query = Guid.TryParse(identifier, out var guid)
? query.Where(e => e.Id == guid)
: query.Where(e => e.Pack.Prefix + e.Slug == identifier);
var sticker = await query.FirstOrDefaultAsync();
var sticker = await st.LookupStickerByIdentifierAsync(identifier);
if (sticker is null) return NotFound();
return Ok(sticker);
}
[HttpGet("lookup/{identifier}/open")]
public async Task<ActionResult<Sticker>> OpenStickerByIdentifier(string identifier)
{
var sticker = await st.LookupStickerByIdentifierAsync(identifier);
if (sticker is null) return NotFound();
return Redirect($"/files/{sticker.ImageId}");
}
[HttpGet("{packId:guid}/content/{id:guid}")]
public async Task<ActionResult<Sticker>> GetSticker(Guid packId, Guid id)

View File

@ -1,10 +1,17 @@
using DysonNetwork.Sphere.Storage;
using Microsoft.EntityFrameworkCore;
namespace DysonNetwork.Sphere.Sticker;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Caching.Memory;
using System;
using System.Linq;
using System.Threading.Tasks;
public class StickerService(AppDatabase db, FileService fs)
namespace DysonNetwork.Sphere.Sticker;
public class StickerService(AppDatabase db, FileService fs, IMemoryCache cache)
{
private static readonly TimeSpan CacheDuration = TimeSpan.FromMinutes(15);
public async Task<Sticker> CreateStickerAsync(Sticker sticker)
{
db.Stickers.Add(sticker);
@ -14,7 +21,6 @@ public class StickerService(AppDatabase db, FileService fs)
return sticker;
}
public async Task<Sticker> UpdateStickerAsync(Sticker sticker, CloudFile? newImage)
{
if (newImage != null)
@ -26,17 +32,21 @@ public class StickerService(AppDatabase db, FileService fs)
db.Stickers.Update(sticker);
await db.SaveChangesAsync();
// Invalidate cache for this sticker
InvalidateStickerCache(sticker);
return sticker;
}
public async Task DeleteStickerAsync(Sticker sticker)
{
db.Stickers.Remove(sticker);
await db.SaveChangesAsync();
await fs.MarkUsageAsync(sticker.Image, -1);
// Invalidate cache for this sticker
InvalidateStickerCache(sticker);
}
public async Task DeleteStickerPackAsync(StickerPack pack)
{
var stickers = await db.Stickers
@ -51,5 +61,47 @@ public class StickerService(AppDatabase db, FileService fs)
await db.SaveChangesAsync();
await fs.MarkUsageRangeAsync(images, -1);
// Invalidate cache for all stickers in this pack
foreach (var sticker in stickers)
{
InvalidateStickerCache(sticker);
}
}
public async Task<Sticker?> LookupStickerByIdentifierAsync(string identifier)
{
// Try to get from cache first
string cacheKey = $"StickerLookup_{identifier}";
if (cache.TryGetValue(cacheKey, out Sticker? cachedSticker))
{
return cachedSticker;
}
// If not in cache, fetch from database
IQueryable<Sticker> query = db.Stickers
.Include(e => e.Pack)
.Include(e => e.Image);
query = Guid.TryParse(identifier, out var guid)
? query.Where(e => e.Id == guid)
: query.Where(e => e.Pack.Prefix + e.Slug == identifier);
var sticker = await query.FirstOrDefaultAsync();
// Store in cache if found
if (sticker != null)
{
cache.Set(cacheKey, sticker, CacheDuration);
}
return sticker;
}
private void InvalidateStickerCache(Sticker sticker)
{
// Remove both possible cache entries
cache.Remove($"StickerLookup_{sticker.Id}");
cache.Remove($"StickerLookup_{sticker.Pack.Prefix}{sticker.Slug}");
}
}