-
Notifications
You must be signed in to change notification settings - Fork 7
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
0b441f5
commit 8794b4b
Showing
7 changed files
with
217 additions
and
16 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
namespace TurboMqtt.Core; | ||
|
||
/// <summary> | ||
/// All possible reason codes for the PubAck packet. | ||
/// </summary> | ||
public enum MqttPubAckReasonCode | ||
{ | ||
Success = 0x00, | ||
NoMatchingSubscribers = 0x10, | ||
UnspecifiedError = 0x80, | ||
ImplementationSpecificError = 0x83, | ||
NotAuthorized = 0x87, | ||
TopicNameInvalid = 0x90, | ||
PacketIdentifierInUse = 0x91, | ||
QuotaExceeded = 0x97, | ||
PayloadFormatInvalid = 0x99 | ||
} | ||
|
||
// add a static helper method that can turn a MqttPubAckReason code into a hard-coded string representation | ||
internal static class MqttPubAckHelpers | ||
{ | ||
public static string ReasonCodeToString(MqttPubAckReasonCode reasonCode) | ||
{ | ||
return reasonCode switch | ||
{ | ||
MqttPubAckReasonCode.Success => "Success", | ||
MqttPubAckReasonCode.NoMatchingSubscribers => "NoMatchingSubscribers", | ||
MqttPubAckReasonCode.UnspecifiedError => "UnspecifiedError", | ||
MqttPubAckReasonCode.ImplementationSpecificError => "ImplementationSpecificError", | ||
MqttPubAckReasonCode.NotAuthorized => "NotAuthorized", | ||
MqttPubAckReasonCode.TopicNameInvalid => "TopicNameInvalid", | ||
MqttPubAckReasonCode.PacketIdentifierInUse => "PacketIdentifierInUse", | ||
MqttPubAckReasonCode.QuotaExceeded => "QuotaExceeded", | ||
MqttPubAckReasonCode.PayloadFormatInvalid => "PayloadFormatInvalid", | ||
_ => throw new ArgumentOutOfRangeException(nameof(reasonCode), reasonCode, null) | ||
}; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
namespace TurboMqtt.Core; | ||
|
||
/// <summary> | ||
/// Subscription and packet identifiers must be greater than 0. | ||
/// </summary> | ||
public readonly struct NonZeroUInt32 | ||
{ | ||
/// <summary> | ||
/// The value of the identifier. | ||
/// </summary> | ||
public uint Value { get; } | ||
|
||
public NonZeroUInt32(uint value) | ||
{ | ||
if (value == 0) | ||
{ | ||
throw new ArgumentOutOfRangeException(nameof(value), "Value must be greater than 0."); | ||
} | ||
|
||
Value = value; | ||
} | ||
|
||
public static implicit operator uint(NonZeroUInt32 value) => value.Value; | ||
public static implicit operator NonZeroUInt32(uint value) => new(value); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
namespace TurboMqtt.Core.PacketTypes; | ||
|
||
using static MqttPubAckHelpers; | ||
|
||
/// <summary> | ||
/// Used to acknowledge the receipt of a Publish packet. | ||
/// </summary> | ||
public sealed class PublishAckPacket : MqttPacketWithId | ||
{ | ||
public override MqttPacketType PacketType => MqttPacketType.PubAck; | ||
|
||
// MQTT 5.0 Optional Properties | ||
|
||
/// <summary> | ||
/// Reason Code for the acknowledgment, available in MQTT 5.0. | ||
/// This field is optional and provides more detailed acknowledgment information. | ||
/// </summary> | ||
public MqttPubAckReasonCode ReasonCode { get; set; } | ||
|
||
/// <summary> | ||
/// User Properties, available in MQTT 5.0. | ||
/// These are key-value pairs that can be sent to provide additional information in the acknowledgment. | ||
/// </summary> | ||
public string ReasonString => ReasonCodeToString(ReasonCode); | ||
|
||
public override string ToString() | ||
{ | ||
return $"PubAck: [PacketIdentifier={PacketId}] [ReasonCode={ReasonCode}]"; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,119 @@ | ||
namespace TurboMqtt.Core.PacketTypes; | ||
|
||
public sealed class SubscribePacket : MqttPacketWithId | ||
{ | ||
public override MqttPacketType PacketType { get; } | ||
|
||
/// <summary> | ||
/// The unique identity of this subscription for this client. | ||
/// </summary> | ||
/// <remarks> | ||
/// Must be a value greater than 0. | ||
/// </remarks> | ||
public NonZeroUInt32 SubscriptionIdentifier { get; set; } | ||
|
||
public TopicSubscription[] Topics { get; set; } = Array.Empty<TopicSubscription>(); | ||
|
||
/// <summary> | ||
/// User Property, available in MQTT 5.0. | ||
/// This is a key-value pair that can be sent multiple times to convey additional information that is not covered by other means. | ||
/// </summary> | ||
public Dictionary<string, string>? UserProperties { get; set; } // MQTT 5.0 only | ||
} | ||
|
||
public sealed class TopicSubscription(string topic) | ||
{ | ||
/// <summary> | ||
/// The topic to subscribe to. | ||
/// </summary> | ||
public string Topic { get; } = topic; | ||
|
||
/// <summary> | ||
/// The subscription options - QoS, No Local, Retain As Published, Retain Handling. | ||
/// </summary> | ||
/// <remarks> | ||
/// Some of these are MQTT 5.0 features and will not be used in MQTT 3.1.1 or 3.0. | ||
/// </remarks> | ||
public SubscriptionOptions Options { get; set; } | ||
|
||
public override string ToString() | ||
{ | ||
return $"Topic: {Topic}, Options: {Options}"; | ||
} | ||
} | ||
|
||
public enum RetainHandlingOption | ||
{ | ||
SendAtSubscribe = 0, // 00 binary | ||
SendAtSubscribeIfNew = 1, // 01 binary | ||
DoNotSendAtSubscribe = 2 // 10 binary | ||
} | ||
|
||
public struct SubscriptionOptions | ||
{ | ||
/// <summary> | ||
/// Gets or sets the Quality of Service level to use when sending messages to the client. | ||
/// </summary> | ||
public QualityOfService QoS { get; set; } | ||
|
||
/// <summary> | ||
/// MQTT 5.0 Feature: indicates whether or not the sender can receive its own messages. | ||
/// </summary> | ||
public bool NoLocal { get; set; } | ||
|
||
/// <summary> | ||
/// MQTT 5.0 Feature: indicates whether or not the message should be retained by the broker. | ||
/// </summary> | ||
public bool RetainAsPublished { get; set; } | ||
|
||
/// <summary> | ||
/// MQTT 5.0 Feature: indicates how the broker should handle retained messages. | ||
/// </summary> | ||
public RetainHandlingOption RetainHandling { get; set; } | ||
|
||
public override string ToString() | ||
{ | ||
return $"QoS: {QoS}, No Local: {NoLocal}, Retain As Published: {RetainAsPublished}, Retain Handling: {RetainHandling}"; | ||
} | ||
} | ||
|
||
internal static class SubscriptionOptionsHelpers | ||
{ | ||
public static byte ToByte(this SubscriptionOptions subscriptionOptions) | ||
{ | ||
byte result = 0; | ||
|
||
// Set the QoS bits (bit 0 and 1) | ||
result |= (byte)subscriptionOptions.QoS; | ||
|
||
// Set the No Local bit (bit 2) | ||
if (subscriptionOptions.NoLocal) | ||
{ | ||
result |= 1 << 2; | ||
} | ||
|
||
// Set the Retain As Published bit (bit 3) | ||
if (subscriptionOptions.RetainAsPublished) | ||
{ | ||
result |= 1 << 3; | ||
} | ||
|
||
// Set the Retain Handling bits (bit 4 and 5) | ||
result |= (byte)((int)subscriptionOptions.RetainHandling << 4); | ||
|
||
return result; | ||
} | ||
|
||
public static SubscriptionOptions ToSubscriptionOptions(this byte subscriptionOptions) | ||
{ | ||
var result = new SubscriptionOptions | ||
{ | ||
QoS = (QualityOfService)(subscriptionOptions & 0b11), | ||
NoLocal = (subscriptionOptions & (1 << 2)) != 0, | ||
RetainAsPublished = (subscriptionOptions & (1 << 3)) != 0, | ||
RetainHandling = (RetainHandlingOption)((subscriptionOptions & 0b11000) >> 3) | ||
}; | ||
|
||
return result; | ||
} | ||
} |