From 807db7f365612386710da3d10c2f3a43747b46b8 Mon Sep 17 00:00:00 2001 From: Ryzhehvost Date: Wed, 30 Jun 2021 13:45:58 +0300 Subject: [PATCH] Implement splitting of steam messages on newlines (#2348) * implement split on newlines * replace test of splitting on newlines * sugar-sugar syntax * Revert "sugar-sugar syntax" This reverts commit ee9b558faf4c94331d560bb5dd43daefad40dd33. * add test to confirm that paragraph character size is less or equal to continuation character size --- ArchiSteamFarm.Tests/SteamChatMessage.cs | 11 ++++++---- .../Steam/Integration/SteamChatMessage.cs | 22 +++++++++++++++++-- 2 files changed, 27 insertions(+), 6 deletions(-) diff --git a/ArchiSteamFarm.Tests/SteamChatMessage.cs b/ArchiSteamFarm.Tests/SteamChatMessage.cs index 3503cb978..8f7735a45 100644 --- a/ArchiSteamFarm.Tests/SteamChatMessage.cs +++ b/ArchiSteamFarm.Tests/SteamChatMessage.cs @@ -50,6 +50,9 @@ namespace ArchiSteamFarm.Tests { [TestMethod] public void ContinuationCharacterSizeIsProperlyCalculated() => Assert.AreEqual(ContinuationCharacterBytes, Encoding.UTF8.GetByteCount(ContinuationCharacter.ToString())); + [TestMethod] + public void ParagraphCharacterSizeIsLessOrEqualToContinuationCharacterSize() => Assert.IsTrue(ContinuationCharacterBytes >= Encoding.UTF8.GetByteCount(ParagraphCharacter.ToString())); + [TestMethod] public async Task DoesntSkipEmptyNewlines() { string message = "asdf" + Environment.NewLine + Environment.NewLine + "asdf"; @@ -277,7 +280,7 @@ namespace ArchiSteamFarm.Tests { [DataRow(false)] [DataRow(true)] [DataTestMethod] - public async Task SplitsOnNewlinesWithoutContinuationCharacter(bool isAccountLimited) { + public async Task SplitsOnNewlinesWithParagraphCharacter(bool isAccountLimited) { int maxMessageBytes = isAccountLimited ? MaxMessageBytesForLimitedAccounts : MaxMessageBytesForUnlimitedAccounts; StringBuilder newlinePartBuilder = new(); @@ -299,9 +302,9 @@ namespace ArchiSteamFarm.Tests { Assert.AreEqual(4, output.Count); - Assert.AreEqual(newlinePart, output[0]); - Assert.AreEqual(newlinePart, output[1]); - Assert.AreEqual(newlinePart, output[2]); + Assert.AreEqual(newlinePart + ParagraphCharacter, output[0]); + Assert.AreEqual(newlinePart + ParagraphCharacter, output[1]); + Assert.AreEqual(newlinePart + ParagraphCharacter, output[2]); Assert.AreEqual(newlinePart, output[3]); } diff --git a/ArchiSteamFarm/Steam/Integration/SteamChatMessage.cs b/ArchiSteamFarm/Steam/Integration/SteamChatMessage.cs index be6b65527..54a900984 100644 --- a/ArchiSteamFarm/Steam/Integration/SteamChatMessage.cs +++ b/ArchiSteamFarm/Steam/Integration/SteamChatMessage.cs @@ -33,6 +33,7 @@ namespace ArchiSteamFarm.Steam.Integration { internal static class SteamChatMessage { internal const char ContinuationCharacter = '…'; // A character used for indicating that the next newline part is a continuation of the previous line internal const byte ContinuationCharacterBytes = 3; // The continuation character specified above uses 3 bytes in UTF-8 + internal const char ParagraphCharacter = '¶'; // A character used for indicating that this is not the last part of message (2 bytes, so it fits in ContinuationCharacterBytes) internal const ushort MaxMessageBytesForLimitedAccounts = 1945; // This is a limitation enforced by Steam internal const ushort MaxMessageBytesForUnlimitedAccounts = 6340; // This is a limitation enforced by Steam internal const ushort MaxMessagePrefixBytes = MaxMessageBytesForLimitedAccounts - ReservedContinuationMessageBytes - ReservedEscapeMessageBytes; // Simplified calculation, nobody should be using prefixes even close to that anyway @@ -86,6 +87,10 @@ namespace ArchiSteamFarm.Steam.Integration { // Check if we reached the limit for one message if (messagePartBytes + NewlineWeight + ReservedEscapeMessageBytes > maxMessageBytes) { + if (stringReader.Peek() != -1) { + messagePart.Append(ParagraphCharacter); + } + yield return messagePart.ToString(); messagePartBytes = prefixBytes; @@ -101,8 +106,17 @@ namespace ArchiSteamFarm.Steam.Integration { for (int lineBytesRead = 0; lineBytesRead < lineBytes.Length;) { if (messagePart.Length > prefixLength) { - messagePartBytes += NewlineWeight; - messagePart.AppendLine(); + if (messagePartBytes + NewlineWeight + lineBytes.Length > maxMessageBytes) { + messagePart.Append(ParagraphCharacter); + yield return messagePart.ToString(); + + messagePartBytes = prefixBytes; + messagePart.Clear(); + messagePart.Append(steamMessagePrefix); + } else { + messagePartBytes += NewlineWeight; + messagePart.AppendLine(); + } } int bytesToTake = Math.Min(maxMessageBytes - messagePartBytes, lineBytes.Length - lineBytesRead); @@ -152,6 +166,10 @@ namespace ArchiSteamFarm.Steam.Integration { continue; } + if (stringReader.Peek() != -1 && messagePart[messagePart.Length-1] != ContinuationCharacter) { + messagePart.Append(ParagraphCharacter); + } + yield return messagePart.ToString(); messagePartBytes = prefixBytes;