refactor: Refactoring of text creation

This commit is contained in:
henrik
2024-12-10 21:42:22 +01:00
parent 41a174e1cb
commit b4b96b3f4e
9 changed files with 101 additions and 138 deletions

View File

@@ -1,2 +1,3 @@
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AIGrainBase_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002Econfig_003FJetBrains_003FRider2024_002E3_003Fresharper_002Dhost_003FSourcesCache_003F7b522cc30a53bd25a33ab94497f733ec9a145f18911e0c8716e1c70af232e26_003FIGrainBase_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AIRemindable_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002Econfig_003FJetBrains_003FRider2024_002E3_003Fresharper_002Dhost_003FSourcesCache_003Fade617b5b5cd50987d2ed8207d608c80393a95d88b90c3a2e0e9335bc19c4b0_003FIRemindable_002Ecs/@EntryIndexedValue">ForceIncluded</s:String></wpf:ResourceDictionary>

View File

@@ -12,6 +12,7 @@
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly" Version="9.0.0" />
<PackageReference Include="UnitsNet" Version="5.60.0" />
</ItemGroup>
</Project>

View File

@@ -1,77 +0,0 @@
@page "/test"
@rendermode InteractiveWebAssembly
@inject PersistentComponentState ApplicationState
@inject ILogger<TestClientForm> Logger
<p>@Data - @RendererInfo.Name</p>
<EditForm Enhance FormName="TestForm" OnSubmit="Callback" Model="Item">
<InputText @bind-Value="@Item.Text"/>
<button class="btn " type="submit" disabled="@(doingStuff || !RendererInfo.IsInteractive)">
@if (doingStuff || !RendererInfo.IsInteractive)
{
<span class="loading loading-spinner"></span>
<a>Loading...</a>
}
else
{
<a>Test</a>
}
</button>
</EditForm>
@code {
private bool doingStuff = false;
private PersistingComponentStateSubscription persistingSubscription;
public sealed class FormInput
{
public required string Text { get; set; }
public required string[] Existing { get; set; }
}
[SupplyParameterFromForm] public FormInput Item { get; set; } = new()
{
Text = string.Empty,
Existing = []
};
public Guid Data = Guid.NewGuid();
protected override Task OnInitializedAsync()
{
persistingSubscription =
ApplicationState.RegisterOnPersisting(PersistData);
if (!ApplicationState.TryTakeFromJson<Guid>("TOKEN", out Data))
{
Data = Guid.NewGuid();
Logger.LogInformation("Data needs to be persisted! {Data}", Data);
}
else
{
Logger.LogInformation("Using persisted DATA");
}
return Task.CompletedTask;
}
private Task PersistData()
{
Logger.LogInformation("Persisting! {Data}", Data);
ApplicationState.PersistAsJson("TOKEN", Data);
return Task.CompletedTask;
}
private async Task Callback()
{
Item = new FormInput
{
Text = string.Empty,
Existing = [..Item.Existing, Item.Text, RendererInfo.Name]
};
}
}

View File

@@ -27,7 +27,7 @@
@{
string key = CreatedItems.GetPrimaryKeyString();
}
<a href="@Nav.ToAbsoluteUri($"/t/{key}")">@Nav.ToAbsoluteUri($"/t/{key}")</a>
<a class="link" href="@Nav.ToAbsoluteUri($"/t/{key}")">@Nav.ToAbsoluteUri($"/t/{key}")</a>
</div>
}
</div>
@@ -38,19 +38,21 @@
[Inject] public ILogger<Home> Logger { get; set; } = null!;
[Inject] public LinkGenerator ItemGenerator { get; set; } = null!;
[Inject] public ILinkGenerator ItemGenerator { get; set; } = null!;
[Inject] public IClusterClient ClusterClient { get; set; } = null!;
[Inject] public IGrainFactory ClusterClient { get; set; } = null!;
public ITextItem? CreatedItems;
private async Task SubmitInput()
{
ITextItem item = await ItemGenerator.GenerateTextShare(Form.InputText);
CreatedItems = item;
LinkResult result = await ItemGenerator.GenerateTextShare(Form.InputText);
if (result.Item is not null)
{
CreatedItems = result.Item;
Form = new UploadForm();
}
Logger.LogInformation("A new item was created!");
}

View File

@@ -0,0 +1,49 @@
using System.Diagnostics.CodeAnalysis;
namespace Pushy.Grains;
[Immutable]
[GenerateSerializer]
[Alias("Pushy.Grains.LinkResult")]
public record LinkResult(ITextItem? Item);
public interface ILinkGenerator : IGrainWithGuidKey
{
[Alias("GenerateLink")]
public ValueTask<LinkResult> GenerateTextShare([Immutable] string text);
}
public sealed class LinkGenerator : IGrainBase, ILinkGenerator
{
private readonly ILogger<LinkGenerator> _logger;
private readonly IClusterClient _clusterClient;
public IGrainContext GrainContext { get; }
public LinkGenerator(
IGrainContext grainContext,
IClusterClient clusterClient,
ILogger<LinkGenerator> logger)
{
_clusterClient = clusterClient;
_logger = logger;
GrainContext = grainContext;
}
public async ValueTask<LinkResult> GenerateTextShare(string text)
{
string item = $"{Guid.CreateVersion7():N}"[9..];
var textGrain = _clusterClient.GetGrain<ITextItem>(item);
try
{
await textGrain.SetText(text);
return new LinkResult(textGrain);
}
catch (Exception)
{
//TODO: Write log message of why it fails?
//Swallow small change of error
return await GenerateTextShare(text);
}
}
}

View File

@@ -2,6 +2,13 @@ using Orleans.Concurrency;
namespace Pushy.Grains;
[GenerateSerializer]
public enum TextSetResult
{
Failure,
Success
}
public sealed class TextItem
{
public string? Text { get; set; }
@@ -9,11 +16,8 @@ public sealed class TextItem
public interface ITextItem : IGrainWithStringKey
{
[Alias("IsAvailable")]
public ValueTask<bool> IsAvailable();
[Alias("SetText")]
public ValueTask SetText(string text);
public ValueTask<TextSetResult> SetText(string text);
[ReadOnly]
[return: Immutable]
@@ -21,44 +25,51 @@ public interface ITextItem : IGrainWithStringKey
ValueTask<string> GetText();
}
public sealed class TextItemGrain : Grain, ITextItem, IRemindable
public sealed class TextItemGrain : IGrainBase, ITextItem, IRemindable
{
private readonly IPersistentState<TextItem> _state;
private IGrainReminder? _reminder;
public TextItemGrain(
IGrainContext grainContext,
[PersistentState("text")] IPersistentState<TextItem> state)
{
_state = state;
GrainContext = grainContext;
}
public IGrainContext GrainContext { get; }
/// <inheritdoc />
public override async Task OnActivateAsync(CancellationToken cancellationToken)
public async Task OnActivateAsync(CancellationToken cancellationToken)
{
_reminder = await this.RegisterOrUpdateReminder("clear", TimeSpan.FromDays(10), TimeSpan.FromDays(10));
}
/// <inheritdoc />
public ValueTask<bool> IsAvailable()
public async ValueTask<TextSetResult> SetText(string text)
{
return ValueTask.FromResult(_state.State.Text is null);
}
/// <inheritdoc />
public async ValueTask SetText(string text)
try
{
if(_state.State.Text is not null)
throw new InvalidOperationException("Text is already set");
if (_state.State.Text is not null)
return TextSetResult.Failure;
_state.State.Text = text;
await _state.WriteStateAsync();
return TextSetResult.Success;
}
catch (Exception)
{
return TextSetResult.Failure;
}
}
/// <inheritdoc />
public ValueTask<string> GetText()
{
return ValueTask.FromResult(_state.State.Text!);
return ValueTask.FromResult(_state.State.Text ?? throw new InvalidOperationException("No text was available"));
}
/// <inheritdoc />
@@ -68,6 +79,7 @@ public sealed class TextItemGrain : Grain, ITextItem, IRemindable
{
_state.State.Text = null;
await _state.WriteStateAsync();
this.DeactivateOnIdle();
}
}
}

View File

@@ -1,32 +0,0 @@
using System.Security.Cryptography;
using System.Text;
using Pushy.Grains;
namespace Pushy;
public sealed class LinkGenerator
{
private readonly ILogger<LinkGenerator> _logger;
private readonly IClusterClient _clusterClient;
public LinkGenerator(
IClusterClient clusterClient,
ILogger<LinkGenerator> logger)
{
_clusterClient = clusterClient;
_logger = logger;
}
public async Task<ITextItem> GenerateTextShare(string text)
{
string item = $"{Guid.CreateVersion7():N}"[6..];
var sharedGrain = _clusterClient.GetGrain<ITextItem>(item);
if (await sharedGrain.IsAvailable())
{
await sharedGrain.SetText(text);
return sharedGrain;
}
return await GenerateTextShare(text);
}
}

View File

@@ -3,8 +3,8 @@ using Elastic.Extensions.Logging.Options;
using Elastic.Transport;
using Microsoft.AspNetCore.DataProtection;
using Pushy.Components;
using Pushy.Grains;
using StackExchange.Redis;
using LinkGenerator = Pushy.LinkGenerator;
var builder = WebApplication.CreateBuilder(args);
@@ -51,7 +51,8 @@ if (builder.Environment.IsProduction())
});
}
builder.Services.AddScoped<LinkGenerator>();
builder.Services.AddScoped(service =>
service.GetRequiredService<IGrainFactory>().GetGrain<ILinkGenerator>(Guid.Empty));
builder.Services.AddAllElasticApm();
builder.Services.AddHealthChecks();

View File

@@ -9,6 +9,11 @@
<UserSecretsId>d8fe2296-80f7-4812-b26a-ccaa6167a6e1</UserSecretsId>
</PropertyGroup>
<PropertyGroup>
<ServerGarbageCollection>true</ServerGarbageCollection>
<ConcurrentGarbageCollection>true</ConcurrentGarbageCollection>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Elastic.Apm.NetCoreAll" Version="1.30.0" />
<PackageReference Include="Elastic.Extensions.Logging" Version="8.12.2" />
@@ -23,6 +28,7 @@
<PackageReference Include="Microsoft.Orleans.Sdk" Version="8.2.0" />
<PackageReference Include="Microsoft.Orleans.Server" Version="8.2.0" />
<PackageReference Include="System.Text.Json" Version="9.0.0" />
<PackageReference Include="UnitsNet" Version="5.60.0" />
<ProjectReference Include="..\Pushy.Client\Pushy.Client.csproj"/>
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.Server" Version="9.0.0" />
</ItemGroup>