Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
128 changes: 128 additions & 0 deletions source/Messages/StompBinaryMessageSerializer.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Net.Http;
using System.Runtime.CompilerServices;
using System.Text;
using Netina.Stomp.Client.Utils;
using System.Linq;

namespace Netina.Stomp.Client.Messages
{
public class StompBinaryMessageSerializer
{
public byte[] Serialize(StompMessage message)
{
var resultBuffer = new List<byte>();
resultBuffer.AddRange(Encoding.UTF8.GetBytes($"{message.Command}\n"));

if (message.Headers?.Count > 0)
{
foreach (var messageHeader in message.Headers)
{
resultBuffer.AddRange(Encoding.UTF8.GetBytes($"{messageHeader.Key}:{messageHeader.Value}\n"));
}
}

resultBuffer.Add((byte)'\n');
resultBuffer.AddRange(message.BinaryBody);
resultBuffer.Add((byte)'\0');

return resultBuffer.ToArray();
}

public StompMessage Deserialize(byte[] message)
{
var headerBuffer = new List<byte>();
var bodyBuffer = new List<byte>();
byte previousByte = 0;
var isBodyStarted = false;

// Building header and body buffers
foreach (var currentByte in message)
{
if (!isBodyStarted && currentByte == previousByte && previousByte == (byte)'\n')
{
isBodyStarted = true;
}
else
{
if (isBodyStarted)
{
bodyBuffer.Add(currentByte);
}
else
{
headerBuffer.Add(currentByte);
}
}

previousByte = currentByte;
}

// Doing a cleanup of a body buffer according to a frame description:
// "The body is then followed by the NULL octet. The NULL octet can be optionally followed by multiple EOLs"
var ignoredChars = new byte[] { (byte)'\n', (byte)'\r' };
var messageEnd = (byte)'\0';
for (var index = bodyBuffer.Count - 1; index >= 0; index--)
{
var currentByte = bodyBuffer[index];
if (ignoredChars.Contains(currentByte))
{
bodyBuffer.RemoveAt(index);
continue;
}

if (currentByte == messageEnd)
{
bodyBuffer.RemoveAt(index);
}

break;
}

var command = string.Empty;
var headers = new Dictionary<string, string>();

// Parse headers
if (headerBuffer.Count > 0)
{
var stringHeader = Encoding.UTF8.GetString(headerBuffer.ToArray());

using (var reader = new StringReader(stringHeader))
{
command = reader.ReadLine();
var header = reader.ReadLine();
while (!string.IsNullOrEmpty(header))
{
var separatorIndex = header.IndexOf(':');
if (separatorIndex != -1)
{
var name = header.Substring(0, separatorIndex);
var value = header.Substring(separatorIndex + 1);
headers[name] = value;
}

header = reader.ReadLine() ?? string.Empty;
}
}
}

// Check body content length is present
if (headers.TryGetValue(StompHeader.ContentLength, out var contentLength))
{
if (long.TryParse(contentLength, out var length))
{
if (length != bodyBuffer.Count)
{
throw new ApplicationException(
"STOMP: Content length header value is different then actual length of bytes received.");
}
}
}


return new StompMessage(command, bodyBuffer.ToArray(), headers);
}
}
}
28 changes: 23 additions & 5 deletions source/Messages/StompMessage.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,29 +5,47 @@ namespace Netina.Stomp.Client.Messages
public class StompMessage
{
public IDictionary<string, string> Headers { get; }
public string Body { get; }
public string TextBody { get; }
public byte[] BinaryBody { get; }
public string Command { get; }

public StompMessageBodyType BodyType { get; }

public StompMessage(string command)
: this(command, string.Empty)
{
}

public StompMessage(string command, string body)
: this(command, body, new Dictionary<string, string>())
public StompMessage(string command, string textBody)
: this(command, textBody, new Dictionary<string, string>())
{
}

public StompMessage(string command, IDictionary<string, string> headers)
: this(command, string.Empty, headers)
{

}

public StompMessage(string command, string textBody, IDictionary<string, string> headers)
{
Command = command;
TextBody = textBody;
Headers = headers;
BodyType = string.IsNullOrEmpty(textBody) ? StompMessageBodyType.Empty : StompMessageBodyType.Text;
}

public StompMessage(string command, byte[] binBody)
: this(command, binBody, new Dictionary<string, string>())
{
}

public StompMessage(string command, string body, IDictionary<string, string> headers)
public StompMessage(string command, byte[] binBody, IDictionary<string, string> headers)
{
Command = command;
Body = body;
BinaryBody = binBody;
Headers = headers;
BodyType = binBody == null || binBody.Length == 0 ? StompMessageBodyType.Empty : StompMessageBodyType.Binary;
}
}
}
9 changes: 9 additions & 0 deletions source/Messages/StompMessageBodyType.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
namespace Netina.Stomp.Client.Messages
{
public enum StompMessageBodyType
{
Text,
Binary,
Empty
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

namespace Netina.Stomp.Client.Messages
{
public class StompMessageSerializer
public class StompTextMessageSerializer
{
public string Serialize(StompMessage message)
{
Expand All @@ -21,7 +21,7 @@ public string Serialize(StompMessage message)
}

buffer.Append('\n');
buffer.Append(message.Body);
buffer.Append(message.TextBody);
buffer.Append('\0');

return buffer.ToString();
Expand Down
4 changes: 2 additions & 2 deletions source/Netina.Stomp.Client.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,8 @@ Add ACK &amp; NACK Commands</PackageReleaseNotes>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
<PackageReference Include="Websocket.Client" Version="4.4.43" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
<PackageReference Include="Websocket.Client" Version="4.6.1" />
</ItemGroup>

<ItemGroup>
Expand Down
Loading