Make IdentityCacheObject IAsyncDisposable

Closes #1733
This commit is contained in:
Jordan Dominion
2024-04-20 10:34:36 -04:00
parent 69c83582cb
commit 80b50a4426
4 changed files with 41 additions and 34 deletions
@@ -357,7 +357,7 @@ namespace Tgstation.Server.Host.Controllers
var identExpiry = token.ParseJwt().ValidTo;
identExpiry += tokenFactory.ValidationParameters.ClockSkew;
identExpiry += TimeSpan.FromSeconds(15);
identityCache.CacheSystemIdentity(user, systemIdentity!, identExpiry);
await identityCache.CacheSystemIdentity(user, systemIdentity!, identExpiry);
}
Logger.LogDebug("Successfully logged in user {userId}!", user.Id);
@@ -1,4 +1,5 @@
using System;
using System.Threading.Tasks;
using Tgstation.Server.Host.Models;
@@ -15,7 +16,8 @@ namespace Tgstation.Server.Host.Security
/// <param name="user">The <see cref="User"/> the <paramref name="systemIdentity"/> belongs to.</param>
/// <param name="systemIdentity">The <see cref="ISystemIdentity"/> to cache.</param>
/// <param name="expiry">When the <paramref name="systemIdentity"/> should expire.</param>
void CacheSystemIdentity(User user, ISystemIdentity systemIdentity, DateTimeOffset expiry);
/// <returns>A <see cref="ValueTask"/> representing the running operation.</returns>
ValueTask CacheSystemIdentity(User user, ISystemIdentity systemIdentity, DateTimeOffset expiry);
/// <summary>
/// Attempt to load a cached <see cref="ISystemIdentity"/>.
@@ -1,16 +1,18 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
using Tgstation.Server.Common.Extensions;
using Tgstation.Server.Host.Models;
using Tgstation.Server.Host.Utils;
namespace Tgstation.Server.Host.Security
{
/// <inheritdoc cref="IIdentityCache" />
sealed class IdentityCache : IIdentityCache, IDisposable
sealed class IdentityCache : IIdentityCache, IAsyncDisposable
{
/// <summary>
/// The <see cref="IAsyncDelayer"/> for the <see cref="IdentityCache"/>.
@@ -41,15 +43,14 @@ namespace Tgstation.Server.Host.Security
}
/// <inheritdoc />
public void Dispose()
public ValueTask DisposeAsync()
{
logger.LogTrace("Disposing...");
foreach (var cachedIdentity in cachedIdentities.Select(x => x.Value).ToList())
cachedIdentity.Dispose();
return ValueTaskExtensions.WhenAll(cachedIdentities.Select(x => x.Value.DisposeAsync()));
}
/// <inheritdoc />
public void CacheSystemIdentity(User user, ISystemIdentity systemIdentity, DateTimeOffset expiry)
public async ValueTask CacheSystemIdentity(User user, ISystemIdentity systemIdentity, DateTimeOffset expiry)
{
ArgumentNullException.ThrowIfNull(user);
ArgumentNullException.ThrowIfNull(systemIdentity);
@@ -57,27 +58,35 @@ namespace Tgstation.Server.Host.Security
var uid = user.Require(x => x.Id);
var sysId = systemIdentity.Uid;
lock (cachedIdentities)
ValueTask oldIdentityDisposal = ValueTask.CompletedTask;
try
{
logger.LogDebug("Caching system identity {sysId} of user {uid}", sysId, uid);
if (cachedIdentities.TryGetValue(uid, out var identCache))
lock (cachedIdentities)
{
logger.LogTrace("Expiring previously cached identity...");
identCache.Dispose(); // also clears it out
}
logger.LogDebug("Caching system identity {sysId} of user {uid}", sysId, uid);
identCache = new IdentityCacheObject(
systemIdentity.Clone(),
asyncDelayer,
() =>
if (cachedIdentities.TryGetValue(uid, out var identCache))
{
logger.LogDebug("Expiring system identity cache for user {uid}", uid);
lock (cachedIdentities)
cachedIdentities.Remove(uid);
},
expiry);
cachedIdentities.Add(uid, identCache);
logger.LogTrace("Expiring previously cached identity...");
oldIdentityDisposal = identCache.DisposeAsync(); // also clears it out
}
identCache = new IdentityCacheObject(
systemIdentity.Clone(),
asyncDelayer,
() =>
{
logger.LogDebug("Expiring system identity cache for user {uid}", uid);
lock (cachedIdentities)
cachedIdentities.Remove(uid);
},
expiry);
cachedIdentities.Add(uid, identCache);
}
}
finally
{
await oldIdentityDisposal;
}
}
@@ -9,7 +9,7 @@ namespace Tgstation.Server.Host.Security
/// <summary>
/// For keeping a specific <see cref="ISystemIdentity"/> alive for a period of time.
/// </summary>
sealed class IdentityCacheObject : IDisposable
sealed class IdentityCacheObject : IAsyncDisposable
{
/// <summary>
/// The <see cref="ISystemIdentity"/> the <see cref="IdentityCache"/> manages.
@@ -53,6 +53,9 @@ namespace Tgstation.Server.Host.Security
{
await asyncDelayer.Delay(expiry - now, cancellationToken);
}
catch (OperationCanceledException)
{
}
finally
{
onExpiry();
@@ -63,18 +66,11 @@ namespace Tgstation.Server.Host.Security
}
/// <inheritdoc />
public void Dispose()
public async ValueTask DisposeAsync()
{
cancellationTokenSource.Cancel();
try
{
task.GetAwaiter().GetResult();
}
catch (OperationCanceledException)
{
}
cancellationTokenSource.Dispose();
await task;
}
}
}