85 lines
2.7 KiB
C#
85 lines
2.7 KiB
C#
namespace SuiteLink.Client.Protocol;
|
|
|
|
public static class SuiteLinkSubscriptionCodec
|
|
{
|
|
public const ushort AdviseMessageType = 0x8010;
|
|
public const ushort AdviseAckMessageType = 0x0003;
|
|
public const ushort UnadviseMessageType = 0x8004;
|
|
|
|
public static byte[] EncodeAdvise(string itemName)
|
|
{
|
|
// Convenience overload for initial bring-up scenarios.
|
|
return EncodeAdvise(0, itemName);
|
|
}
|
|
|
|
public static byte[] EncodeAdvise(uint tagId, string itemName)
|
|
{
|
|
if (string.IsNullOrWhiteSpace(itemName))
|
|
{
|
|
throw new ArgumentException("Value cannot be null or whitespace.", nameof(itemName));
|
|
}
|
|
|
|
var itemNameBytes = SuiteLinkEncoding.EncodeLengthPrefixedUtf16(itemName);
|
|
var payload = new byte[sizeof(uint) + itemNameBytes.Length];
|
|
SuiteLinkEncoding.WriteUInt32LittleEndian(payload.AsSpan(0, sizeof(uint)), tagId);
|
|
itemNameBytes.CopyTo(payload, sizeof(uint));
|
|
|
|
return SuiteLinkFrameWriter.WriteFrame(AdviseMessageType, payload);
|
|
}
|
|
|
|
public static byte[] EncodeUnadvise(uint tagId)
|
|
{
|
|
Span<byte> payload = stackalloc byte[sizeof(uint)];
|
|
SuiteLinkEncoding.WriteUInt32LittleEndian(payload, tagId);
|
|
return SuiteLinkFrameWriter.WriteFrame(UnadviseMessageType, payload);
|
|
}
|
|
|
|
public static IReadOnlyList<AdviseAck> DecodeAdviseAckMany(ReadOnlySpan<byte> bytes)
|
|
{
|
|
var frame = SuiteLinkFrameReader.ParseFrame(bytes);
|
|
if (frame.MessageType != AdviseAckMessageType)
|
|
{
|
|
throw new FormatException(
|
|
$"Unexpected advise ack message type 0x{frame.MessageType:x4}; expected 0x{AdviseAckMessageType:x4}.");
|
|
}
|
|
|
|
var payload = frame.Payload.Span;
|
|
if (payload.Length == 0)
|
|
{
|
|
return [];
|
|
}
|
|
|
|
if (payload.Length % 5 != 0)
|
|
{
|
|
throw new FormatException(
|
|
$"Unexpected advise ack payload length {payload.Length}; payload must be a multiple of 5 bytes.");
|
|
}
|
|
|
|
var itemCount = payload.Length / 5;
|
|
var items = new List<AdviseAck>(itemCount);
|
|
var offset = 0;
|
|
while (offset < payload.Length)
|
|
{
|
|
var tagId = SuiteLinkEncoding.ReadUInt32LittleEndian(payload.Slice(offset, 4));
|
|
items.Add(new AdviseAck(tagId));
|
|
offset += 5;
|
|
}
|
|
|
|
return items;
|
|
}
|
|
|
|
public static AdviseAck DecodeAdviseAck(ReadOnlySpan<byte> bytes)
|
|
{
|
|
var items = DecodeAdviseAckMany(bytes);
|
|
if (items.Count != 1)
|
|
{
|
|
throw new FormatException(
|
|
$"Expected a single advise ack item but decoded {items.Count} items.");
|
|
}
|
|
|
|
return items[0];
|
|
}
|
|
}
|
|
|
|
public readonly record struct AdviseAck(uint TagId);
|