From 59433bd461e28c317ad6623ff3d0c816bbf6eac1 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sat, 16 Dec 2023 10:06:54 -0500 Subject: [PATCH] Version 8 [NugetDeploy] - Switch to ValueTasks. - Switch to v8 MS dependencies. - Update to Stylecop beta. - Fix double data read. - Switch to records and structs where appropriate. --- Byond.TopicSender/Byond.TopicSender.csproj | 10 +++--- Byond.TopicSender/ITopicClient.cs | 12 +++---- Byond.TopicSender/SocketParameters.cs | 2 +- Byond.TopicSender/TopicClient.cs | 42 +++++++++++----------- Byond.TopicSender/TopicResponse.cs | 2 +- Byond.TopicSender/TopicResponseHeader.cs | 2 +- Byond.TopicSender/analyzers.ruleset | 6 +++- 7 files changed, 41 insertions(+), 35 deletions(-) diff --git a/Byond.TopicSender/Byond.TopicSender.csproj b/Byond.TopicSender/Byond.TopicSender.csproj index 10c9ca3..549bc6b 100644 --- a/Byond.TopicSender/Byond.TopicSender.csproj +++ b/Byond.TopicSender/Byond.TopicSender.csproj @@ -3,14 +3,14 @@ net6.0;net7.0;net8.0 true - 7.1.0 + 8.0.0 Jordan Dominion Library for asynchronously sending valid topic strings to /world/Topic() in BYOND servers. https://Cyberboss.github.io/Byond.TopicSender https://github.com/Cyberboss/Byond.TopicSender Git Copyright (c) Jordan Brown 2018 - Multi-targeted across .NET 6-8. Fixed issue with partial reads. + Fixed potential double data reads occurring. Switched to using ValueTask return values. Switched to using records ans d structs where appropriate. Updated Microsoft packages to version 8. LICENSE byond topic packet sender true @@ -36,11 +36,11 @@ - + - + - + all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/Byond.TopicSender/ITopicClient.cs b/Byond.TopicSender/ITopicClient.cs index 3e945bc..255a405 100644 --- a/Byond.TopicSender/ITopicClient.cs +++ b/Byond.TopicSender/ITopicClient.cs @@ -16,8 +16,8 @@ public interface ITopicClient /// The query string to send. /// The port of the . /// The for the operation. - /// A resulting in the returned from the server. - Task SendTopic(string destinationServer, string queryString, ushort port, CancellationToken cancellationToken = default); + /// A resulting in the returned from the server. + ValueTask SendTopic(string destinationServer, string queryString, ushort port, CancellationToken cancellationToken = default); /// /// Send a to the /world/Topic of a server at a given . @@ -26,8 +26,8 @@ public interface ITopicClient /// The query string to send. /// The port of the . /// The for the operation. - /// A resulting in the returned from the server. - Task SendTopic(IPAddress address, string queryString, ushort port, CancellationToken cancellationToken = default); + /// A resulting in the returned from the server. + ValueTask SendTopic(IPAddress address, string queryString, ushort port, CancellationToken cancellationToken = default); /// /// Send a to the /world/Topic of a server at a given . @@ -35,8 +35,8 @@ public interface ITopicClient /// The of the server. /// The query string to send. /// The for the operation. - /// A resulting in the returned from the server. - Task SendTopic(IPEndPoint endPoint, string queryString, CancellationToken cancellationToken = default); + /// A resulting in the returned from the server. + ValueTask SendTopic(IPEndPoint endPoint, string queryString, CancellationToken cancellationToken = default); /// /// Properly escapes characters for a Byond Topic() packet. Performs URL encoding. See http://www.byond.com/docs/ref/info.html#/proc/list2params. diff --git a/Byond.TopicSender/SocketParameters.cs b/Byond.TopicSender/SocketParameters.cs index d6a6c74..a016b2d 100644 --- a/Byond.TopicSender/SocketParameters.cs +++ b/Byond.TopicSender/SocketParameters.cs @@ -5,7 +5,7 @@ namespace Byond.TopicSender /// /// parameters used by the . /// - public sealed class SocketParameters + public readonly record struct SocketParameters { /// /// The timeout for the send operation. diff --git a/Byond.TopicSender/TopicClient.cs b/Byond.TopicSender/TopicClient.cs index a99ffdd..ac0806c 100644 --- a/Byond.TopicSender/TopicClient.cs +++ b/Byond.TopicSender/TopicClient.cs @@ -33,17 +33,16 @@ public sealed class TopicClient : ITopicClient /// /// The to use. /// The optional to use. - public TopicClient(SocketParameters socketParameters, ILogger? logger = null) + public TopicClient(SocketParameters socketParameters, ILogger? logger) { - this.socketParameters = socketParameters ?? throw new ArgumentNullException(nameof(socketParameters)); + this.socketParameters = socketParameters; this.logger = logger ?? new NullLogger(); } /// - public async Task SendTopic(string destinationServer, string queryString, ushort port, CancellationToken cancellationToken = default) + public async ValueTask SendTopic(string destinationServer, string queryString, ushort port, CancellationToken cancellationToken = default) { - if (destinationServer == null) - throw new ArgumentNullException(nameof(destinationServer)); + ArgumentNullException.ThrowIfNull(destinationServer); var hostEntries = await Dns.GetHostAddressesAsync(destinationServer, cancellationToken).ConfigureAwait(false); // pick the first IPV4 entry @@ -51,25 +50,24 @@ public async Task SendTopic(string destinationServer, string quer } /// - public Task SendTopic(IPAddress address, string queryString, ushort port, CancellationToken cancellationToken = default) + public ValueTask SendTopic(IPAddress address, string queryString, ushort port, CancellationToken cancellationToken = default) { - if (address == null) - throw new ArgumentNullException(nameof(address)); + ArgumentNullException.ThrowIfNull(address); + return SendTopic(new IPEndPoint(address, port), queryString, cancellationToken); } /// - public async Task SendTopic(IPEndPoint endPoint, string queryString, CancellationToken cancellationToken = default) + public async ValueTask SendTopic(IPEndPoint endPoint, string queryString, CancellationToken cancellationToken = default) { - if (endPoint == null) - throw new ArgumentNullException(nameof(endPoint)); - if (queryString == null) - throw new ArgumentNullException(nameof(queryString)); + ArgumentNullException.ThrowIfNull(endPoint); + ArgumentNullException.ThrowIfNull(queryString); using var socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); { // prepare - var needsQueryToken = queryString.Length == 0 || queryString[0] != '?'; + const char QueryToken = '?'; + var needsQueryToken = queryString.Length == 0 || queryString[0] != QueryToken; var queryStringByteLength = Encoding.UTF8.GetByteCount(queryString); @@ -119,7 +117,7 @@ struct byond_msg_topic { writer.Write((byte)0); if (needsQueryToken) - writer.Write('?'); + writer.Write(QueryToken); writer.Seek(queryStringByteLength, SeekOrigin.Current); writer.Write((byte)0); @@ -197,12 +195,16 @@ struct byond_msg_topic { throw; } - receiveOffset += read; - if (!peeking && read == 0) + if (!peeking) { - if (receiveOffset < returnedData.Length) - logger.LogDebug("Zero bytes read at offset {receiveOffset} before expected length of {expectedLength}.", receiveOffset, returnedData.Length); - break; + if (read == 0) + { + if (receiveOffset < returnedData.Length) + logger.LogDebug("Zero bytes read at offset {receiveOffset} before expected length of {expectedLength}.", receiveOffset, returnedData.Length); + break; + } + + receiveOffset += read; } if (header == null && receiveOffset >= TopicResponseHeader.HeaderLength) diff --git a/Byond.TopicSender/TopicResponse.cs b/Byond.TopicSender/TopicResponse.cs index 4e84ebc..03548c8 100644 --- a/Byond.TopicSender/TopicResponse.cs +++ b/Byond.TopicSender/TopicResponse.cs @@ -7,7 +7,7 @@ namespace Byond.TopicSender /// /// Represents a topic response from BYOND. /// - public sealed class TopicResponse : TopicResponseHeader + public sealed record TopicResponse : TopicResponseHeader { /// /// The of the header. diff --git a/Byond.TopicSender/TopicResponseHeader.cs b/Byond.TopicSender/TopicResponseHeader.cs index 3c72486..e6aa994 100644 --- a/Byond.TopicSender/TopicResponseHeader.cs +++ b/Byond.TopicSender/TopicResponseHeader.cs @@ -5,7 +5,7 @@ namespace Byond.TopicSender /// /// Represents the header data of a . /// - public class TopicResponseHeader + public record TopicResponseHeader { /// /// The of a topic response header. diff --git a/Byond.TopicSender/analyzers.ruleset b/Byond.TopicSender/analyzers.ruleset index 2699bd4..dd6e143 100644 --- a/Byond.TopicSender/analyzers.ruleset +++ b/Byond.TopicSender/analyzers.ruleset @@ -1,5 +1,5 @@  - + @@ -667,6 +667,9 @@ + + + @@ -751,6 +754,7 @@ +