Nullify ComponentInterfacingController

This commit is contained in:
Jordan Dominion
2023-11-25 16:46:06 -05:00
parent 6a8b48ad68
commit f4ff59ce1f
2 changed files with 20 additions and 11 deletions
@@ -141,7 +141,7 @@ namespace Tgstation.Server.Host.Controllers
DatabaseContext.ChatBots.Add(dbModel);
await DatabaseContext.Save(cancellationToken);
return await WithComponentInstance(
return await WithComponentInstanceNullable(
async instance =>
{
try
@@ -180,7 +180,7 @@ namespace Tgstation.Server.Host.Controllers
[TgsAuthorize(ChatBotRights.Delete)]
[ProducesResponseType(204)]
public async ValueTask<IActionResult> Delete(long id, CancellationToken cancellationToken)
=> await WithComponentInstance(
=> await WithComponentInstanceNullable(
async instance =>
{
await Task.WhenAll(
@@ -352,7 +352,7 @@ namespace Tgstation.Server.Host.Controllers
await DatabaseContext.Save(cancellationToken);
earlyOut = await WithComponentInstance(
earlyOut = await WithComponentInstanceNullable(
async instance =>
{
var chat = instance.Chat;
@@ -10,11 +10,10 @@ using Tgstation.Server.Api.Models;
using Tgstation.Server.Api.Models.Response;
using Tgstation.Server.Host.Components;
using Tgstation.Server.Host.Database;
using Tgstation.Server.Host.Models;
using Tgstation.Server.Host.Security;
using Tgstation.Server.Host.Utils;
#nullable disable
namespace Tgstation.Server.Host.Controllers
{
/// <summary>
@@ -65,18 +64,18 @@ namespace Tgstation.Server.Host.Controllers
}
/// <inheritdoc />
protected override async ValueTask<IActionResult> ValidateRequest(CancellationToken cancellationToken)
protected override async ValueTask<IActionResult?> ValidateRequest(CancellationToken cancellationToken)
{
if (!useInstanceRequestHeader)
return null;
if (!ApiHeaders.InstanceId.HasValue)
if (!ApiHeaders!.InstanceId.HasValue)
return BadRequest(new ErrorMessageResponse(ErrorCode.InstanceHeaderRequired));
if (AuthenticationContext.InstancePermissionSet == null)
return Forbid();
if (ValidateInstanceOnlineStatus(Instance))
if (ValidateInstanceOnlineStatus(Instance!))
await DatabaseContext.Save(cancellationToken);
using var instanceReferenceCheck = instanceManager.GetInstanceReference(Instance);
@@ -99,7 +98,7 @@ namespace Tgstation.Server.Host.Controllers
using (var instanceReferenceCheck = instanceManager.GetInstanceReference(metadata))
online = instanceReferenceCheck != null;
if (metadata.Online.Value == online)
if (metadata.Require(x => x.Online) == online)
return false;
const string OfflineWord = "offline";
@@ -122,11 +121,11 @@ namespace Tgstation.Server.Host.Controllers
/// <param name="instance">The <see cref="Models.Instance"/> to grab. If <see langword="null"/>, <see cref="ApiController.Instance"/> will be used.</param>
/// <returns>A <see cref="ValueTask{TResult}"/> resulting in the <see cref="IActionResult"/> that should be returned.</returns>
/// <remarks>The context of <paramref name="action"/> should be as small as possible so as to avoid race conditions. This function can return a <see cref="ConflictResult"/> if the requested instance was offline.</remarks>
protected async ValueTask<IActionResult> WithComponentInstance(Func<IInstanceCore, ValueTask<IActionResult>> action, Models.Instance instance = null)
protected async ValueTask<IActionResult?> WithComponentInstanceNullable(Func<IInstanceCore, ValueTask<IActionResult?>> action, Models.Instance? instance = null)
{
ArgumentNullException.ThrowIfNull(action);
instance ??= Instance;
instance ??= Instance ?? throw new InvalidOperationException("ComponentInterfacingController has no Instance!");
using var instanceReference = instanceManager.GetInstanceReference(instance);
using (LogContext.PushProperty(SerilogContextHelper.InstanceReferenceContextProperty, instanceReference.Uid))
@@ -136,5 +135,15 @@ namespace Tgstation.Server.Host.Controllers
return await action(instanceReference);
}
}
/// <summary>
/// Run a given <paramref name="action"/> with the relevant <see cref="IInstance"/>.
/// </summary>
/// <param name="action">A <see cref="Func{T, TResult}"/> accepting the <see cref="IInstance"/> and returning a <see cref="ValueTask{TResult}"/> with the <see cref="IActionResult"/>.</param>
/// <param name="instance">The <see cref="Models.Instance"/> to grab. If <see langword="null"/>, <see cref="ApiController.Instance"/> will be used.</param>
/// <returns>A <see cref="ValueTask{TResult}"/> resulting in the <see cref="IActionResult"/> that should be returned.</returns>
/// <remarks>The context of <paramref name="action"/> should be as small as possible so as to avoid race conditions. This function can return a <see cref="ConflictResult"/> if the requested instance was offline.</remarks>
protected async ValueTask<IActionResult> WithComponentInstance(Func<IInstanceCore, ValueTask<IActionResult>> action, Models.Instance? instance = null)
=> (await WithComponentInstanceNullable(async core => await action(core), instance))!;
}
}