From 5d6d3cc08ae5b5778781503bda60de13b726a71a Mon Sep 17 00:00:00 2001 From: Harry Cordewener Date: Sun, 17 Nov 2024 19:38:01 -0600 Subject: [PATCH] v1.0.8: ValueTasks --- CHANGELOG.md | 5 + README.md | 36 ++--- .../MockPipelineClient.cs | 130 +++++++++--------- .../KestrelMockServer.cs | 52 +++---- TelnetNegotiationCore.TestServer/Program.cs | 35 +++-- TelnetNegotiationCore.TestServer/Startup.cs | 33 +++-- .../CHARSETTests.cs | 12 +- .../CreateDotGraph.cs | 8 +- TelnetNegotiationCore.UnitTests/TTypeTests.cs | 10 +- .../Handlers/MSDPClientHandler.cs | 2 +- .../Handlers/MSDPServerHandler.cs | 39 +++--- .../Handlers/MSDPServerModel.cs | 78 +++++------ .../Interpreters/TelnetCharsetInterpreter.cs | 47 +++---- .../Interpreters/TelnetEORInterpreter.cs | 44 +++--- .../Interpreters/TelnetGMCPInterpreter.cs | 28 ++-- .../Interpreters/TelnetMSDPInterpreter.cs | 16 +-- .../Interpreters/TelnetMSSPInterpreter.cs | 20 +-- .../Interpreters/TelnetNAWSInterpreter.cs | 20 +-- .../Interpreters/TelnetStandardInterpreter.cs | 36 ++--- .../TelnetSuppressGAInterpreter.cs | 32 ++--- .../TelnetTerminalTypeInterpreter.cs | 20 +-- TelnetNegotiationCore/Models/MSSPConfig.cs | 2 +- TelnetNegotiationCore/Models/Trigger.cs | 2 +- .../TelnetNegotiationCore.csproj | 3 +- 24 files changed, 354 insertions(+), 356 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a2e806c..78c2205 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,11 @@ # Change Log All notable changes to this project will be documented in this file. +## [1.0.8] - 2024-11-17 + +### Changed +- Use ValueTasks instead of Tasks for improved performance. + ## [1.0.7] - 2024-03-19 ### Changed diff --git a/README.md b/README.md index 0b2ed8a..80e8ba0 100644 --- a/README.md +++ b/README.md @@ -59,7 +59,7 @@ Log.Logger = log; Create functions that implement your desired behavior on getting a signal. ```csharp -private async Task WriteToOutputStreamAsync(byte[] arg, StreamWriter writer) +private async ValueTask WriteToOutputStreamAsync(byte[] arg, StreamWriter writer) { try { @@ -71,19 +71,19 @@ private async Task WriteToOutputStreamAsync(byte[] arg, StreamWriter writer) } } -public static Task WriteBackAsync(byte[] writeback, Encoding encoding) => +public static ValueTask WriteBackAsync(byte[] writeback, Encoding encoding) => Task.Run(() => Console.WriteLine(encoding.GetString(writeback))); -public Task SignalGMCPAsync((string module, string writeback) val, Encoding encoding) => +public ValueTask SignalGMCPAsync((string module, string writeback) val, Encoding encoding) => Task.Run(() => _Logger.LogDebug("GMCP Signal: {Module}: {WriteBack}", val.module, val.writeback)); -public Task SignalMSSPAsync(MSSPConfig val) => +public ValueTask SignalMSSPAsync(MSSPConfig val) => Task.Run(() => _Logger.LogDebug("New MSSP: {@MSSP}", val)); -public Task SignalPromptAsync() => +public ValueTask SignalPromptAsync() => Task.Run(() => _Logger.LogDebug("Prompt")); -public Task SignalNAWSAsync(int height, int width) => +public ValueTask SignalNAWSAsync(int height, int width) => Task.Run(() => _Logger.LogDebug("Client Height and Width updated: {Height}x{Width}", height, width)); ``` @@ -123,7 +123,7 @@ public class KestrelMockServer : ConnectionHandler _Logger = logger; } - private async Task WriteToOutputStreamAsync(byte[] arg, PipeWriter writer) + private async ValueTask WriteToOutputStreamAsync(byte[] arg, PipeWriter writer) { try { @@ -135,28 +135,28 @@ public class KestrelMockServer : ConnectionHandler } } - public Task SignalGMCPAsync((string module, string writeback) val) + public ValueTask SignalGMCPAsync((string module, string writeback) val) { _Logger.LogDebug("GMCP Signal: {Module}: {WriteBack}", val.module, val.writeback); - return Task.CompletedTask; + return ValueTask.CompletedTask; } - public Task SignalMSSPAsync(MSSPConfig val) + public ValueTask SignalMSSPAsync(MSSPConfig val) { _Logger.LogDebug("New MSSP: {@MSSPConfig}", val); - return Task.CompletedTask; + return ValueTask.CompletedTask; } - public Task SignalNAWSAsync(int height, int width) + public ValueTask SignalNAWSAsync(int height, int width) { _Logger.LogDebug("Client Height and Width updated: {Height}x{Width}", height, width); - return Task.CompletedTask; + return ValueTask.CompletedTask; } - private static async Task SignalMSDPAsync(MSDPServerHandler handler, TelnetInterpreter telnet, string config) => + private static async ValueTask SignalMSDPAsync(MSDPServerHandler handler, TelnetInterpreter telnet, string config) => await handler.HandleAsync(telnet, config); - public static async Task WriteBackAsync(byte[] writeback, Encoding encoding, TelnetInterpreter telnet) + public static async ValueTask WriteBackAsync(byte[] writeback, Encoding encoding, TelnetInterpreter telnet) { var str = encoding.GetString(writeback); if (str.StartsWith("echo")) @@ -166,13 +166,13 @@ public class KestrelMockServer : ConnectionHandler Console.WriteLine(encoding.GetString(writeback)); } - private async Task MSDPUpdateBehavior(string resetVariable) + private async ValueTask MSDPUpdateBehavior(string resetVariable) { _Logger.LogDebug("MSDP Reset Request: {@Reset}", resetVariable); - await Task.CompletedTask; + await ValueTask.CompletedTask; } - public async override Task OnConnectedAsync(ConnectionContext connection) + public async override ValueTask OnConnectedAsync(ConnectionContext connection) { using (_Logger.BeginScope(new Dictionary { { "ConnectionId", connection.ConnectionId } })) { diff --git a/TelnetNegotiationCore.TestClient/MockPipelineClient.cs b/TelnetNegotiationCore.TestClient/MockPipelineClient.cs index f882296..8f0d6a2 100644 --- a/TelnetNegotiationCore.TestClient/MockPipelineClient.cs +++ b/TelnetNegotiationCore.TestClient/MockPipelineClient.cs @@ -4,93 +4,91 @@ using Pipelines.Sockets.Unofficial; using System.Text; using TelnetNegotiationCore.Models; -using System.Collections.Immutable; using Microsoft.Extensions.Logging; -namespace TelnetNegotiationCore.TestClient +namespace TelnetNegotiationCore.TestClient; + +public class MockPipelineClient(ILogger logger) { - public class MockPipelineClient(ILogger logger) + private async ValueTask WriteToOutputStreamAsync(byte[] arg, PipeWriter writer) { - - private async Task WriteToOutputStreamAsync(byte[] arg, PipeWriter writer) + try { - try - { - await writer.WriteAsync(new ReadOnlyMemory(arg), CancellationToken.None); - } - catch (ObjectDisposedException ode) - { - logger.LogError(ode, "Stream has been closed"); - } + await writer.WriteAsync(new ReadOnlyMemory(arg), CancellationToken.None); } - - public static Task WriteBackAsync(byte[] writeback, Encoding encoding, TelnetInterpreter t) => - Task.Run(() => Console.WriteLine(encoding.GetString(writeback.AsSpan()))); - - public Task SignalGMCPAsync((string module, string writeback) val) + catch (ObjectDisposedException ode) { - logger.LogDebug("GMCP Signal: {Module}: {WriteBack}", val.module, val.writeback); - return Task.CompletedTask; + logger.LogError(ode, "Stream has been closed"); } + } - public Task SignalMSSPAsync(MSSPConfig val) - { - logger.LogDebug("New MSSP: {@MSSPConfig}", val); - return Task.CompletedTask; - } + public static async ValueTask WriteBackAsync(byte[] writeback, Encoding encoding, TelnetInterpreter t) => + await Task.Run(() => Console.WriteLine(encoding.GetString(writeback.AsSpan()))); + + public ValueTask SignalGMCPAsync((string module, string writeback) val) + { + logger.LogDebug("GMCP Signal: {Module}: {WriteBack}", val.module, val.writeback); + return ValueTask.CompletedTask; + } - public Task SignalPromptAsync() => - Task.Run(() => logger.LogDebug("Prompt")); + public ValueTask SignalMSSPAsync(MSSPConfig val) + { + logger.LogDebug("New MSSP: {@MSSPConfig}", val); + return ValueTask.CompletedTask; + } - public async Task StartAsync(string address, int port) + public async ValueTask SignalPromptAsync() => + await Task.Run(() => logger.LogDebug("Prompt")); + + public async Task StartAsync(string address, int port) + { + var client = new TcpClient(address, port); + var stream = client.GetStream(); + var pipe = StreamConnection.GetDuplex(stream, new PipeOptions()); + + var telnet = await new TelnetInterpreter(TelnetInterpreter.TelnetMode.Client, logger) { - var client = new TcpClient(address, port); - var stream = client.GetStream(); - var pipe = StreamConnection.GetDuplex(stream, new PipeOptions()); + CallbackOnSubmitAsync = WriteBackAsync, + CallbackNegotiationAsync = (x) => WriteToOutputStreamAsync(x, pipe.Output), + SignalOnGMCPAsync = SignalGMCPAsync, + SignalOnMSSPAsync = SignalMSSPAsync, + SignalOnPromptingAsync = SignalPromptAsync, + CharsetOrder = [Encoding.GetEncoding("utf-8"), Encoding.GetEncoding("iso-8859-1")] + }.BuildAsync(); - var telnet = await new TelnetInterpreter(TelnetInterpreter.TelnetMode.Client, logger) - { - CallbackOnSubmitAsync = WriteBackAsync, - CallbackNegotiationAsync = (x) => WriteToOutputStreamAsync(x, pipe.Output), - SignalOnGMCPAsync = SignalGMCPAsync, - SignalOnMSSPAsync = SignalMSSPAsync, - SignalOnPromptingAsync = SignalPromptAsync, - CharsetOrder = new[] { Encoding.GetEncoding("utf-8"), Encoding.GetEncoding("iso-8859-1") } - }.BuildAsync(); + var backgroundTask = Task.Run(() => ReadFromPipeline(telnet, pipe.Input)); - var backgroundTask = Task.Run(() => ReadFromPipeline(telnet, pipe.Input)); + while (true) + { + string read = Console.ReadLine() ?? string.Empty; - while (true) + if (telnet != null) { - string read = Console.ReadLine() ?? string.Empty; - - if (telnet != null) - { - await telnet.SendPromptAsync(telnet?.CurrentEncoding.GetBytes(read)); - } + await telnet.SendPromptAsync(telnet?.CurrentEncoding.GetBytes(read)); } } + } - /// - /// Read data coming from the server and interpret it. - /// - /// The Pipeline Reader - /// A ValueTask - static async ValueTask ReadFromPipeline(TelnetInterpreter telnet, PipeReader reader) + /// + /// Read data coming from the server and interpret it. + /// + /// Interpreter + /// The Pipeline Reader + /// A ValueTask + static async ValueTask ReadFromPipeline(TelnetInterpreter telnet, PipeReader reader) + { + while (true) { - while (true) - { - // await some data being available - ReadResult read = await reader.ReadAtLeastAsync(1); + // await some data being available + var read = await reader.ReadAtLeastAsync(1); - foreach(var segment in read.Buffer) - { - await telnet.InterpretByteArrayAsync(segment.Span.ToImmutableArray()); - } - - // tell the pipe that we used everything - reader.AdvanceTo(read.Buffer.End); + foreach(var segment in read.Buffer) + { + await telnet.InterpretByteArrayAsync([..segment.Span]); } + + // tell the pipe that we used everything + reader.AdvanceTo(read.Buffer.End); } } -} +} \ No newline at end of file diff --git a/TelnetNegotiationCore.TestServer/KestrelMockServer.cs b/TelnetNegotiationCore.TestServer/KestrelMockServer.cs index e482d5e..2dbf080 100644 --- a/TelnetNegotiationCore.TestServer/KestrelMockServer.cs +++ b/TelnetNegotiationCore.TestServer/KestrelMockServer.cs @@ -15,15 +15,15 @@ namespace TelnetNegotiationCore.TestServer { public class KestrelMockServer : ConnectionHandler { - private readonly ILogger _Logger; + private readonly ILogger _logger; - public KestrelMockServer(ILogger logger) : base() + public KestrelMockServer(ILogger logger) { Console.OutputEncoding = Encoding.UTF8; - _Logger = logger; + _logger = logger; } - private async Task WriteToOutputStreamAsync(byte[] arg, PipeWriter writer) + private async ValueTask WriteToOutputStreamAsync(byte[] arg, PipeWriter writer) { try { @@ -31,32 +31,32 @@ private async Task WriteToOutputStreamAsync(byte[] arg, PipeWriter writer) } catch (ObjectDisposedException ode) { - _Logger.LogError(ode, "Stream has been closed"); + _logger.LogError(ode, "Stream has been closed"); } } - public Task SignalGMCPAsync((string module, string writeback) val) + public ValueTask SignalGMCPAsync((string module, string writeback) val) { - _Logger.LogDebug("GMCP Signal: {Module}: {WriteBack}", val.module, val.writeback); - return Task.CompletedTask; + _logger.LogDebug("GMCP Signal: {Module}: {WriteBack}", val.module, val.writeback); + return ValueTask.CompletedTask; } - public Task SignalMSSPAsync(MSSPConfig val) + public ValueTask SignalMSSPAsync(MSSPConfig val) { - _Logger.LogDebug("New MSSP: {@MSSPConfig}", val); - return Task.CompletedTask; + _logger.LogDebug("New MSSP: {@MSSPConfig}", val); + return ValueTask.CompletedTask; } - public Task SignalNAWSAsync(int height, int width) + public ValueTask SignalNAWSAsync(int height, int width) { - _Logger.LogDebug("Client Height and Width updated: {Height}x{Width}", height, width); - return Task.CompletedTask; + _logger.LogDebug("Client Height and Width updated: {Height}x{Width}", height, width); + return ValueTask.CompletedTask; } - private static async Task SignalMSDPAsync(MSDPServerHandler handler, TelnetInterpreter telnet, string config) => + private static async ValueTask SignalMSDPAsync(MSDPServerHandler handler, TelnetInterpreter telnet, string config) => await handler.HandleAsync(telnet, config); - public static async Task WriteBackAsync(byte[] writeback, Encoding encoding, TelnetInterpreter telnet) + public static async ValueTask WriteBackAsync(byte[] writeback, Encoding encoding, TelnetInterpreter telnet) { var str = encoding.GetString(writeback); if (str.StartsWith("echo")) @@ -66,17 +66,17 @@ public static async Task WriteBackAsync(byte[] writeback, Encoding encoding, Tel Console.WriteLine(encoding.GetString(writeback)); } - private async Task MSDPUpdateBehavior(string resetVariable) + private async ValueTask MSDPUpdateBehavior(string resetVariable) { - _Logger.LogDebug("MSDP Reset Request: {@Reset}", resetVariable); - await Task.CompletedTask; + _logger.LogDebug("MSDP Reset Request: {@Reset}", resetVariable); + await ValueTask.CompletedTask; } - public async override Task OnConnectedAsync(ConnectionContext connection) + public override async Task OnConnectedAsync(ConnectionContext connection) { - using (_Logger.BeginScope(new Dictionary { { "ConnectionId", connection.ConnectionId } })) + using (_logger.BeginScope(new Dictionary { { "ConnectionId", connection.ConnectionId } })) { - _Logger.LogInformation("{ConnectionId} connected", connection.ConnectionId); + _logger.LogInformation("{ConnectionId} connected", connection.ConnectionId); var MSDPHandler = new MSDPServerHandler(new MSDPServerModel(MSDPUpdateBehavior) { @@ -86,15 +86,15 @@ public async override Task OnConnectedAsync(ConnectionContext connection) Sendable_Variables = () => ["ROOM"], }); - var telnet = await new TelnetInterpreter(TelnetInterpreter.TelnetMode.Server, _Logger) + var telnet = await new TelnetInterpreter(TelnetInterpreter.TelnetMode.Server, _logger) { CallbackOnSubmitAsync = WriteBackAsync, SignalOnGMCPAsync = SignalGMCPAsync, SignalOnMSSPAsync = SignalMSSPAsync, SignalOnNAWSAsync = SignalNAWSAsync, SignalOnMSDPAsync = (telnet, config) => SignalMSDPAsync(MSDPHandler, telnet, config), - CallbackNegotiationAsync = (x) => WriteToOutputStreamAsync(x, connection.Transport.Output), - CharsetOrder = new[] { Encoding.GetEncoding("utf-8"), Encoding.GetEncoding("iso-8859-1") } + CallbackNegotiationAsync = x => WriteToOutputStreamAsync(x, connection.Transport.Output), + CharsetOrder = [Encoding.GetEncoding("utf-8"), Encoding.GetEncoding("iso-8859-1")] } .RegisterMSSPConfig(() => new MSSPConfig { @@ -126,7 +126,7 @@ public async override Task OnConnectedAsync(ConnectionContext connection) connection.Transport.Input.AdvanceTo(buffer.End); } - _Logger.LogInformation("{ConnectionId} disconnected", connection.ConnectionId); + _logger.LogInformation("{ConnectionId} disconnected", connection.ConnectionId); } } } diff --git a/TelnetNegotiationCore.TestServer/Program.cs b/TelnetNegotiationCore.TestServer/Program.cs index e141006..8ea9934 100644 --- a/TelnetNegotiationCore.TestServer/Program.cs +++ b/TelnetNegotiationCore.TestServer/Program.cs @@ -1,31 +1,28 @@ using Microsoft.AspNetCore; using Microsoft.AspNetCore.Connections; using Microsoft.AspNetCore.Hosting; -using Microsoft.Extensions.Logging; using Serilog; using System.Threading.Tasks; -namespace TelnetNegotiationCore.TestServer +namespace TelnetNegotiationCore.TestServer; + +public class Program { - public class Program + public static async Task Main(string[] args) { - static async Task Main(string[] args) - { - var log = new LoggerConfiguration() - .Enrich.FromLogContext() - .WriteTo.Console() - .MinimumLevel.Debug() - .CreateLogger(); - - Log.Logger = log; + var log = new LoggerConfiguration() + .Enrich.FromLogContext() + .WriteTo.Console() + .MinimumLevel.Debug() + .CreateLogger(); - CreateWebHostBuilder(args).Build().Run(); - await Task.CompletedTask; - } + Log.Logger = log; - public static IWebHostBuilder CreateWebHostBuilder(string[] args) => - WebHost.CreateDefaultBuilder(args) - .UseStartup() - .UseKestrel(options => options.ListenLocalhost(4202, builder => builder.UseConnectionHandler())); + await CreateWebHostBuilder(args).Build().RunAsync(); } + + private static IWebHostBuilder CreateWebHostBuilder(string[] args) => + WebHost.CreateDefaultBuilder(args) + .UseStartup() + .UseKestrel(options => options.ListenLocalhost(4202, builder => builder.UseConnectionHandler())); } \ No newline at end of file diff --git a/TelnetNegotiationCore.TestServer/Startup.cs b/TelnetNegotiationCore.TestServer/Startup.cs index ff441ea..cbe1884 100644 --- a/TelnetNegotiationCore.TestServer/Startup.cs +++ b/TelnetNegotiationCore.TestServer/Startup.cs @@ -5,24 +5,23 @@ using Serilog; using System.Threading.Tasks; -namespace TelnetNegotiationCore.TestServer +namespace TelnetNegotiationCore.TestServer; + +public class Startup { - public class Startup + // This method gets called by the runtime. Use this method to add services to the container. + // For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940 + public static void ConfigureServices(IServiceCollection services) { - // This method gets called by the runtime. Use this method to add services to the container. - // For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940 - public static void ConfigureServices(IServiceCollection services) + services.AddLogging(logging => { - services.AddLogging(logging => - { - logging.ClearProviders(); - logging.AddSerilog(); - logging.SetMinimumLevel(LogLevel.Debug); - }); - services.BuildServiceProvider(); - } - - // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. - public static void Configure(IApplicationBuilder app, IHostingEnvironment _) => app.Run(async _ => await Task.CompletedTask); + logging.ClearProviders(); + logging.AddSerilog(); + logging.SetMinimumLevel(LogLevel.Debug); + }); + services.BuildServiceProvider(); } -} + + // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. + public static void Configure(IApplicationBuilder app, IHostingEnvironment _) => app.Run(async _ => await Task.CompletedTask); +} \ No newline at end of file diff --git a/TelnetNegotiationCore.UnitTests/CHARSETTests.cs b/TelnetNegotiationCore.UnitTests/CHARSETTests.cs index a9fef38..8469b5d 100644 --- a/TelnetNegotiationCore.UnitTests/CHARSETTests.cs +++ b/TelnetNegotiationCore.UnitTests/CHARSETTests.cs @@ -15,13 +15,13 @@ public class CharsetTests() : BaseTest { private byte[] _negotiationOutput; - private Task WriteBackToOutput(byte[] arg1, Encoding arg2, TelnetInterpreter t) => throw new NotImplementedException(); + private ValueTask WriteBackToOutput(byte[] arg1, Encoding arg2, TelnetInterpreter t) => throw new NotImplementedException(); - private Task WriteBackToGMCP((string module, string writeback) arg1) => throw new NotImplementedException(); + private ValueTask WriteBackToGMCP((string module, string writeback) arg1) => throw new NotImplementedException(); - private Task ClientWriteBackToNegotiate(byte[] arg1) { _negotiationOutput = arg1; return Task.CompletedTask; } + private ValueTask ClientWriteBackToNegotiate(byte[] arg1) { _negotiationOutput = arg1; return ValueTask.CompletedTask; } - private Task ServerWriteBackToNegotiate(byte[] arg1) { _negotiationOutput = arg1; return Task.CompletedTask; } + private ValueTask ServerWriteBackToNegotiate(byte[] arg1) { _negotiationOutput = arg1; return ValueTask.CompletedTask; } [SetUp] public void Setup() @@ -38,7 +38,7 @@ public async Task ServerEvaluationCheck(IEnumerable clientSends, IEnumer CallbackNegotiationAsync = ServerWriteBackToNegotiate, CallbackOnSubmitAsync = WriteBackToOutput, SignalOnGMCPAsync = WriteBackToGMCP, - CallbackOnByteAsync = (x, y) => Task.CompletedTask, + CallbackOnByteAsync = (x, y) => ValueTask.CompletedTask, }.RegisterMSSPConfig(() => new MSSPConfig { Name = "My Telnet Negotiated Server", @@ -75,7 +75,7 @@ public async Task ClientEvaluationCheck(IEnumerable serverSends, IEnumer CallbackNegotiationAsync = ClientWriteBackToNegotiate, CallbackOnSubmitAsync = WriteBackToOutput, SignalOnGMCPAsync = WriteBackToGMCP, - CallbackOnByteAsync = (x, y) => Task.CompletedTask, + CallbackOnByteAsync = (x, y) => ValueTask.CompletedTask, CharsetOrder = new[] { Encoding.GetEncoding("utf-8"), Encoding.GetEncoding("iso-8859-1") } }.RegisterMSSPConfig(() => new MSSPConfig { diff --git a/TelnetNegotiationCore.UnitTests/CreateDotGraph.cs b/TelnetNegotiationCore.UnitTests/CreateDotGraph.cs index 39276a9..9b34d2c 100644 --- a/TelnetNegotiationCore.UnitTests/CreateDotGraph.cs +++ b/TelnetNegotiationCore.UnitTests/CreateDotGraph.cs @@ -58,11 +58,11 @@ await File.WriteAllTextAsync(Path.Combine(Directory.GetCurrentDirectory(), "..", dotGraph); } - private async Task WriteToOutputStream(byte[] arg) => await Task.CompletedTask; + private async ValueTask WriteToOutputStream(byte[] arg) => await ValueTask.CompletedTask; - private async Task SignalNAWS(int arg1, int arg2) => await Task.CompletedTask; + private async ValueTask SignalNAWS(int arg1, int arg2) => await ValueTask.CompletedTask; - private async Task WriteBack(byte[] arg1, Encoding encoding, TelnetInterpreter t) => await Task.CompletedTask; + private async ValueTask WriteBack(byte[] arg1, Encoding encoding, TelnetInterpreter t) => await ValueTask.CompletedTask; - private async Task WriteBackToGMCP((string module, string writeback) arg1) => await Task.CompletedTask; + private async ValueTask WriteBackToGMCP((string module, string writeback) arg1) => await ValueTask.CompletedTask; } \ No newline at end of file diff --git a/TelnetNegotiationCore.UnitTests/TTypeTests.cs b/TelnetNegotiationCore.UnitTests/TTypeTests.cs index e5842fa..bb4e4d0 100644 --- a/TelnetNegotiationCore.UnitTests/TTypeTests.cs +++ b/TelnetNegotiationCore.UnitTests/TTypeTests.cs @@ -16,11 +16,11 @@ public class TTypeTests: BaseTest private TelnetInterpreter _client_ti; private byte[] _negotiationOutput; - private Task WriteBackToOutput(byte[] arg1, Encoding arg2, TelnetInterpreter t) => throw new NotImplementedException(); + private ValueTask WriteBackToOutput(byte[] arg1, Encoding arg2, TelnetInterpreter t) => throw new NotImplementedException(); - private Task WriteBackToNegotiate(byte[] arg1) { _negotiationOutput = arg1; return Task.CompletedTask; } + private ValueTask WriteBackToNegotiate(byte[] arg1) { _negotiationOutput = arg1; return ValueTask.CompletedTask; } - private Task WriteBackToGMCP((string Package, string Info) tuple) => throw new NotImplementedException(); + private ValueTask WriteBackToGMCP((string Package, string Info) tuple) => throw new NotImplementedException(); [SetUp] public async Task Setup() @@ -30,7 +30,7 @@ public async Task Setup() CallbackNegotiationAsync = WriteBackToNegotiate, CallbackOnSubmitAsync = WriteBackToOutput, SignalOnGMCPAsync = WriteBackToGMCP, - CallbackOnByteAsync = (x, y) => Task.CompletedTask, + CallbackOnByteAsync = (x, y) => ValueTask.CompletedTask, }.RegisterMSSPConfig(() => new MSSPConfig { Name = "My Telnet Negotiated Server", @@ -48,7 +48,7 @@ public async Task Setup() CallbackNegotiationAsync = WriteBackToNegotiate, CallbackOnSubmitAsync = WriteBackToOutput, SignalOnGMCPAsync = WriteBackToGMCP, - CallbackOnByteAsync = (x, y) => Task.CompletedTask, + CallbackOnByteAsync = (x, y) => ValueTask.CompletedTask, }.RegisterMSSPConfig(() => new MSSPConfig { Name = "My Telnet Negotiated Client", diff --git a/TelnetNegotiationCore/Handlers/MSDPClientHandler.cs b/TelnetNegotiationCore/Handlers/MSDPClientHandler.cs index 52d9f94..43a76b0 100644 --- a/TelnetNegotiationCore/Handlers/MSDPClientHandler.cs +++ b/TelnetNegotiationCore/Handlers/MSDPClientHandler.cs @@ -8,7 +8,7 @@ namespace TelnetNegotiationCore.Handlers; /// public class MSDPClientHandler() { - public Task HandleAsync(string serverJson) + public ValueTask HandleAsync(string serverJson) { throw new NotImplementedException(); } diff --git a/TelnetNegotiationCore/Handlers/MSDPServerHandler.cs b/TelnetNegotiationCore/Handlers/MSDPServerHandler.cs index 074887c..13c5ce8 100644 --- a/TelnetNegotiationCore/Handlers/MSDPServerHandler.cs +++ b/TelnetNegotiationCore/Handlers/MSDPServerHandler.cs @@ -21,7 +21,7 @@ public class MSDPServerHandler(MSDPServerModel model) { public MSDPServerModel Data { get; private init; } = model; - public async Task HandleAsync(TelnetInterpreter telnet, string clientJson) + public async ValueTask HandleAsync(TelnetInterpreter telnet, string clientJson) { var json = JsonSerializer.Deserialize(clientJson); @@ -61,15 +61,15 @@ public async Task HandleAsync(TelnetInterpreter telnet, string clientJson) /// /// Telnet Interpreter to callback with. /// The item to report - private async Task HandleListRequestAsync(TelnetInterpreter telnet, string item) => + private async ValueTask HandleListRequestAsync(TelnetInterpreter telnet, string item) => await ExecuteOnAsync(item, async (val) => - await (Data.Lists.TryGetValue(val, out Func> value) + await (Data.Lists.TryGetValue(val, out var value) ? telnet.CallbackNegotiationAsync( MSDPLibrary.Report(JsonSerializer.Serialize(value()), telnet.CurrentEncoding)) - : Task.CompletedTask)); + : ValueTask.CompletedTask)); - private async Task HandleReportRequestAsync(TelnetInterpreter telnet, string item) => + private async ValueTask HandleReportRequestAsync(TelnetInterpreter telnet, string item) => await ExecuteOnAsync(item, async (val) => { await HandleSendRequestAsync(telnet, val); @@ -82,11 +82,11 @@ await ExecuteOnAsync(item, async (val) => /// though any LIST option can be used. /// /// Item to reset - private async Task HandleResetRequestAsync(string item) => - await ExecuteOnAsync(item, async (var) => + private async ValueTask HandleResetRequestAsync(string item) => + await ExecuteOnAsync(item, (var) => { var found = Data.Reportable_Variables().TryGetValue(var, out var list); - await Task.CompletedTask; + return ValueTask.CompletedTask; }); /// @@ -97,7 +97,7 @@ await ExecuteOnAsync(item, async (var) => /// /// Telnet interpreter to send back negotiation with /// The item to send - private async Task HandleSendRequestAsync(TelnetInterpreter telnet, string item) => + private async ValueTask HandleSendRequestAsync(TelnetInterpreter telnet, string item) => await ExecuteOnAsync(item, async (var) => { var found = Data.Sendable_Variables().TryGetValue(var, out var val); @@ -109,24 +109,19 @@ await ExecuteOnAsync(item, async (var) => /// The UNREPORT command is used to remove the report status of variables after the use of the REPORT command. /// /// The item to stop reporting on - private async Task HandleUnReportRequestAsync(string item) => - await ExecuteOnAsync(item, async (var) => + private async ValueTask HandleUnReportRequestAsync(string item) => + await ExecuteOnAsync(item, (var) => { Data.UnReport(var); - await Task.CompletedTask; + return ValueTask.CompletedTask; }); - private async Task ExecuteOnAsync(string item, Func function) + private async ValueTask ExecuteOnAsync(string item, Func function) { - string[] items; - if (item.StartsWith('[')) - { - items = JsonSerializer.Deserialize(item); - } - else - { - items = [item]; - } + var items = item.StartsWith('[') + ? JsonSerializer.Deserialize(item) + : [item]; + foreach (var val in items) { await function(val); diff --git a/TelnetNegotiationCore/Handlers/MSDPServerModel.cs b/TelnetNegotiationCore/Handlers/MSDPServerModel.cs index d7ea6c3..ae951a1 100644 --- a/TelnetNegotiationCore/Handlers/MSDPServerModel.cs +++ b/TelnetNegotiationCore/Handlers/MSDPServerModel.cs @@ -64,53 +64,53 @@ namespace TelnetNegotiationCore.Handlers; /// public class MSDPServerModel { - /// - /// What lists we can report on. - /// - public Dictionary>> Lists { get; private init; } + /// + /// What lists we can report on. + /// + public Dictionary>> Lists { get; private init; } - public Func> Commands { get; set; } = () => []; + public Func> Commands { get; set; } = () => []; - public Func> Configurable_Variables { get; set; } = () => []; + public Func> Configurable_Variables { get; set; } = () => []; - public Func> Reportable_Variables { get; set; } = () => []; + public Func> Reportable_Variables { get; set; } = () => []; - public Dictionary> Reported_Variables => []; + public Dictionary> Reported_Variables => []; - public Func> Sendable_Variables { get; set; } = () => []; + public Func> Sendable_Variables { get; set; } = () => []; - public Func ResetCallbackAsync { get; } + public Func ResetCallbackAsync { get; } - /// - /// Creates the MSDP Server Model. - /// Define each public variable to implement MSDP. - /// - /// Function to call when a client wishes to set a server variable. - public MSDPServerModel(Func resetCallback) - { - Lists = new() - { - { "COMMANDS", Commands}, - { "CONFIGURABLE_VARIABLES", Configurable_Variables}, - { "REPORTABLE_VARIABLES", Reportable_Variables}, - { "REPORTED_VARIABLES", () => Reported_Variables.Select( x=> x.Key).ToHashSet() }, - { "SENDABLE_VARIABLES", Sendable_Variables} - }; - - ResetCallbackAsync = resetCallback; - } + /// + /// Creates the MSDP Server Model. + /// Define each public variable to implement MSDP. + /// + /// Function to call when a client wishes to set a server variable. + public MSDPServerModel(Func resetCallback) + { + Lists = new() + { + { "COMMANDS", Commands }, + { "CONFIGURABLE_VARIABLES", Configurable_Variables }, + { "REPORTABLE_VARIABLES", Reportable_Variables }, + { "REPORTED_VARIABLES", () => Reported_Variables.Select(x => x.Key).ToHashSet() }, + { "SENDABLE_VARIABLES", Sendable_Variables } + }; - public async Task ResetAsync(string configurableVariable) => - await ResetCallbackAsync(configurableVariable); + ResetCallbackAsync = resetCallback; + } - public void Report(string reportableVariable, Func function) => - Reported_Variables.Add(reportableVariable, function); + public async ValueTask ResetAsync(string configurableVariable) => + await ResetCallbackAsync(configurableVariable); - public void UnReport(string reportableVariable) => - Reported_Variables.Remove(reportableVariable); + public void Report(string reportableVariable, Func function) => + Reported_Variables.Add(reportableVariable, function); - public async Task NotifyChangeAsync(string reportableVariable, string newValue) => - await (Reported_Variables.TryGetValue(reportableVariable, out var function) - ? function(newValue) - : Task.CompletedTask); -} + public void UnReport(string reportableVariable) => + Reported_Variables.Remove(reportableVariable); + + public async ValueTask NotifyChangeAsync(string reportableVariable, string newValue) => + await (Reported_Variables.TryGetValue(reportableVariable, out var function) + ? function(newValue) + : ValueTask.CompletedTask); +} \ No newline at end of file diff --git a/TelnetNegotiationCore/Interpreters/TelnetCharsetInterpreter.cs b/TelnetNegotiationCore/Interpreters/TelnetCharsetInterpreter.cs index 790ff41..eb457cb 100644 --- a/TelnetNegotiationCore/Interpreters/TelnetCharsetInterpreter.cs +++ b/TelnetNegotiationCore/Interpreters/TelnetCharsetInterpreter.cs @@ -37,13 +37,14 @@ public partial class TelnetInterpreter /// private int _acceptedCharsetByteIndex = 0; - private bool charsetOffered = false; + private bool _charsetOffered = false; private Func> AllowedEncodings { get; set; } = Encoding.GetEncodings; - private Func, IOrderedEnumerable> _charsetOrder = (x) => x.Select(y => y.GetEncoding()).OrderBy(z => z.EncodingName); + private readonly Func, IOrderedEnumerable> _charsetOrder = x + => x.Select(y => y.GetEncoding()).OrderBy(z => z.EncodingName); - private Func SignalCharsetChangeAsync { get; set; } + private Func SignalCharsetChangeAsync { get; set; } public Lazy SupportedCharacterSets { get; } @@ -58,7 +59,7 @@ public IEnumerable CharsetOrder init { var ordered = value.Reverse().ToList(); - _charsetOrder = (x) => x.Select(x => x.GetEncoding()).OrderByDescending(z => ordered.IndexOf(z)); + _charsetOrder = x => x.Select(y => y.GetEncoding()).OrderByDescending(z => ordered.IndexOf(z)); } } @@ -83,7 +84,7 @@ private StateMachine SetupCharsetNegotiation(StateMachine await OnWillingCharsetAsync(x)); tsm.Configure(State.WontDoCharset) .SubstateOf(State.Accepting) @@ -91,7 +92,7 @@ private StateMachine SetupCharsetNegotiation(StateMachine await OnDoCharsetAsync(x)); tsm.Configure(State.DontCharset) .SubstateOf(State.Accepting) @@ -140,14 +141,14 @@ private StateMachine SetupCharsetNegotiation(StateMachine tsm.Configure(State.EvaluatingAcceptedCharsetValue).PermitReentry(t)); tsm.Configure(State.CompletingAcceptedCharset) - .OnEntryAsync(CompleteAcceptedCharsetAsync) + .OnEntryAsync(async x => await CompleteAcceptedCharsetAsync(x)) .SubstateOf(State.Accepting); tsm.Configure(State.CompletingCharset) - .OnEntryAsync(CompleteCharsetAsync) + .OnEntryAsync(async x => await CompleteCharsetAsync(x)) .SubstateOf(State.Accepting); - RegisterInitialWilling(WillingCharsetAsync); + RegisterInitialWilling(async () => await WillingCharsetAsync()); return tsm; } @@ -175,7 +176,7 @@ private void GetAcceptedCharset(StateMachine.Transition _) /// /// Read the Charset state values and finalize it and prepare to respond. /// - /// Ignored + /// Byte private void CaptureCharset(OneOf b) { if (_charsetByteIndex > _charsetByteState.Length) return; @@ -186,7 +187,7 @@ private void CaptureCharset(OneOf b) /// /// Read the Charset state values and finalize it and prepare to respond. /// - /// Ignored + /// private void CaptureAcceptedCharset(OneOf b) { _acceptedCharsetByteState[_acceptedCharsetByteIndex] = b.AsT0; @@ -197,16 +198,16 @@ private void CaptureAcceptedCharset(OneOf b) /// Finalize internal state values for Charset. /// /// Ignored - private async Task CompleteCharsetAsync(StateMachine.Transition _) + private async ValueTask CompleteCharsetAsync(StateMachine.Transition _) { - if (charsetOffered && Mode == TelnetMode.Server) + if (_charsetOffered && Mode == TelnetMode.Server) { await CallbackNegotiationAsync([(byte)Trigger.IAC, (byte)Trigger.SB, (byte)Trigger.CHARSET, (byte)Trigger.REJECTED, (byte)Trigger.IAC, (byte)Trigger.SE]); return; } - char? sep = ascii.GetString(_charsetByteState, 0, 1)?[0]; - string[] charsetsOffered = ascii.GetString(_charsetByteState, 1, _charsetByteIndex - 1).Split(sep ?? ' '); + var sep = ascii.GetString(_charsetByteState, 0, 1)?[0]; + var charsetsOffered = ascii.GetString(_charsetByteState, 1, _charsetByteIndex - 1).Split(sep ?? ' '); _Logger.LogDebug("Charsets offered to us: {@charsetResultDebug}", charsetsOffered); @@ -228,7 +229,7 @@ private async Task CompleteCharsetAsync(StateMachine.Transition byte[] postAmble = [ (byte)Trigger.IAC, (byte)Trigger.SE ]; CurrentEncoding = chosenEncoding; - await (SignalCharsetChangeAsync?.Invoke(CurrentEncoding) ?? Task.CompletedTask); + await (SignalCharsetChangeAsync?.Invoke(CurrentEncoding) ?? ValueTask.CompletedTask); // TODO: The implementing Server or Client needs to be warned when CurrentEncoding is set! // This would allow, for instance, the Console to ensure it displays Unicode correctly. @@ -240,7 +241,7 @@ private async Task CompleteCharsetAsync(StateMachine.Transition /// Finalize internal state values for Accepted Charset. /// /// Ignored - private async Task CompleteAcceptedCharsetAsync(StateMachine.Transition _) + private async ValueTask CompleteAcceptedCharsetAsync(StateMachine.Transition _) { try { @@ -252,23 +253,23 @@ private async Task CompleteAcceptedCharsetAsync(StateMachine.Tra await CallbackNegotiationAsync([(byte)Trigger.IAC, (byte)Trigger.SB, (byte)Trigger.CHARSET, (byte)Trigger.REJECTED, (byte)Trigger.IAC, (byte)Trigger.SE]); } _Logger.LogInformation("Connection: Accepted Charset Negotiation for: {charset}", CurrentEncoding.WebName); - charsetOffered = false; + _charsetOffered = false; } /// /// Announce we do charset negotiation to the client after getting a Willing. /// - private async Task OnWillingCharsetAsync(StateMachine.Transition _) + private async ValueTask OnWillingCharsetAsync(StateMachine.Transition _) { _Logger.LogDebug("Connection: {ConnectionState}", "Request charset negotiation from Client"); await CallbackNegotiationAsync([(byte)Trigger.IAC, (byte)Trigger.DO, (byte)Trigger.CHARSET]); - charsetOffered = false; + _charsetOffered = false; } /// /// Announce we do charset negotiation to the client. /// - private async Task WillingCharsetAsync() + private async ValueTask WillingCharsetAsync() { _Logger.LogDebug("Connection: {ConnectionState}", "Announcing willingness to Charset!"); await CallbackNegotiationAsync([(byte)Trigger.IAC, (byte)Trigger.WILL, (byte)Trigger.CHARSET]); @@ -277,11 +278,11 @@ private async Task WillingCharsetAsync() /// /// Announce the charsets we support to the client after getting a Do. /// - private async Task OnDoCharsetAsync(StateMachine.Transition _) + private async ValueTask OnDoCharsetAsync(StateMachine.Transition _) { _Logger.LogDebug("Charsets String: {CharsetList}", ";" + string.Join(";", _charsetOrder(AllowedEncodings()).Select(x => x.WebName))); await CallbackNegotiationAsync(SupportedCharacterSets.Value); - charsetOffered = true; + _charsetOffered = true; } /// diff --git a/TelnetNegotiationCore/Interpreters/TelnetEORInterpreter.cs b/TelnetNegotiationCore/Interpreters/TelnetEORInterpreter.cs index 0c39377..33b8232 100644 --- a/TelnetNegotiationCore/Interpreters/TelnetEORInterpreter.cs +++ b/TelnetNegotiationCore/Interpreters/TelnetEORInterpreter.cs @@ -10,7 +10,7 @@ public partial class TelnetInterpreter { private bool? _doEOR = null; - public Func SignalOnPromptingAsync { get; init; } + public Func SignalOnPromptingAsync { get; init; } /// /// Character set Negotiation will set the Character Set and Character Page Server & Client have agreed to. @@ -29,13 +29,13 @@ private StateMachine SetupEORNegotiation(StateMachine await OnDoEORAsync(x)); tsm.Configure(State.DontEOR) .SubstateOf(State.Accepting) - .OnEntryAsync(OnDontEORAsync); + .OnEntryAsync(async () => await OnDontEORAsync()); - RegisterInitialWilling(WillingEORAsync); + RegisterInitialWilling(async () => await WillingEORAsync()); } else { @@ -47,11 +47,11 @@ private StateMachine SetupEORNegotiation(StateMachine await WontEORAsync()); tsm.Configure(State.WillEOR) .SubstateOf(State.Accepting) - .OnEntryAsync(OnWillEORAsync); + .OnEntryAsync(async x => await OnWillEORAsync(x)); } tsm.Configure(State.StartNegotiation) @@ -59,35 +59,35 @@ private StateMachine SetupEORNegotiation(StateMachine await OnEORPrompt()); return tsm; } - private async Task OnEORPrompt() + private async ValueTask OnEORPrompt() { _Logger.LogDebug("Connection: {ConnectionState}", "Server is prompting EOR"); - await (SignalOnPromptingAsync?.Invoke() ?? Task.CompletedTask); + await (SignalOnPromptingAsync?.Invoke() ?? ValueTask.CompletedTask); } - private async Task OnDontEORAsync() + private ValueTask OnDontEORAsync() { _Logger.LogDebug("Connection: {ConnectionState}", "Client won't do EOR - do nothing"); _doEOR = false; - await Task.CompletedTask; + return ValueTask.CompletedTask; } - private async Task WontEORAsync() + private ValueTask WontEORAsync() { _Logger.LogDebug("Connection: {ConnectionState}", "Server won't do EOR - do nothing"); _doEOR = false; - await Task.CompletedTask; + return ValueTask.CompletedTask; } /// /// Announce we do EOR negotiation to the client. /// - private async Task WillingEORAsync() + private async ValueTask WillingEORAsync() { _Logger.LogDebug("Connection: {ConnectionState}", "Announcing willingness to EOR!"); await CallbackNegotiationAsync([(byte)Trigger.IAC, (byte)Trigger.WILL, (byte)Trigger.TELOPT_EOR]); @@ -96,17 +96,17 @@ private async Task WillingEORAsync() /// /// Store that we are now in EOR mode. /// - private Task OnDoEORAsync(StateMachine.Transition _) + private ValueTask OnDoEORAsync(StateMachine.Transition _) { _Logger.LogDebug("Connection: {ConnectionState}", "Client supports End of Record."); _doEOR = true; - return Task.CompletedTask; + return ValueTask.CompletedTask; } /// /// Store that we are now in EOR mode. /// - private async Task OnWillEORAsync(StateMachine.Transition _) + private async ValueTask OnWillEORAsync(StateMachine.Transition _) { _Logger.LogDebug("Connection: {ConnectionState}", "Server supports End of Record."); _doEOR = true; @@ -117,8 +117,8 @@ private async Task OnWillEORAsync(StateMachine.Transition _) /// Sends a byte message as a Prompt, if supported, by not sending an EOR at the end. /// /// Byte array - /// A completed Task - public async Task SendPromptAsync(byte[] send) + /// A completed ValueTask + public async ValueTask SendPromptAsync(byte[] send) { await CallbackNegotiationAsync(send); if (_doEOR is null or false) @@ -129,7 +129,7 @@ public async Task SendPromptAsync(byte[] send) { await CallbackNegotiationAsync([(byte)Trigger.IAC, (byte)Trigger.EOR]); } - else if (_doGA is not null or false) + else if (_doGA is not null) { await CallbackNegotiationAsync([(byte)Trigger.IAC, (byte)Trigger.GA]); } @@ -139,8 +139,8 @@ public async Task SendPromptAsync(byte[] send) /// Sends a byte message, adding an EOR at the end if needed. /// /// Byte array - /// A completed Task - public async Task SendAsync(byte[] send) + /// A completed ValueTask + public async ValueTask SendAsync(byte[] send) { await CallbackNegotiationAsync(send); await CallbackNegotiationAsync(CurrentEncoding.GetBytes(Environment.NewLine)); diff --git a/TelnetNegotiationCore/Interpreters/TelnetGMCPInterpreter.cs b/TelnetNegotiationCore/Interpreters/TelnetGMCPInterpreter.cs index b8b0960..c0ffec1 100644 --- a/TelnetNegotiationCore/Interpreters/TelnetGMCPInterpreter.cs +++ b/TelnetNegotiationCore/Interpreters/TelnetGMCPInterpreter.cs @@ -14,7 +14,7 @@ public partial class TelnetInterpreter { private List _GMCPBytes = []; - public Func<(string Package, string Info), Task> SignalOnGMCPAsync { get; init; } + public Func<(string Package, string Info), ValueTask> SignalOnGMCPAsync { get; init; } private StateMachine SetupGMCPNegotiation(StateMachine tsm) { @@ -46,7 +46,7 @@ private StateMachine SetupGMCPNegotiation(StateMachine await DoGMCPAsync(x)); tsm.Configure(State.WontGMCP) .SubstateOf(State.Accepting) @@ -78,7 +78,7 @@ private StateMachine SetupGMCPNegotiation(StateMachine await CompleteGMCPNegotiation(x)); return tsm; } @@ -92,13 +92,13 @@ private void RegisterGMCPValue(OneOf b) _GMCPBytes.Add(b.AsT0); } - public Task SendGMCPCommand(string package, string command) => + public ValueTask SendGMCPCommand(string package, string command) => SendGMCPCommand(CurrentEncoding.GetBytes(package), CurrentEncoding.GetBytes(command)); - public Task SendGMCPCommand(string package, byte[] command) => + public ValueTask SendGMCPCommand(string package, byte[] command) => SendGMCPCommand(CurrentEncoding.GetBytes(package), command); - public async Task SendGMCPCommand(byte[] package, byte[] command) + public async ValueTask SendGMCPCommand(byte[] package, byte[] command) { await CallbackNegotiationAsync( [ @@ -106,7 +106,7 @@ await CallbackNegotiationAsync( .. package, .. CurrentEncoding.GetBytes(" "), .. command, - .. new byte[] { (byte)Trigger.IAC, (byte)Trigger.SE }, + .. new[] { (byte)Trigger.IAC, (byte)Trigger.SE }, ]); } @@ -114,8 +114,8 @@ .. CurrentEncoding.GetBytes(" "), /// Completes the GMCP Negotiation. This is currently assuming a golden path. /// /// Transition, ignored. - /// Task - private async Task CompleteGMCPNegotiation(StateMachine.Transition _) + /// ValueTask + private async ValueTask CompleteGMCPNegotiation(StateMachine.Transition _) { var space = CurrentEncoding.GetBytes(" ").First(); var firstSpace = _GMCPBytes.FindIndex(x => x == space); @@ -127,11 +127,11 @@ private async Task CompleteGMCPNegotiation(StateMachine.Transiti if(package == "MSDP") { - await (SignalOnMSDPAsync?.Invoke(this, JsonSerializer.Serialize(Functional.MSDPLibrary.MSDPScan(packageBytes, CurrentEncoding))) ?? Task.CompletedTask); + await (SignalOnMSDPAsync?.Invoke(this, JsonSerializer.Serialize(Functional.MSDPLibrary.MSDPScan(packageBytes, CurrentEncoding))) ?? ValueTask.CompletedTask); } else { - await (SignalOnGMCPAsync?.Invoke((Package: package, Info: CurrentEncoding.GetString(packageBytes))) ?? Task.CompletedTask); + await (SignalOnGMCPAsync?.Invoke((Package: package, Info: CurrentEncoding.GetString(packageBytes))) ?? ValueTask.CompletedTask); } } @@ -139,15 +139,15 @@ private async Task CompleteGMCPNegotiation(StateMachine.Transiti /// Announces the Server will GMCP. /// /// Transition, ignored. - /// Task - private async Task WillGMCPAsync(StateMachine.Transition _) + /// ValueTask + private async ValueTask WillGMCPAsync(StateMachine.Transition _) { _Logger.LogDebug("Connection: {ConnectionState}", "Announcing the server will GMCP"); await CallbackNegotiationAsync([(byte)Trigger.IAC, (byte)Trigger.WILL, (byte)Trigger.GMCP]); } - private async Task DoGMCPAsync(StateMachine.Transition _) + private async ValueTask DoGMCPAsync(StateMachine.Transition _) { _Logger.LogDebug("Connection: {ConnectionState}", "Announcing the client can do GMCP"); diff --git a/TelnetNegotiationCore/Interpreters/TelnetMSDPInterpreter.cs b/TelnetNegotiationCore/Interpreters/TelnetMSDPInterpreter.cs index bcd2a26..7977cfa 100644 --- a/TelnetNegotiationCore/Interpreters/TelnetMSDPInterpreter.cs +++ b/TelnetNegotiationCore/Interpreters/TelnetMSDPInterpreter.cs @@ -20,7 +20,7 @@ public partial class TelnetInterpreter { private List _currentMSDPInfo; - public Func SignalOnMSDPAsync { get; init; } + public Func SignalOnMSDPAsync { get; init; } /// /// Mud Server Status Protocol will provide information to the requestee about the server's contents. @@ -39,13 +39,13 @@ private StateMachine SetupMSDPNegotiation(StateMachine await OnDoMSDPAsync(x)); tsm.Configure(State.DontMSDP) .SubstateOf(State.Accepting) .OnEntry(() => _Logger.LogDebug("Connection: {ConnectionState}", "Client won't do MSDP - do nothing")); - RegisterInitialWilling(WillingMSDPAsync); + RegisterInitialWilling(async () => await WillingMSDPAsync()); } else { @@ -57,7 +57,7 @@ private StateMachine SetupMSDPNegotiation(StateMachine await OnWillMSDPAsync()); tsm.Configure(State.WontMSDP) .SubstateOf(State.Accepting) @@ -100,7 +100,7 @@ private StateMachine SetupMSDPNegotiation(StateMachine /// Announce we do MSDP negotiation to the client. /// - private async Task WillingMSDPAsync() + private async ValueTask WillingMSDPAsync() { _Logger.LogDebug("Connection: {ConnectionState}", "Announcing willingness to MSDP!"); await CallbackNegotiationAsync([(byte)Trigger.IAC, (byte)Trigger.WILL, (byte)Trigger.MSDP]); @@ -109,16 +109,16 @@ private async Task WillingMSDPAsync() /// /// Announce the MSDP we support to the client after getting a Do. /// - private Task OnDoMSDPAsync(StateMachine.Transition _) + private ValueTask OnDoMSDPAsync(StateMachine.Transition _) { _Logger.LogDebug("Connection: {ConnectionState}", "Client will do MSDP output"); - return Task.CompletedTask; + return ValueTask.CompletedTask; } /// /// Announce we do MSDP negotiation to the server. /// - private async Task OnWillMSDPAsync() + private async ValueTask OnWillMSDPAsync() { _Logger.LogDebug("Connection: {ConnectionState}", "Announcing willingness to MSDP!"); await CallbackNegotiationAsync([(byte)Trigger.IAC, (byte)Trigger.DO, (byte)Trigger.MSDP]); diff --git a/TelnetNegotiationCore/Interpreters/TelnetMSSPInterpreter.cs b/TelnetNegotiationCore/Interpreters/TelnetMSSPInterpreter.cs index ebcc021..ca45655 100644 --- a/TelnetNegotiationCore/Interpreters/TelnetMSSPInterpreter.cs +++ b/TelnetNegotiationCore/Interpreters/TelnetMSSPInterpreter.cs @@ -20,7 +20,7 @@ public partial class TelnetInterpreter private List _currentMSSPValue; private List> _currentMSSPVariableList; - public Func SignalOnMSSPAsync { get; init; } + public Func SignalOnMSSPAsync { get; init; } private IImmutableDictionary MSSPAttributeMembers = typeof(MSSPConfig) .GetMembers() @@ -45,13 +45,13 @@ private StateMachine SetupMSSPNegotiation(StateMachine await OnDoMSSPAsync(x)); tsm.Configure(State.DontMSSP) .SubstateOf(State.Accepting) .OnEntry(() => _Logger.LogDebug("Connection: {ConnectionState}", "Client won't do MSSP - do nothing")); - RegisterInitialWilling(WillingMSSPAsync); + RegisterInitialWilling(async () => await WillingMSSPAsync()); } else { @@ -63,7 +63,7 @@ private StateMachine SetupMSSPNegotiation(StateMachine await OnWillMSSPAsync()); tsm.Configure(State.WontMSSP) .SubstateOf(State.Accepting) @@ -101,7 +101,7 @@ private StateMachine SetupMSSPNegotiation(StateMachine await ReadMSSPValues()); TriggerHelper.ForAllTriggersExcept([Trigger.MSSP_VAL, Trigger.MSSP_VAR, Trigger.IAC], t => tsm.Configure(State.EvaluatingMSSPVal).OnEntryFrom(ParameterizedTrigger(t), CaptureMSSPValue)); TriggerHelper.ForAllTriggersExcept([Trigger.MSSP_VAL, Trigger.MSSP_VAR, Trigger.IAC], t => tsm.Configure(State.EvaluatingMSSPVar).OnEntryFrom(ParameterizedTrigger(t), CaptureMSSPVariable)); @@ -131,7 +131,7 @@ private void RegisterMSSPVar() _currentMSSPVariable = []; } - private async Task ReadMSSPValues() + private async ValueTask ReadMSSPValues() { RegisterMSSPVal(); RegisterMSSPVar(); @@ -145,7 +145,7 @@ private async Task ReadMSSPValues() StoreClientMSSPDetails(group.Key, group.Select(x => CurrentEncoding.GetString([.. x.Second]))); } - await (SignalOnMSSPAsync?.Invoke(_msspConfig()) ?? Task.CompletedTask); + await (SignalOnMSSPAsync?.Invoke(_msspConfig()) ?? ValueTask.CompletedTask); } /// @@ -218,7 +218,7 @@ private void CaptureMSSPValue(OneOf b) /// /// Announce we do MSSP negotiation to the client. /// - private async Task WillingMSSPAsync() + private async ValueTask WillingMSSPAsync() { _Logger.LogDebug("Connection: {ConnectionState}", "Announcing willingness to MSSP!"); await CallbackNegotiationAsync([(byte)Trigger.IAC, (byte)Trigger.WILL, (byte)Trigger.MSSP]); @@ -227,7 +227,7 @@ private async Task WillingMSSPAsync() /// /// Announce the MSSP we support to the client after getting a Do. /// - private async Task OnDoMSSPAsync(StateMachine.Transition _) + private async ValueTask OnDoMSSPAsync(StateMachine.Transition _) { _Logger.LogDebug("Connection: {ConnectionState}", "Writing MSSP output"); await CallbackNegotiationAsync(ReportMSSP(_msspConfig())); @@ -236,7 +236,7 @@ private async Task OnDoMSSPAsync(StateMachine.Transition _) /// /// Announce we do MSSP negotiation to the server. /// - private async Task OnWillMSSPAsync() + private async ValueTask OnWillMSSPAsync() { _Logger.LogDebug("Connection: {ConnectionState}", "Announcing willingness to MSSP!"); await CallbackNegotiationAsync([(byte)Trigger.IAC, (byte)Trigger.DO, (byte)Trigger.MSSP]); diff --git a/TelnetNegotiationCore/Interpreters/TelnetNAWSInterpreter.cs b/TelnetNegotiationCore/Interpreters/TelnetNAWSInterpreter.cs index c259336..0f3f5fe 100644 --- a/TelnetNegotiationCore/Interpreters/TelnetNAWSInterpreter.cs +++ b/TelnetNegotiationCore/Interpreters/TelnetNAWSInterpreter.cs @@ -45,7 +45,7 @@ public partial class TelnetInterpreter /// /// NAWS Callback function to alert server of Width & Height negotiation /// - public Func SignalOnNAWSAsync { get; init; } + public Func SignalOnNAWSAsync { get; init; } /// /// This exists to avoid an infinite loop with badly conforming clients. @@ -82,7 +82,7 @@ private StateMachine SetupNAWS(StateMachine tsm) tsm.Configure(State.DoNAWS) .SubstateOf(State.Accepting) - .OnEntryAsync(ServerWontNAWSAsync); + .OnEntryAsync(async () => await ServerWontNAWSAsync()); } if (Mode == TelnetMode.Client) @@ -98,7 +98,7 @@ private StateMachine SetupNAWS(StateMachine tsm) tsm.Configure(State.WillDoNAWS) .SubstateOf(State.Accepting) - .OnEntryAsync(RequestNAWSAsync); + .OnEntryAsync(async x => await RequestNAWSAsync(x)); tsm.Configure(State.WontDoNAWS) .SubstateOf(State.Accepting) @@ -125,16 +125,16 @@ private StateMachine SetupNAWS(StateMachine tsm) tsm.Configure(State.CompletingNAWS) .SubstateOf(State.EndSubNegotiation) - .OnEntryAsync(CompleteNAWSAsync); + .OnEntryAsync(async x => await CompleteNAWSAsync(x)); RegisterInitialWilling(async () => await RequestNAWSAsync(null)); return tsm; } - public async Task SendNAWS(short width, short height) + public async ValueTask SendNAWS(short width, short height) { - if(!_WillingToDoNAWS) await Task.CompletedTask; + if(!_WillingToDoNAWS) await ValueTask.CompletedTask; await CallbackNegotiationAsync([(byte)Trigger.IAC, (byte)Trigger.SB, (byte)Trigger.NAWS, .. BitConverter.GetBytes(width), .. BitConverter.GetBytes(height), @@ -144,7 +144,7 @@ .. BitConverter.GetBytes(width), .. BitConverter.GetBytes(height), /// /// Request NAWS from a client /// - public async Task RequestNAWSAsync(StateMachine.Transition _) + public async ValueTask RequestNAWSAsync(StateMachine.Transition _) { if (!_WillingToDoNAWS) { @@ -176,7 +176,7 @@ private void GetNAWS(StateMachine.Transition _) _nawsIndex = 0; } - private async Task ServerWontNAWSAsync() + private async ValueTask ServerWontNAWSAsync() { _Logger.LogDebug("Connection: {ConnectionState}", "Announcing refusing to send NAWS, this is a Server!"); await CallbackNegotiationAsync([(byte)Trigger.IAC, (byte)Trigger.WONT, (byte)Trigger.NAWS]); @@ -186,7 +186,7 @@ private async Task ServerWontNAWSAsync() /// Read the NAWS state values and finalize it into width and height values. /// /// Ignored - private async Task CompleteNAWSAsync(StateMachine.Transition _) + private async ValueTask CompleteNAWSAsync(StateMachine.Transition _) { byte[] width = [_nawsByteState[0], _nawsByteState[1]]; byte[] height = [_nawsByteState[2], _nawsByteState[3]]; @@ -201,6 +201,6 @@ private async Task CompleteNAWSAsync(StateMachine.Transition _) ClientHeight = BitConverter.ToInt16(height); _Logger.LogDebug("Negotiated for: {clientWidth} width and {clientHeight} height", ClientWidth, ClientHeight); - await (SignalOnNAWSAsync?.Invoke(ClientHeight, ClientWidth) ?? Task.CompletedTask); + await (SignalOnNAWSAsync?.Invoke(ClientHeight, ClientWidth) ?? ValueTask.CompletedTask); } } diff --git a/TelnetNegotiationCore/Interpreters/TelnetStandardInterpreter.cs b/TelnetNegotiationCore/Interpreters/TelnetStandardInterpreter.cs index fc17395..cddcabe 100644 --- a/TelnetNegotiationCore/Interpreters/TelnetStandardInterpreter.cs +++ b/TelnetNegotiationCore/Interpreters/TelnetStandardInterpreter.cs @@ -20,7 +20,7 @@ public partial class TelnetInterpreter /// /// A list of functions to call at the start. /// - private readonly List> _InitialCall; + private readonly List> _InitialCall; /// /// The current Encoding used for interpreting incoming non-negotiation text, and what we should send on outbound. @@ -30,7 +30,7 @@ public partial class TelnetInterpreter /// /// Telnet state machine /// - public StateMachine TelnetStateMachine { get; private set; } + public StateMachine TelnetStateMachine { get; } /// /// A cache of parameterized triggers. @@ -72,17 +72,17 @@ public enum TelnetMode /// /// Callback to run on a submission (linefeed) /// - public Func CallbackOnSubmitAsync { get; init; } + public Func CallbackOnSubmitAsync { get; init; } /// /// Callback to the output stream directly for negotiation. /// - public Func CallbackNegotiationAsync { get; init; } + public Func CallbackNegotiationAsync { get; init; } /// /// Callback per byte. /// - public Func CallbackOnByteAsync { get; init; } + public Func CallbackOnByteAsync { get; init; } /// /// Constructor, sets up for standard Telnet protocol with NAWS and Character Set support. @@ -90,6 +90,7 @@ public enum TelnetMode /// /// After calling this constructor, one should subscribe to the Triggers, register a Stream, and then run Process() /// + /// Server or Client mode /// A Serilog Logger. If null, we will use the default one with a Context of the Telnet Interpreter. public TelnetInterpreter(TelnetMode mode, ILogger logger) { @@ -118,7 +119,7 @@ public TelnetInterpreter(TelnetMode mode, ILogger logger) if (logger.IsEnabled(LogLevel.Trace)) { - TelnetStateMachine.OnTransitioned((transition) => _Logger.LogTrace("Telnet StateMachine: {Source} --[{Trigger}({TriggerByte})]--> {Destination}", + TelnetStateMachine.OnTransitioned(transition => _Logger.LogTrace("Telnet StateMachine: {Source} --[{Trigger}({TriggerByte})]--> {Destination}", transition.Source, transition.Trigger, transition.Parameters[0], transition.Destination)); } } @@ -127,7 +128,7 @@ public TelnetInterpreter(TelnetMode mode, ILogger logger) /// Validates the configuration, then sets up the initial calls for negotiation. /// /// The Telnet Interpreter - public async Task BuildAsync() + public async ValueTask BuildAsync() { Validate(); @@ -153,7 +154,8 @@ private StateMachine SetupStandardProtocol(StateMachine tsm.Configure(State.ReadingCharacters).OnEntryFromAsync(ParameterizedTrigger(t), WriteToBufferAndAdvanceAsync)); + TriggerHelper.ForAllTriggers(t => tsm.Configure(State.ReadingCharacters) + .OnEntryFromAsync(ParameterizedTrigger(t), async x => await WriteToBufferAndAdvanceAsync(x))); // We've gotten a newline. We interpret this as time to act and send a signal back. tsm.Configure(State.Act) @@ -204,13 +206,13 @@ private StateMachine SetupStandardProtocol(StateMachine /// A useful byte for the Client/Server - private async Task WriteToBufferAndAdvanceAsync(OneOf b) + private async ValueTask WriteToBufferAndAdvanceAsync(OneOf b) { if (b.AsT0 == (byte)Trigger.CARRIAGERETURN) return; _Logger.LogTrace("Debug: Writing into buffer: {Byte}", b.AsT0); _buffer[_bufferPosition] = b.AsT0; _bufferPosition++; - await (CallbackOnByteAsync?.Invoke(b.AsT0, CurrentEncoding) ?? Task.CompletedTask); + await (CallbackOnByteAsync?.Invoke(b.AsT0, CurrentEncoding) ?? ValueTask.CompletedTask); } /// @@ -218,7 +220,7 @@ private async Task WriteToBufferAndAdvanceAsync(OneOf b) /// private void WriteToOutput() { - byte[] cp = new byte[_bufferPosition]; + var cp = new byte[_bufferPosition]; _buffer.AsSpan()[.._bufferPosition].CopyTo(cp); _bufferPosition = 0; CallbackOnSubmitAsync.Invoke(cp, CurrentEncoding, this); @@ -245,7 +247,7 @@ private TelnetInterpreter Validate() return this; } - private void RegisterInitialWilling(Func fun) + private void RegisterInitialWilling(Func fun) { _InitialCall.Add(fun); } @@ -255,8 +257,8 @@ private void RegisterInitialWilling(Func fun) /// TODO: Cache the value of IsDefined, or get a way to compile this down to a faster call that doesn't require reflection each time. /// /// An integer representation of a byte. - /// Task - public async Task InterpretAsync(byte bt) + /// ValueTask + public async ValueTask InterpretAsync(byte bt) { if (Enum.IsDefined(typeof(Trigger), (short)bt)) { @@ -273,9 +275,9 @@ public async Task InterpretAsync(byte bt) /// Interprets the next byte in an asynchronous way. /// TODO: Cache the value of IsDefined, or get a way to compile this down to a faster call that doesn't require reflection each time. /// - /// An integer representation of a byte. - /// Task - public async Task InterpretByteArrayAsync(ImmutableArray byteArray) + /// An integer representation of a byte. + /// ValueTask + public async ValueTask InterpretByteArrayAsync(ImmutableArray byteArray) { foreach (var b in byteArray) { diff --git a/TelnetNegotiationCore/Interpreters/TelnetSuppressGAInterpreter.cs b/TelnetNegotiationCore/Interpreters/TelnetSuppressGAInterpreter.cs index 34f1dd7..e9a3d5c 100644 --- a/TelnetNegotiationCore/Interpreters/TelnetSuppressGAInterpreter.cs +++ b/TelnetNegotiationCore/Interpreters/TelnetSuppressGAInterpreter.cs @@ -26,13 +26,13 @@ private StateMachine SetupSuppressGANegotiation(StateMachine await OnDoSuppressGAAsync(x)); tsm.Configure(State.DontSUPPRESSGOAHEAD) .SubstateOf(State.Accepting) - .OnEntryAsync(OnDontSuppressGAAsync); + .OnEntryAsync(async () => await OnDontSuppressGAAsync()); - RegisterInitialWilling(WillingSuppressGAAsync); + RegisterInitialWilling(async () => await WillingSuppressGAAsync()); } else { @@ -44,41 +44,41 @@ private StateMachine SetupSuppressGANegotiation(StateMachine await WontSuppressGAAsync()); tsm.Configure(State.WillSUPPRESSGOAHEAD) .SubstateOf(State.Accepting) - .OnEntryAsync(OnWillSuppressGAAsync); + .OnEntryAsync(async x => await OnWillSuppressGAAsync(x)); } return tsm; } - private async Task OnSUPPRESSGOAHEADPrompt() + private async ValueTask OnSUPPRESSGOAHEADPrompt() { _Logger.LogDebug("Connection: {ConnectionState}", "Server is prompting SUPPRESSGOAHEAD"); - await (SignalOnPromptingAsync?.Invoke() ?? Task.CompletedTask); + await (SignalOnPromptingAsync?.Invoke() ?? ValueTask.CompletedTask); } - private async Task OnDontSuppressGAAsync() + private async ValueTask OnDontSuppressGAAsync() { _Logger.LogDebug("Connection: {ConnectionState}", "Client won't do SUPPRESSGOAHEAD - do nothing"); _doGA = true; - await Task.CompletedTask; + await ValueTask.CompletedTask; } - private async Task WontSuppressGAAsync() + private async ValueTask WontSuppressGAAsync() { _Logger.LogDebug("Connection: {ConnectionState}", "Server won't do SUPPRESSGOAHEAD - do nothing"); _doGA = true; - await Task.CompletedTask; + await ValueTask.CompletedTask; } /// /// Announce we do SUPPRESSGOAHEAD negotiation to the client. /// - private async Task WillingSuppressGAAsync() + private async ValueTask WillingSuppressGAAsync() { _Logger.LogDebug("Connection: {ConnectionState}", "Announcing willingness to SUPPRESSGOAHEAD!"); await CallbackNegotiationAsync([(byte)Trigger.IAC, (byte)Trigger.WILL, (byte)Trigger.SUPPRESSGOAHEAD]); @@ -87,17 +87,17 @@ private async Task WillingSuppressGAAsync() /// /// Store that we are now in SUPPRESSGOAHEAD mode. /// - private Task OnDoSuppressGAAsync(StateMachine.Transition _) + private ValueTask OnDoSuppressGAAsync(StateMachine.Transition _) { _Logger.LogDebug("Connection: {ConnectionState}", "Client supports End of Record."); - _doGA =false; - return Task.CompletedTask; + _doGA = false; + return ValueTask.CompletedTask; } /// /// Store that we are now in SUPPRESSGOAHEAD mode. /// - private async Task OnWillSuppressGAAsync(StateMachine.Transition _) + private async ValueTask OnWillSuppressGAAsync(StateMachine.Transition _) { _Logger.LogDebug("Connection: {ConnectionState}", "Server supports End of Record."); _doGA = false; diff --git a/TelnetNegotiationCore/Interpreters/TelnetTerminalTypeInterpreter.cs b/TelnetNegotiationCore/Interpreters/TelnetTerminalTypeInterpreter.cs index cd6106c..aa2c895 100644 --- a/TelnetNegotiationCore/Interpreters/TelnetTerminalTypeInterpreter.cs +++ b/TelnetNegotiationCore/Interpreters/TelnetTerminalTypeInterpreter.cs @@ -104,7 +104,7 @@ private StateMachine SetupTelnetTerminalTypeAsClient(StateMachin tsm.Configure(State.DoTType) .SubstateOf(State.Accepting) - .OnEntryAsync(WillDoTerminalTypeAsync); + .OnEntryAsync(async () => await WillDoTerminalTypeAsync()); tsm.Configure(State.DontTType) .SubstateOf(State.Accepting) @@ -121,7 +121,7 @@ private StateMachine SetupTelnetTerminalTypeAsClient(StateMachin .OnEntry(GetTerminalType); tsm.Configure(State.CompletingTerminalType) - .OnEntryAsync(ReportNextAvailableTerminalTypeAsync) + .OnEntryAsync(async () => await ReportNextAvailableTerminalTypeAsync()) .Permit(Trigger.SE, State.Accepting); return tsm; @@ -138,7 +138,7 @@ private StateMachine SetupTelnetTerminalTypeAsServer(StateMachin { tsm.Configure(State.WillDoTType) .SubstateOf(State.Accepting) - .OnEntryAsync(RequestTerminalTypeAsync); + .OnEntryAsync(async () => await RequestTerminalTypeAsync()); tsm.Configure(State.WontDoTType) .SubstateOf(State.Accepting) @@ -166,10 +166,10 @@ private StateMachine SetupTelnetTerminalTypeAsServer(StateMachin .Permit(Trigger.SE, State.CompletingTerminalType); tsm.Configure(State.CompletingTerminalType) - .OnEntryAsync(CompleteTerminalTypeAsServerAsync) + .OnEntryAsync(async () => await CompleteTerminalTypeAsServerAsync()) .SubstateOf(State.Accepting); - RegisterInitialWilling(SendDoTerminalTypeAsync); + RegisterInitialWilling(async () => await SendDoTerminalTypeAsync()); return tsm; } @@ -199,7 +199,7 @@ private void CaptureTerminalType(OneOf b) /// Read the Terminal Type state values and finalize it into the Terminal Types List. /// Then, if we have not seen this Terminal Type before, request another! /// - private async Task CompleteTerminalTypeAsServerAsync() + private async ValueTask CompleteTerminalTypeAsServerAsync() { var TType = ascii.GetString(_ttypeByteState, 0, _ttypeIndex); if (TerminalTypes.Contains(TType)) @@ -229,7 +229,7 @@ private async Task CompleteTerminalTypeAsServerAsync() /// Tell the Client that the Server is willing to listen to Terminal Type. /// /// - private async Task WillDoTerminalTypeAsync() + private async ValueTask WillDoTerminalTypeAsync() { _Logger.LogDebug("Connection: {ConnectionState}", "Telling the other party, Willing to do Terminal Type."); await CallbackNegotiationAsync([(byte)Trigger.IAC, (byte)Trigger.WILL, (byte)Trigger.TTYPE]); @@ -238,7 +238,7 @@ private async Task WillDoTerminalTypeAsync() /// /// Tell the Client to do Terminal Type. This should not happen as a Server. /// - private async Task SendDoTerminalTypeAsync() + private async ValueTask SendDoTerminalTypeAsync() { _Logger.LogDebug("Connection: {ConnectionState}", "Telling the other party, to do Terminal Type."); await CallbackNegotiationAsync([(byte)Trigger.IAC, (byte)Trigger.DO, (byte)Trigger.TTYPE]); @@ -247,13 +247,13 @@ private async Task SendDoTerminalTypeAsync() /// /// Request Terminal Type from Client. This flips to the next one. /// - public async Task RequestTerminalTypeAsync() + public async ValueTask RequestTerminalTypeAsync() { _Logger.LogDebug("Connection: {ConnectionState}", "Telling the client, to send the next Terminal Type."); await CallbackNegotiationAsync([(byte)Trigger.IAC, (byte)Trigger.SB, (byte)Trigger.TTYPE, (byte)Trigger.SEND, (byte)Trigger.IAC, (byte)Trigger.SE]); } - private async Task ReportNextAvailableTerminalTypeAsync() + private async ValueTask ReportNextAvailableTerminalTypeAsync() { _CurrentTerminalType = (_CurrentTerminalType + 1) % (TerminalTypes.Count + 1); _Logger.LogDebug("Connection: {ConnectionState}", "Reporting the next Terminal Type to the server."); diff --git a/TelnetNegotiationCore/Models/MSSPConfig.cs b/TelnetNegotiationCore/Models/MSSPConfig.cs index fc3f0a7..2b5a9fd 100644 --- a/TelnetNegotiationCore/Models/MSSPConfig.cs +++ b/TelnetNegotiationCore/Models/MSSPConfig.cs @@ -13,7 +13,7 @@ public class NameAttribute(string name) : Attribute } /// -/// Indicates whether or not it's in the official MSSP definition. +/// Indicates whether it's in the official MSSP definition. /// [AttributeUsage(AttributeTargets.Property, Inherited = false)] public class OfficialAttribute(bool official) : Attribute diff --git a/TelnetNegotiationCore/Models/Trigger.cs b/TelnetNegotiationCore/Models/Trigger.cs index 6d9a32c..9cc277c 100644 --- a/TelnetNegotiationCore/Models/Trigger.cs +++ b/TelnetNegotiationCore/Models/Trigger.cs @@ -23,7 +23,7 @@ public class ParameterizedTriggers public StateMachine.TriggerWithParameters> ParameterizedTrigger(StateMachine stm, Trigger t) { - if (_cache.TryGetValue(t, out StateMachine.TriggerWithParameters> value)) + if (_cache.TryGetValue(t, out var value)) { return value; } diff --git a/TelnetNegotiationCore/TelnetNegotiationCore.csproj b/TelnetNegotiationCore/TelnetNegotiationCore.csproj index 222fd10..b153cea 100644 --- a/TelnetNegotiationCore/TelnetNegotiationCore.csproj +++ b/TelnetNegotiationCore/TelnetNegotiationCore.csproj @@ -3,7 +3,7 @@ net9.0 latest - 1.0.7 + 1.0.8 True Telnet Negotiation Core $(AssemblyName) @@ -16,6 +16,7 @@ git telnet LICENSE + https://github.com/HarryCordewener/TelnetNegotiationCore/blob/main/CHANGELOG.md Copyright © TelnetNegotiationCore Contributors 2024-$([System.DateTime]::Now.ToString(yyyy))