using System;
using System.Collections.Generic;
using Best.HTTP.Shared.PlatformSupport.Memory;
using Best.MQTT.Packets;
using Best.MQTT.Packets.Utils;
namespace Best.MQTT
{
///
/// https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901106
///
public readonly struct ApplicationMessage
{
///
/// https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901108
///
internal readonly UInt16 PacketId;
///
/// https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901117
///
internal readonly UInt32 SubscriptionId;
///
/// Set to true if it's not the first occasion the broker sent this application message.
///
///
public readonly bool IsDuplicate;
///
/// QoS this application message sent with.
///
///
public readonly QoSLevels QoS;
///
/// Set to true if this is a retained application message.
///
///
public readonly bool Retain;
///
/// The topic's name this application message is publish to.
///
///
public readonly string Topic;
///
/// Payload type (binary or text).
///
///
public readonly PayloadTypes PayloadFormat;
///
/// Expiry interval of the application message.
///
///
public readonly TimeSpan ExpiryInterval;
///
/// Topic alias index the broker used.
///
///
internal readonly UInt16 TopicAlias;
///
/// Topic name where the publisher waiting for a response to this application message.
///
///
public readonly string ResponseTopic;
///
/// Arbitrary data sent with the application message.
///
///
public readonly BufferSegment CorrelationData;
///
/// Key-value pairs sent with the application message.
///
///
public readonly List> UserProperties;
///
/// Arbitrary value set by the publisher.
///
///
public readonly string ContentType;
///
/// Payload of the application message.
///
///
public readonly BufferSegment Payload;
internal ApplicationMessage(UInt32 sId, Packet packet)
{
// https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901117
// Multiple Subscription Identifiers will be included if the publication is the result of a match to more than one subscription, in this case their order is not significant.
this.SubscriptionId = sId;
this.IsDuplicate = packet.Flags[3];
this.QoS = (QoSLevels)packet.Flags.Range(2, 1);
this.Retain = packet.Flags[0];
this.Topic = packet.VariableHeaderFields[0].UTF8String.Key;
// The Packet Identifier field is only present in PUBLISH packets where the QoS level is 1 or 2.
this.PacketId = this.QoS >= QoSLevels.AtLeastOnceDelivery ? (UInt16)packet.VariableHeaderFields[1].Integer : (UInt16)0;
Properties properties = packet.VariableHeaderFields.Properties;
this.PayloadFormat = properties.TryFindData(PacketProperties.PayloadFormatIndicator, DataTypes.Byte, out var data) ? (PayloadTypes)data.Integer : PayloadTypes.Bytes;
this.ExpiryInterval = properties.TryFindData(PacketProperties.MessageExpiryInterval, DataTypes.FourByteInteger, out data) ? TimeSpan.FromSeconds(data.Integer) : TimeSpan.MaxValue;
this.TopicAlias = properties.TryFindData(PacketProperties.TopicAlias, DataTypes.TwoByteInteger, out data) ? (UInt16)data.Integer : (UInt16)0;
this.ResponseTopic = properties.TryFindData(PacketProperties.ResponseTopic, DataTypes.UTF8String, out data) ? data.UTF8String.Key : null;
this.CorrelationData = properties.TryFindData(PacketProperties.CorrelationData, DataTypes.Binary, out data) ? data.Binary : BufferSegment.Empty;
this.UserProperties = properties.ConvertAll>(PacketProperties.UserProperty, kvp_data => kvp_data.UTF8String);
this.ContentType = properties.TryFindData(PacketProperties.ContentType, DataTypes.UTF8String, out data) ? data.UTF8String.Key : null;
this.Payload = packet.Payload.Count > 0 ? packet.Payload[0].Binary : BufferSegment.Empty;
}
}
}