From 7dbcc456b98046ffc734d38aba7ee926389ceb8f Mon Sep 17 00:00:00 2001 From: Spirtix Date: Mon, 30 Jun 2025 19:33:49 +0200 Subject: [PATCH] async locking for VikingSession --- src/Attributes/VikingSession.cs | 33 ++++++++++++++++++++++++++++----- 1 file changed, 28 insertions(+), 5 deletions(-) diff --git a/src/Attributes/VikingSession.cs b/src/Attributes/VikingSession.cs index e93eb2b..044adaf 100644 --- a/src/Attributes/VikingSession.cs +++ b/src/Attributes/VikingSession.cs @@ -1,5 +1,6 @@ using Microsoft.AspNetCore.Mvc.Filters; using Microsoft.AspNetCore.Mvc; +using Microsoft.EntityFrameworkCore; using sodoff.Model; namespace sodoff.Attributes; @@ -12,6 +13,9 @@ public class VikingSession : Attribute, IAsyncActionFilter { public Modes Mode { get; set; } = Modes.VIKING; public bool UseLock = false; + private static Dictionary semaphores = new(); + private static SemaphoreSlim dictSemaphore = new(1, 1); + public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next) { DBContext ctx = context.HttpContext.RequestServices.GetService(typeof(DBContext)) as DBContext; @@ -22,7 +26,7 @@ public class VikingSession : Attribute, IAsyncActionFilter { return; } - Session? session = ctx.Sessions.FirstOrDefault(x => x.ApiToken == Guid.Parse(context.HttpContext.Request.Form[ApiToken].ToString())); + Session? session = await ctx.Sessions.FirstOrDefaultAsync(x => x.ApiToken == Guid.Parse(context.HttpContext.Request.Form[ApiToken].ToString())); // get viking / user id from session @@ -44,15 +48,16 @@ public class VikingSession : Attribute, IAsyncActionFilter { // NOTE: we can't refer to session.User / session.Viking here, // because it may cause to ignore modifications from the threads we are waiting for // we can use its only after vikingMutex.WaitOne() - - Mutex vikingMutex = new Mutex(false, "SoDOffViking:" + userVikingId); + string semKey = "SoDOffViking:" + userVikingId; + SemaphoreSlim semaphore = await GetSemaphore(semKey); try { - vikingMutex.WaitOne(); + await semaphore.WaitAsync(); context.ActionArguments["user"] = session.User; context.ActionArguments["viking"] = session.Viking; await next(); } finally { - vikingMutex.ReleaseMutex(); + semaphore.Release(); + await RemoveSemaphore(semKey, semaphore); } } else { context.ActionArguments["user"] = session.User; @@ -60,4 +65,22 @@ public class VikingSession : Attribute, IAsyncActionFilter { await next(); } } + + private static async Task GetSemaphore(string key) { + await dictSemaphore.WaitAsync(); + if (!semaphores.TryGetValue(key, out SemaphoreSlim semaphore)) { + semaphore = new SemaphoreSlim(1, 1); + semaphores.Add(key, semaphore); + } + dictSemaphore.Release(); + return semaphore; + } + + private static async Task RemoveSemaphore(string key, SemaphoreSlim sem) { + await dictSemaphore.WaitAsync(); + if (sem.CurrentCount == 1) { + semaphores.Remove(key); + } + dictSemaphore.Release(); + } }