refactor: Refactoring of text creation
This commit is contained in:
@@ -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">
|
<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>
|
<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>
|
||||||
@@ -12,6 +12,7 @@
|
|||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly" Version="9.0.0" />
|
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly" Version="9.0.0" />
|
||||||
|
<PackageReference Include="UnitsNet" Version="5.60.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
|||||||
@@ -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]
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -27,7 +27,7 @@
|
|||||||
@{
|
@{
|
||||||
string key = CreatedItems.GetPrimaryKeyString();
|
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>
|
||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
@@ -38,19 +38,21 @@
|
|||||||
|
|
||||||
[Inject] public ILogger<Home> Logger { get; set; } = null!;
|
[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;
|
public ITextItem? CreatedItems;
|
||||||
|
|
||||||
private async Task SubmitInput()
|
private async Task SubmitInput()
|
||||||
{
|
{
|
||||||
ITextItem item = await ItemGenerator.GenerateTextShare(Form.InputText);
|
LinkResult result = await ItemGenerator.GenerateTextShare(Form.InputText);
|
||||||
|
|
||||||
CreatedItems = item;
|
|
||||||
|
|
||||||
|
if (result.Item is not null)
|
||||||
|
{
|
||||||
|
CreatedItems = result.Item;
|
||||||
Form = new UploadForm();
|
Form = new UploadForm();
|
||||||
|
}
|
||||||
Logger.LogInformation("A new item was created!");
|
Logger.LogInformation("A new item was created!");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
49
Pushy/Pushy/Grains/LinkGenerator.cs
Normal file
49
Pushy/Pushy/Grains/LinkGenerator.cs
Normal 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -2,6 +2,13 @@ using Orleans.Concurrency;
|
|||||||
|
|
||||||
namespace Pushy.Grains;
|
namespace Pushy.Grains;
|
||||||
|
|
||||||
|
[GenerateSerializer]
|
||||||
|
public enum TextSetResult
|
||||||
|
{
|
||||||
|
Failure,
|
||||||
|
Success
|
||||||
|
}
|
||||||
|
|
||||||
public sealed class TextItem
|
public sealed class TextItem
|
||||||
{
|
{
|
||||||
public string? Text { get; set; }
|
public string? Text { get; set; }
|
||||||
@@ -9,11 +16,8 @@ public sealed class TextItem
|
|||||||
|
|
||||||
public interface ITextItem : IGrainWithStringKey
|
public interface ITextItem : IGrainWithStringKey
|
||||||
{
|
{
|
||||||
[Alias("IsAvailable")]
|
|
||||||
public ValueTask<bool> IsAvailable();
|
|
||||||
|
|
||||||
[Alias("SetText")]
|
[Alias("SetText")]
|
||||||
public ValueTask SetText(string text);
|
public ValueTask<TextSetResult> SetText(string text);
|
||||||
|
|
||||||
[ReadOnly]
|
[ReadOnly]
|
||||||
[return: Immutable]
|
[return: Immutable]
|
||||||
@@ -21,44 +25,51 @@ public interface ITextItem : IGrainWithStringKey
|
|||||||
ValueTask<string> GetText();
|
ValueTask<string> GetText();
|
||||||
}
|
}
|
||||||
|
|
||||||
public sealed class TextItemGrain : Grain, ITextItem, IRemindable
|
public sealed class TextItemGrain : IGrainBase, ITextItem, IRemindable
|
||||||
{
|
{
|
||||||
private readonly IPersistentState<TextItem> _state;
|
private readonly IPersistentState<TextItem> _state;
|
||||||
|
|
||||||
private IGrainReminder? _reminder;
|
private IGrainReminder? _reminder;
|
||||||
|
|
||||||
public TextItemGrain(
|
public TextItemGrain(
|
||||||
|
IGrainContext grainContext,
|
||||||
[PersistentState("text")] IPersistentState<TextItem> state)
|
[PersistentState("text")] IPersistentState<TextItem> state)
|
||||||
{
|
{
|
||||||
_state = state;
|
_state = state;
|
||||||
|
GrainContext = grainContext;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public IGrainContext GrainContext { get; }
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <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));
|
_reminder = await this.RegisterOrUpdateReminder("clear", TimeSpan.FromDays(10), TimeSpan.FromDays(10));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public ValueTask<bool> IsAvailable()
|
public async ValueTask<TextSetResult> SetText(string text)
|
||||||
{
|
{
|
||||||
return ValueTask.FromResult(_state.State.Text is null);
|
try
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
public async ValueTask SetText(string text)
|
|
||||||
{
|
{
|
||||||
if(_state.State.Text is not null)
|
if (_state.State.Text is not null)
|
||||||
throw new InvalidOperationException("Text is already set");
|
return TextSetResult.Failure;
|
||||||
|
|
||||||
_state.State.Text = text;
|
_state.State.Text = text;
|
||||||
await _state.WriteStateAsync();
|
await _state.WriteStateAsync();
|
||||||
|
|
||||||
|
return TextSetResult.Success;
|
||||||
|
}
|
||||||
|
catch (Exception)
|
||||||
|
{
|
||||||
|
return TextSetResult.Failure;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public ValueTask<string> GetText()
|
public ValueTask<string> GetText()
|
||||||
{
|
{
|
||||||
return ValueTask.FromResult(_state.State.Text!);
|
return ValueTask.FromResult(_state.State.Text ?? throw new InvalidOperationException("No text was available"));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
@@ -68,6 +79,7 @@ public sealed class TextItemGrain : Grain, ITextItem, IRemindable
|
|||||||
{
|
{
|
||||||
_state.State.Text = null;
|
_state.State.Text = null;
|
||||||
await _state.WriteStateAsync();
|
await _state.WriteStateAsync();
|
||||||
|
this.DeactivateOnIdle();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -3,8 +3,8 @@ using Elastic.Extensions.Logging.Options;
|
|||||||
using Elastic.Transport;
|
using Elastic.Transport;
|
||||||
using Microsoft.AspNetCore.DataProtection;
|
using Microsoft.AspNetCore.DataProtection;
|
||||||
using Pushy.Components;
|
using Pushy.Components;
|
||||||
|
using Pushy.Grains;
|
||||||
using StackExchange.Redis;
|
using StackExchange.Redis;
|
||||||
using LinkGenerator = Pushy.LinkGenerator;
|
|
||||||
|
|
||||||
var builder = WebApplication.CreateBuilder(args);
|
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.AddAllElasticApm();
|
||||||
|
|
||||||
builder.Services.AddHealthChecks();
|
builder.Services.AddHealthChecks();
|
||||||
|
|||||||
@@ -9,6 +9,11 @@
|
|||||||
<UserSecretsId>d8fe2296-80f7-4812-b26a-ccaa6167a6e1</UserSecretsId>
|
<UserSecretsId>d8fe2296-80f7-4812-b26a-ccaa6167a6e1</UserSecretsId>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<ServerGarbageCollection>true</ServerGarbageCollection>
|
||||||
|
<ConcurrentGarbageCollection>true</ConcurrentGarbageCollection>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Elastic.Apm.NetCoreAll" Version="1.30.0" />
|
<PackageReference Include="Elastic.Apm.NetCoreAll" Version="1.30.0" />
|
||||||
<PackageReference Include="Elastic.Extensions.Logging" Version="8.12.2" />
|
<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.Sdk" Version="8.2.0" />
|
||||||
<PackageReference Include="Microsoft.Orleans.Server" Version="8.2.0" />
|
<PackageReference Include="Microsoft.Orleans.Server" Version="8.2.0" />
|
||||||
<PackageReference Include="System.Text.Json" Version="9.0.0" />
|
<PackageReference Include="System.Text.Json" Version="9.0.0" />
|
||||||
|
<PackageReference Include="UnitsNet" Version="5.60.0" />
|
||||||
<ProjectReference Include="..\Pushy.Client\Pushy.Client.csproj"/>
|
<ProjectReference Include="..\Pushy.Client\Pushy.Client.csproj"/>
|
||||||
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.Server" Version="9.0.0" />
|
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.Server" Version="9.0.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|||||||
Reference in New Issue
Block a user