From aaa2574d5723e3673ac72a376fc4834e1db20bc0 Mon Sep 17 00:00:00 2001 From: Ayymoss Date: Sat, 27 Jul 2024 23:56:31 +0100 Subject: [PATCH 1/2] Refactor PromptClientInput to accept string array for prompt Updated the `PromptClientInput` method to accept a string array instead of a single string. This change ensures that multiple prompts can be handled, improving input flexibility and client communication. Additionally, modified related method calls to maintain consistency with the new input type. --- SharedLibraryCore/Utilities.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/SharedLibraryCore/Utilities.cs b/SharedLibraryCore/Utilities.cs index 34843cab..4ac41ac8 100644 --- a/SharedLibraryCore/Utilities.cs +++ b/SharedLibraryCore/Utilities.cs @@ -1375,7 +1375,7 @@ public static void ExecuteAfterDelay(int delayMs, Func public static void ExecuteAfterDelay(this Func action, int delayMs, CancellationToken token = default) => ExecuteAfterDelay(delayMs, action, token); - public static async Task PromptClientInput(this EFClient client, string prompt, Func> validator, + public static async Task PromptClientInput(this EFClient client, string[] prompt, Func> validator, CancellationToken token = default) { var clientResponse = new ManualResetEventSlim(false); @@ -1384,7 +1384,7 @@ public static async Task PromptClientInput(this EFClient client, string try { IGameEventSubscriptions.ClientMessaged += OnResponse; - await client.TellAsync([prompt], token); + await client.TellAsync(prompt, token); using var tokenSource = new CancellationTokenSource(DefaultCommandTimeout); using var linkedTokenSource = CancellationTokenSource.CreateLinkedTokenSource(tokenSource.Token, token); @@ -1419,7 +1419,7 @@ async Task OnResponse(ClientMessageEvent messageEvent, CancellationToken cancell } else { - await client.TellAsync([prompt], cancellationToken); + await client.TellAsync(prompt, cancellationToken); } } } From 58ac495dd31af12839b326420462d81c7237249e Mon Sep 17 00:00:00 2001 From: Ayymoss Date: Sun, 4 Aug 2024 18:08:23 +0100 Subject: [PATCH 2/2] Refactor PromptClientInput to support parsed result and errors Updated PromptClientInput to handle parsed input results and return error messages instead of raw strings. Introduced ParsedInputResult class to encapsulate parsing results and errors, enhancing client validation and feedback mechanism. --- .../Helpers/ParsedInputResult.cs | 16 ++++++++++ SharedLibraryCore/Utilities.cs | 29 +++++++++++-------- 2 files changed, 33 insertions(+), 12 deletions(-) create mode 100644 SharedLibraryCore/Helpers/ParsedInputResult.cs diff --git a/SharedLibraryCore/Helpers/ParsedInputResult.cs b/SharedLibraryCore/Helpers/ParsedInputResult.cs new file mode 100644 index 00000000..3c590f59 --- /dev/null +++ b/SharedLibraryCore/Helpers/ParsedInputResult.cs @@ -0,0 +1,16 @@ +using System.Collections.Generic; + +namespace SharedLibraryCore.Helpers; + +public class ParsedInputResult +{ + public TResult? Result { get; set; } + public string? RawInput { get; set; } + public List ErrorMessages { get; set; } = []; + + public ParsedInputResult WithError(string errorMessage) + { + ErrorMessages.Add(errorMessage); + return this; + } +} diff --git a/SharedLibraryCore/Utilities.cs b/SharedLibraryCore/Utilities.cs index 4ac41ac8..ee47a773 100644 --- a/SharedLibraryCore/Utilities.cs +++ b/SharedLibraryCore/Utilities.cs @@ -1375,28 +1375,32 @@ public static void ExecuteAfterDelay(int delayMs, Func public static void ExecuteAfterDelay(this Func action, int delayMs, CancellationToken token = default) => ExecuteAfterDelay(delayMs, action, token); - public static async Task PromptClientInput(this EFClient client, string[] prompt, Func> validator, - CancellationToken token = default) + public static async Task> PromptClientInput(this EFClient client, string[] prompts, + Func>> parser, string tokenExpiredMessage, CancellationToken token = default) { var clientResponse = new ManualResetEventSlim(false); - string response = null; + ParsedInputResult? response = null; try { IGameEventSubscriptions.ClientMessaged += OnResponse; - await client.TellAsync(prompt, token); + await client.TellAsync(prompts, token); using var tokenSource = new CancellationTokenSource(DefaultCommandTimeout); using var linkedTokenSource = CancellationTokenSource.CreateLinkedTokenSource(tokenSource.Token, token); - clientResponse.Wait(linkedTokenSource.Token); + try + { + clientResponse.Wait(linkedTokenSource.Token); + } + catch (OperationCanceledException) + { + await client.TellAsync([tokenExpiredMessage], token); + return new ParsedInputResult { ErrorMessages = [tokenExpiredMessage] }; + } return response; } - catch (OperationCanceledException) - { - return null; - } finally { IGameEventSubscriptions.ClientMessaged -= OnResponse; @@ -1410,16 +1414,17 @@ async Task OnResponse(ClientMessageEvent messageEvent, CancellationToken cancell return; } - response = messageEvent.Message; + response = await parser(messageEvent.Message); + response.RawInput = messageEvent.Message; - if (await validator(response)) + if (response.ErrorMessages.Count is 0) { // ReSharper disable once AccessToDisposedClosure clientResponse.Set(); } else { - await client.TellAsync(prompt, cancellationToken); + await client.TellAsync(response.ErrorMessages.Concat(prompts), cancellationToken); } } }