✨ Lookup stickers and open directly
⚡ Optimize lookup stickers' performance
This commit is contained in:
parent
3d5d4db3e3
commit
b20bc3c443
@ -165,18 +165,21 @@ public class StickerController(AppDatabase db, StickerService st) : ControllerBa
|
|||||||
[HttpGet("lookup/{identifier}")]
|
[HttpGet("lookup/{identifier}")]
|
||||||
public async Task<ActionResult<Sticker>> GetStickerByIdentifier(string identifier)
|
public async Task<ActionResult<Sticker>> GetStickerByIdentifier(string identifier)
|
||||||
{
|
{
|
||||||
IQueryable<Sticker> query = db.Stickers
|
var sticker = await st.LookupStickerByIdentifierAsync(identifier);
|
||||||
.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();
|
|
||||||
|
|
||||||
if (sticker is null) return NotFound();
|
if (sticker is null) return NotFound();
|
||||||
return Ok(sticker);
|
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}")]
|
[HttpGet("{packId:guid}/content/{id:guid}")]
|
||||||
public async Task<ActionResult<Sticker>> GetSticker(Guid packId, Guid id)
|
public async Task<ActionResult<Sticker>> GetSticker(Guid packId, Guid id)
|
||||||
{
|
{
|
||||||
|
@ -1,10 +1,17 @@
|
|||||||
using DysonNetwork.Sphere.Storage;
|
using DysonNetwork.Sphere.Storage;
|
||||||
using Microsoft.EntityFrameworkCore;
|
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)
|
public async Task<Sticker> CreateStickerAsync(Sticker sticker)
|
||||||
{
|
{
|
||||||
db.Stickers.Add(sticker);
|
db.Stickers.Add(sticker);
|
||||||
@ -14,7 +21,6 @@ public class StickerService(AppDatabase db, FileService fs)
|
|||||||
|
|
||||||
return sticker;
|
return sticker;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<Sticker> UpdateStickerAsync(Sticker sticker, CloudFile? newImage)
|
public async Task<Sticker> UpdateStickerAsync(Sticker sticker, CloudFile? newImage)
|
||||||
{
|
{
|
||||||
if (newImage != null)
|
if (newImage != null)
|
||||||
@ -27,16 +33,20 @@ public class StickerService(AppDatabase db, FileService fs)
|
|||||||
db.Stickers.Update(sticker);
|
db.Stickers.Update(sticker);
|
||||||
await db.SaveChangesAsync();
|
await db.SaveChangesAsync();
|
||||||
|
|
||||||
|
// Invalidate cache for this sticker
|
||||||
|
InvalidateStickerCache(sticker);
|
||||||
|
|
||||||
return sticker;
|
return sticker;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task DeleteStickerAsync(Sticker sticker)
|
public async Task DeleteStickerAsync(Sticker sticker)
|
||||||
{
|
{
|
||||||
db.Stickers.Remove(sticker);
|
db.Stickers.Remove(sticker);
|
||||||
await db.SaveChangesAsync();
|
await db.SaveChangesAsync();
|
||||||
await fs.MarkUsageAsync(sticker.Image, -1);
|
await fs.MarkUsageAsync(sticker.Image, -1);
|
||||||
}
|
|
||||||
|
|
||||||
|
// Invalidate cache for this sticker
|
||||||
|
InvalidateStickerCache(sticker);
|
||||||
|
}
|
||||||
public async Task DeleteStickerPackAsync(StickerPack pack)
|
public async Task DeleteStickerPackAsync(StickerPack pack)
|
||||||
{
|
{
|
||||||
var stickers = await db.Stickers
|
var stickers = await db.Stickers
|
||||||
@ -51,5 +61,47 @@ public class StickerService(AppDatabase db, FileService fs)
|
|||||||
await db.SaveChangesAsync();
|
await db.SaveChangesAsync();
|
||||||
|
|
||||||
await fs.MarkUsageRangeAsync(images, -1);
|
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}");
|
||||||
}
|
}
|
||||||
}
|
}
|
Loading…
x
Reference in New Issue
Block a user