1
0
mirror of https://github.com/chylex/Minecraft-Phantom-Panel.git synced 2025-04-28 19:15:45 +02:00

Make Result type serializable

This commit is contained in:
chylex 2024-03-31 18:24:22 +02:00
parent c99f5bc6bf
commit d03f532996
Signed by: chylex
GPG Key ID: 4DE42C8F19A80548
8 changed files with 106 additions and 85 deletions
Agent/Phantom.Agent.Services/Instances
Common/Phantom.Common.Data
Controller
Phantom.Controller.Database/Repositories
Phantom.Controller.Services/Users
Utils/Phantom.Utils/Tasks
Web/Phantom.Web/Pages

View File

@ -12,7 +12,6 @@ using Phantom.Common.Data.Replies;
using Phantom.Utils.Actor;
using Phantom.Utils.IO;
using Phantom.Utils.Logging;
using Phantom.Utils.Tasks;
using Serilog;
namespace Phantom.Agent.Services.Instances;
@ -140,8 +139,8 @@ sealed class InstanceManagerActor : ReceiveActor<InstanceManagerActor.ICommand>
}
var ticket = instanceTicketManager.Reserve(instanceInfo.Configuration);
if (ticket is Result<InstanceTicketManager.Ticket, LaunchInstanceResult>.Fail fail) {
return InstanceActionResult.Concrete(fail.Error);
if (!ticket) {
return InstanceActionResult.Concrete(ticket.Error);
}
if (agentState.InstancesByGuid.TryGetValue(instanceGuid, out var instance)) {

View File

@ -1,8 +1,8 @@
using Phantom.Agent.Minecraft.Instance;
using Phantom.Agent.Minecraft.Launcher;
using Phantom.Agent.Minecraft.Server;
using Phantom.Common.Data;
using Phantom.Common.Data.Instance;
using Phantom.Utils.Tasks;
namespace Phantom.Agent.Services.Instances.State;

View File

@ -0,0 +1,91 @@
using System.Diagnostics.CodeAnalysis;
using MemoryPack;
namespace Phantom.Common.Data;
[MemoryPackable(GenerateType.VersionTolerant)]
public sealed partial class Result<TValue, TError> {
[MemoryPackOrder(0)]
[MemoryPackInclude]
private readonly bool hasValue;
[MemoryPackOrder(1)]
[MemoryPackInclude]
private readonly TValue? value;
[MemoryPackOrder(2)]
[MemoryPackInclude]
private readonly TError? error;
[MemoryPackIgnore]
public TValue Value => hasValue ? value! : throw new InvalidOperationException("Attempted to get value from an error result.");
[MemoryPackIgnore]
public TError Error => !hasValue ? error! : throw new InvalidOperationException("Attempted to get error from a success result.");
private Result(bool hasValue, TValue? value, TError? error) {
this.hasValue = hasValue;
this.value = value;
this.error = error;
}
public static implicit operator Result<TValue, TError>(TValue value) {
return new Result<TValue, TError>(hasValue: true, value, default);
}
public static implicit operator Result<TValue, TError>(TError error) {
return new Result<TValue, TError>(hasValue: false, default, error);
}
public static implicit operator bool(Result<TValue, TError> result) {
return result.hasValue;
}
}
[MemoryPackable(GenerateType.VersionTolerant)]
public sealed partial class Result<TError> {
[MemoryPackOrder(0)]
[MemoryPackInclude]
private readonly bool hasValue;
[MemoryPackOrder(1)]
[MemoryPackInclude]
private readonly TError? error;
[MemoryPackIgnore]
public TError Error => !hasValue ? error! : throw new InvalidOperationException("Attempted to get error from a success result.");
private Result(bool hasValue, TError? error) {
this.hasValue = hasValue;
this.error = error;
}
public bool TryGetError([MaybeNullWhen(false)] out TError error) {
if (hasValue) {
error = default;
return false;
}
else {
error = this.error!;
return true;
}
}
public static implicit operator Result<TError>([SuppressMessage("ReSharper", "UnusedParameter.Global")] Result.OkType _) {
return new Result<TError>(hasValue: true, default);
}
public static implicit operator Result<TError>(TError error) {
return new Result<TError>(hasValue: false, error);
}
public static implicit operator bool(Result<TError> result) {
return result.hasValue;
}
}
public static class Result {
public static OkType Ok { get; } = new ();
public readonly record struct OkType;
}

View File

@ -1,9 +1,9 @@
using System.Collections.Immutable;
using Microsoft.EntityFrameworkCore;
using Phantom.Common.Data;
using Phantom.Common.Data.Web.Users;
using Phantom.Controller.Database.Entities;
using Phantom.Utils.Collections;
using Phantom.Utils.Tasks;
namespace Phantom.Controller.Database.Repositories;

View File

@ -1,12 +1,12 @@
using System.Collections.Immutable;
using Microsoft.EntityFrameworkCore;
using Phantom.Common.Data;
using Phantom.Common.Data.Web.Users;
using Phantom.Common.Data.Web.Users.AddUserErrors;
using Phantom.Common.Data.Web.Users.PasswordRequirementViolations;
using Phantom.Common.Data.Web.Users.UsernameRequirementViolations;
using Phantom.Controller.Database.Entities;
using Phantom.Utils.Collections;
using Phantom.Utils.Tasks;
namespace Phantom.Controller.Database.Repositories;

View File

@ -54,9 +54,8 @@ sealed class UserManager {
}
}
else {
var result = userRepository.SetUserPassword(user, password);
if (!result) {
return new Common.Data.Web.Users.CreateOrUpdateAdministratorUserResults.UpdatingFailed(result.Error);
if (userRepository.SetUserPassword(user, password).TryGetError(out var error)) {
return new Common.Data.Web.Users.CreateOrUpdateAdministratorUserResults.UpdatingFailed(error);
}
auditLogWriter.AdministratorUserModified(user);

View File

@ -1,69 +0,0 @@
using System.Diagnostics.CodeAnalysis;
namespace Phantom.Utils.Tasks;
public abstract record Result<TValue, TError> {
private Result() {}
public abstract TValue Value { get; init; }
public abstract TError Error { get; init; }
public static implicit operator Result<TValue, TError>(TValue value) {
return new Ok(value);
}
public static implicit operator Result<TValue, TError>(TError error) {
return new Fail(error);
}
public static implicit operator bool(Result<TValue, TError> result) {
return result is Ok;
}
public sealed record Ok(TValue Value) : Result<TValue, TError> {
public override TError Error {
get => throw new InvalidOperationException("Attempted to get error from Ok result.");
init {}
}
}
public sealed record Fail(TError Error) : Result<TValue, TError> {
public override TValue Value {
get => throw new InvalidOperationException("Attempted to get value from Fail result.");
init {}
}
}
}
public abstract record Result<TError> {
private Result() {}
public abstract TError Error { get; init; }
public static implicit operator Result<TError>(TError error) {
return new Fail(error);
}
public static implicit operator Result<TError>([SuppressMessage("ReSharper", "UnusedParameter.Global")] Result.OkType _) {
return new Ok();
}
public static implicit operator bool(Result<TError> result) {
return result is Ok;
}
public sealed record Ok : Result<TError> {
public override TError Error {
get => throw new InvalidOperationException("Attempted to get error from Ok result.");
init {}
}
}
public sealed record Fail(TError Error) : Result<TError>;
}
public static class Result {
public static OkType Ok { get; } = new ();
public readonly record struct OkType;
}

View File

@ -1,14 +1,14 @@
@page "/setup"
@using Phantom.Utils.Tasks
@using Phantom.Common.Data
@using Phantom.Common.Data.Web.Users
@using Phantom.Common.Data.Web.Users.CreateOrUpdateAdministratorUserResults
@using Phantom.Common.Messages.Web.ToController
@using Phantom.Utils.Cryptography
@using Phantom.Web.Services
@using Phantom.Web.Services.Authentication
@using Phantom.Web.Services.Rpc
@using System.ComponentModel.DataAnnotations
@using Phantom.Utils.Cryptography
@using System.Security.Cryptography
@using Phantom.Common.Messages.Web.ToController
@using Phantom.Common.Data.Web.Users
@using Phantom.Common.Data.Web.Users.CreateOrUpdateAdministratorUserResults
@attribute [AllowAnonymous]
@inject ApplicationProperties ApplicationProperties
@inject UserLoginManager LoginManager
@ -65,8 +65,9 @@
return;
}
if (await CreateOrUpdateAdministrator() is Result<string>.Fail fail) {
form.SubmitModel.StopSubmitting(fail.Error);
var createOrUpdateAdministratorResult = await CreateOrUpdateAdministrator();
if (createOrUpdateAdministratorResult.TryGetError(out var error)) {
form.SubmitModel.StopSubmitting(error);
return;
}