diff --git a/MQTTnet.sln b/MQTTnet.sln index 2c1fcd710..5886b9740 100644 --- a/MQTTnet.sln +++ b/MQTTnet.sln @@ -33,6 +33,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MQTTnet.Extensions.TopicTem EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MQTTnet.Server", "Source\MQTTnet.Server\MQTTnet.Server.csproj", "{C876EFFD-C5AD-4E26-BD9F-4C48252C02BC}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MQTTnet.PowerShell", "Source\MQTTnet.PowerShell\MQTTnet.PowerShell.csproj", "{37B129C5-0231-4EB5-AF13-77959068911C}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -79,6 +81,10 @@ Global {C876EFFD-C5AD-4E26-BD9F-4C48252C02BC}.Debug|Any CPU.Build.0 = Debug|Any CPU {C876EFFD-C5AD-4E26-BD9F-4C48252C02BC}.Release|Any CPU.ActiveCfg = Release|Any CPU {C876EFFD-C5AD-4E26-BD9F-4C48252C02BC}.Release|Any CPU.Build.0 = Release|Any CPU + {37B129C5-0231-4EB5-AF13-77959068911C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {37B129C5-0231-4EB5-AF13-77959068911C}.Debug|Any CPU.Build.0 = Debug|Any CPU + {37B129C5-0231-4EB5-AF13-77959068911C}.Release|Any CPU.ActiveCfg = Release|Any CPU + {37B129C5-0231-4EB5-AF13-77959068911C}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/Source/MQTTnet.PowerShell/Cmdlets/ConnectMqttSessionCmdlet.cs b/Source/MQTTnet.PowerShell/Cmdlets/ConnectMqttSessionCmdlet.cs new file mode 100644 index 000000000..e576267b6 --- /dev/null +++ b/Source/MQTTnet.PowerShell/Cmdlets/ConnectMqttSessionCmdlet.cs @@ -0,0 +1,47 @@ +using System.Management.Automation; + +namespace MQTTnet.PowerShell.Cmdlets; + +[Cmdlet(VerbsCommunications.Connect, "MqttSession")] +[OutputType(typeof(MqttClientConnectResult))] +public class ConnectMqttSessionCmdlet : PSCmdlet +{ + [Parameter] + public SwitchParameter CleanSession { get; set; } = true; + + [Parameter] + public string? ClientId { get; set; } = Guid.NewGuid().ToString(); + + [Parameter(Mandatory = true)] + public required new string Host { get; set; } + + [Parameter] + public string? Password { get; set; } + + [Parameter] + public int Port { get; set; } = 1883; + + [Parameter(Mandatory = true, ValueFromPipeline = true)] + public required PsMqttSession Session { get; set; } + + [Parameter] + public string? Username { get; set; } + + [Parameter] + public SwitchParameter UseTls { get; set; } + + protected override void ProcessRecord() + { + var clientOptionsBuilder = new MqttClientOptionsBuilder(); + clientOptionsBuilder.WithTcpServer(Host, Port); + + if (Username != null) + { + clientOptionsBuilder.WithCredentials(Username, Password); + } + + var response = Session.GetClient().ConnectAsync(clientOptionsBuilder.Build()).GetAwaiter().GetResult(); + + WriteObject(response); + } +} \ No newline at end of file diff --git a/Source/MQTTnet.PowerShell/Cmdlets/DisconnectMqttSessionCmdlet.cs b/Source/MQTTnet.PowerShell/Cmdlets/DisconnectMqttSessionCmdlet.cs new file mode 100644 index 000000000..4d86fcc4a --- /dev/null +++ b/Source/MQTTnet.PowerShell/Cmdlets/DisconnectMqttSessionCmdlet.cs @@ -0,0 +1,31 @@ +using System.Management.Automation; + +namespace MQTTnet.PowerShell.Cmdlets; + +[Cmdlet(VerbsCommunications.Disconnect, "MqttSession")] +public class DisconnectMqttSessionCmdlet : PSCmdlet +{ + [Parameter] + public MqttClientDisconnectOptionsReason Reason { get; set; } = MqttClientDisconnectOptionsReason.NormalDisconnection; + + [Parameter] + public string? ReasonString { get; set; } + + [Parameter(Mandatory = true, ValueFromPipeline = true)] + public required PsMqttSession Session { get; set; } + + [Parameter] + public uint SessionExpiryInterval { get; set; } + + protected override void ProcessRecord() + { + if (Session.GetClient().IsConnected) + { + var options = new MqttClientDisconnectOptionsBuilder().WithSessionExpiryInterval(SessionExpiryInterval).WithReason(Reason).WithReasonString(ReasonString).Build(); + + Session.GetClient().DisconnectAsync(options).GetAwaiter().GetResult(); + } + + WriteObject("Disconnected."); + } +} \ No newline at end of file diff --git a/Source/MQTTnet.PowerShell/Cmdlets/NewMqttSessionCmdlet.cs b/Source/MQTTnet.PowerShell/Cmdlets/NewMqttSessionCmdlet.cs new file mode 100644 index 000000000..68aaae3f7 --- /dev/null +++ b/Source/MQTTnet.PowerShell/Cmdlets/NewMqttSessionCmdlet.cs @@ -0,0 +1,13 @@ +using System.Management.Automation; + +namespace MQTTnet.PowerShell.Cmdlets; + +[Cmdlet(VerbsCommon.New, "MqttSession")] +[OutputType(typeof(PsMqttSession))] +public class NewMqttSessionCmdlet : PSCmdlet +{ + protected override void ProcessRecord() + { + WriteObject(new PsMqttSession()); + } +} \ No newline at end of file diff --git a/Source/MQTTnet.PowerShell/Cmdlets/PublishMqttMessageCmdlet.cs b/Source/MQTTnet.PowerShell/Cmdlets/PublishMqttMessageCmdlet.cs new file mode 100644 index 000000000..7547b25b6 --- /dev/null +++ b/Source/MQTTnet.PowerShell/Cmdlets/PublishMqttMessageCmdlet.cs @@ -0,0 +1,52 @@ +using System.Management.Automation; +using System.Text; +using MQTTnet.Protocol; + +namespace MQTTnet.PowerShell.Cmdlets; + +[Cmdlet(VerbsData.Publish, "MqttMessage")] +public class PublishMqttMessageCmdlet : PSCmdlet +{ + [Parameter(Mandatory = true)] + public string? Payload { get; set; } + + [Parameter] + public int QoS { get; set; } = 0; + + [Parameter] + public SwitchParameter Retain { get; set; } + + [Parameter(Mandatory = true, ValueFromPipeline = true)] + public required PsMqttSession Session { get; set; } + + [Parameter(Mandatory = true)] + public required string Topic { get; set; } + + public string? ContentType { get; set; } + + public string? ResponseTopic { get; set; } + + public ushort TopicAlias { get; set; } + + public uint MessageExpiryInterval { get; set; } + + protected override void ProcessRecord() + { + // if (Session == null || !Session.IsConnected) + // throw new InvalidOperationException("Session not connected."); + + var msg = new MqttApplicationMessageBuilder().WithTopic(Topic) + .WithPayload(Encoding.UTF8.GetBytes(Payload ?? string.Empty)) + .WithQualityOfServiceLevel((MqttQualityOfServiceLevel)QoS) + .WithRetainFlag(Retain) + .WithContentType(ContentType) + .WithResponseTopic(ResponseTopic) + .WithTopicAlias(TopicAlias) + .WithMessageExpiryInterval(MessageExpiryInterval) + .Build(); + + var response = Session.GetClient().PublishAsync(msg).GetAwaiter().GetResult(); + + WriteObject(response); + } +} \ No newline at end of file diff --git a/Source/MQTTnet.PowerShell/Cmdlets/ReceiveMqttMessageCmdlet.cs b/Source/MQTTnet.PowerShell/Cmdlets/ReceiveMqttMessageCmdlet.cs new file mode 100644 index 000000000..82983d5ef --- /dev/null +++ b/Source/MQTTnet.PowerShell/Cmdlets/ReceiveMqttMessageCmdlet.cs @@ -0,0 +1,74 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Management.Automation; + +namespace MQTTnet.PowerShell.Cmdlets; + +[Cmdlet(VerbsCommunications.Receive, "MqttMessage")] +[OutputType(typeof(PsMqttMessage))] +public class ReceiveMqttMessageCmdlet : PSCmdlet +{ + [Parameter(Mandatory = true, ValueFromPipeline = true)] + public required PsMqttSession Session { get; set; } + + [Parameter] + [ValidateRange(0, int.MaxValue)] + public int TimeoutSeconds { get; set; } = 0; + + protected override void ProcessRecord() + { + var tcs = new TaskCompletionSource(); + EventHandler? handler = null; + CancellationTokenSource? cts = null; + + try + { + handler = (s, e) => + { + if (!tcs.Task.IsCompleted) + { + tcs.TrySetResult(e); + } + }; + + Session.MessageReceived += handler; + + // Optionaler Timeout + if (TimeoutSeconds > 0) + { + cts = new CancellationTokenSource(); + cts.CancelAfter(TimeSpan.FromSeconds(TimeoutSeconds)); + cts.Token.Register(() => + { + if (!tcs.Task.IsCompleted) + { + tcs.TrySetCanceled(); + } + }); + } + + WriteVerbose("Waiting for next MQTT message..."); + + try + { + var message = tcs.Task.GetAwaiter().GetResult(); + WriteObject(message); + } + catch (TaskCanceledException) + { + WriteWarning($"Timeout after {TimeoutSeconds} seconds — no message received."); + } + } + finally + { + if (handler != null) + { + Session.MessageReceived -= handler; + } + + cts?.Dispose(); + } + } +} \ No newline at end of file diff --git a/Source/MQTTnet.PowerShell/Cmdlets/RegisterMqttMessageHandlerCmdlet.cs b/Source/MQTTnet.PowerShell/Cmdlets/RegisterMqttMessageHandlerCmdlet.cs new file mode 100644 index 000000000..844e45b9c --- /dev/null +++ b/Source/MQTTnet.PowerShell/Cmdlets/RegisterMqttMessageHandlerCmdlet.cs @@ -0,0 +1,26 @@ +using System.Management.Automation; +using System.Management.Automation.Runspaces; + +namespace MQTTnet.PowerShell.Cmdlets; + +[Cmdlet(VerbsLifecycle.Register, "MqttMessageHandler")] +public class RegisterMqttMessageHandlerCmdlet : PSCmdlet +{ + [Parameter(Mandatory = true, ValueFromPipeline = true)] + public required PsMqttSession Session { get; set; } + + [Parameter(Mandatory = true)] + public ScriptBlock? Action { get; set; } + + protected override void ProcessRecord() + { + EventHandler handler = (s, e) => + { + //throw new NotImplementedException(); + //InvokeCommand.InvokeScript(Action, false, PipelineResultTypes.Output, null, new object[] { e.Topic, e.Payload }); + }; + + Session.MessageReceived += handler; + WriteObject($"Handler registered for MQTT messages on session."); + } +} \ No newline at end of file diff --git a/Source/MQTTnet.PowerShell/Cmdlets/RemoveMqttSessionCmdlet.cs b/Source/MQTTnet.PowerShell/Cmdlets/RemoveMqttSessionCmdlet.cs new file mode 100644 index 000000000..3e3084a44 --- /dev/null +++ b/Source/MQTTnet.PowerShell/Cmdlets/RemoveMqttSessionCmdlet.cs @@ -0,0 +1,16 @@ +using System.Management.Automation; + +namespace MQTTnet.PowerShell.Cmdlets; + +[Cmdlet(VerbsCommon.Remove, "MqttSession")] +public class RemoveMqttSessionCmdlet : PSCmdlet +{ + [Parameter(Mandatory = true, ValueFromPipeline = true)] + public required PsMqttSession Session { get; set; } + + protected override void ProcessRecord() + { + Session.Dispose(); + WriteObject("Session removed."); + } +} \ No newline at end of file diff --git a/Source/MQTTnet.PowerShell/Cmdlets/SubscribeMqttTopicCmdlet.cs b/Source/MQTTnet.PowerShell/Cmdlets/SubscribeMqttTopicCmdlet.cs new file mode 100644 index 000000000..69bb570d8 --- /dev/null +++ b/Source/MQTTnet.PowerShell/Cmdlets/SubscribeMqttTopicCmdlet.cs @@ -0,0 +1,55 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Management.Automation; +using MQTTnet.Protocol; + +namespace MQTTnet.PowerShell.Cmdlets; + +[Cmdlet("Subscribe", "MqttTopic")] +[OutputType(typeof(MqttClientSubscribeResult))] +public class SubscribeMqttTopicCmdlet : PSCmdlet +{ + [Parameter] + public bool NoLocal { get; set; } + + [Parameter] + public int QoS { get; set; } = 0; + + [Parameter] + public bool RetainAsPublished { get; set; } + + [Parameter] + public MqttRetainHandling RetainHandling { get; set; } = MqttRetainHandling.SendAtSubscribe; + + [Parameter(Mandatory = true, ValueFromPipeline = true)] + public required PsMqttSession Session { get; set; } + + [Parameter] + public uint SubscriptionIdentifier { get; set; } + + [Parameter(Mandatory = true)] + public required string Topic { get; set; } + + protected override void ProcessRecord() + { + var topicFilter = new MqttTopicFilterBuilder().WithTopic(Topic) + .WithQualityOfServiceLevel((MqttQualityOfServiceLevel)QoS) + .WithNoLocal(NoLocal) + .WithRetainAsPublished(RetainAsPublished) + .WithRetainHandling(RetainHandling) + .Build(); + + var options = new MqttClientSubscribeOptionsBuilder().WithTopicFilter(topicFilter); + + if (SubscriptionIdentifier > 0) + { + options.WithSubscriptionIdentifier(SubscriptionIdentifier); + } + + var response = Session.GetClient().SubscribeAsync(options.Build()).GetAwaiter().GetResult(); + + WriteObject(response); + } +} \ No newline at end of file diff --git a/Source/MQTTnet.PowerShell/Cmdlets/UnsubscribeMqttTopicCmdlet.cs b/Source/MQTTnet.PowerShell/Cmdlets/UnsubscribeMqttTopicCmdlet.cs new file mode 100644 index 000000000..efee5fc23 --- /dev/null +++ b/Source/MQTTnet.PowerShell/Cmdlets/UnsubscribeMqttTopicCmdlet.cs @@ -0,0 +1,23 @@ +using System.Management.Automation; + +namespace MQTTnet.PowerShell.Cmdlets; + +[Cmdlet("Unsubscribe", "MqttTopic")] +[OutputType(typeof(MqttClientUnsubscribeResult))] +public class UnsubscribeMqttTopicCmdlet : PSCmdlet +{ + [Parameter(Mandatory = true, ValueFromPipeline = true)] + public required PsMqttSession Session { get; set; } + + [Parameter(Mandatory = true)] + public required string Topic { get; set; } + + protected override void ProcessRecord() + { + var options = new MqttClientUnsubscribeOptionsBuilder().WithTopicFilter(Topic).Build(); + + var response = Session.GetClient().UnsubscribeAsync(options).GetAwaiter().GetResult(); + + WriteObject(response); + } +} \ No newline at end of file diff --git a/Source/MQTTnet.PowerShell/MQTTnet.PowerShell.csproj b/Source/MQTTnet.PowerShell/MQTTnet.PowerShell.csproj new file mode 100644 index 000000000..5e45f70f5 --- /dev/null +++ b/Source/MQTTnet.PowerShell/MQTTnet.PowerShell.csproj @@ -0,0 +1,28 @@ + + + + MQTTnet.PowerShell + default + enable + + + + + All + + + + + + + + + + + + + + + + + diff --git a/Source/MQTTnet.PowerShell/PsMqttMessage.cs b/Source/MQTTnet.PowerShell/PsMqttMessage.cs new file mode 100644 index 000000000..696362451 --- /dev/null +++ b/Source/MQTTnet.PowerShell/PsMqttMessage.cs @@ -0,0 +1,30 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Management.Automation; +using MQTTnet.Packets; + +namespace MQTTnet.PowerShell; + +public class PsMqttPublishResult +{ + +} + +public class PsMqttConnectResult +{ + +} + +public class PsMqttMessage +{ + public required string? ContentType { get; init; } + public required string Payload { get; init; } + public int QoS { get; init; } + public required byte[] RawPayload { get; init; } + public string? ResponseTopic { get; init; } + public bool Retain { get; init; } + public required string Topic { get; init; } + public required List? UserProperties { get; init; } +} \ No newline at end of file diff --git a/Source/MQTTnet.PowerShell/PsMqttSession.cs b/Source/MQTTnet.PowerShell/PsMqttSession.cs new file mode 100644 index 000000000..83089763c --- /dev/null +++ b/Source/MQTTnet.PowerShell/PsMqttSession.cs @@ -0,0 +1,50 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Buffers; +using System.Text; + +namespace MQTTnet.PowerShell; + +public sealed class PsMqttSession : IDisposable +{ + readonly IMqttClient _client; + + public PsMqttSession() + { + var factory = new MqttClientFactory(); + _client = factory.CreateMqttClient(); + + _client.ApplicationMessageReceivedAsync += e => + { + MessageReceived?.Invoke( + this, + new PsMqttMessage + { + Topic = e.ApplicationMessage.Topic, + Payload = Encoding.UTF8.GetString(e.ApplicationMessage.Payload), + RawPayload = e.ApplicationMessage.Payload.ToArray(), + UserProperties = e.ApplicationMessage.UserProperties, + QoS = (int)e.ApplicationMessage.QualityOfServiceLevel, + ContentType = e.ApplicationMessage.ContentType, + Retain = e.ApplicationMessage.Retain, + ResponseTopic = e.ApplicationMessage.ResponseTopic + }); + + return Task.CompletedTask; + }; + } + + public event EventHandler? MessageReceived; + + public void Dispose() + { + _client.Dispose(); + } + + public IMqttClient GetClient() + { + return _client; + } +} \ No newline at end of file diff --git a/Source/MQTTnet.PowerShell/Test.ps1 b/Source/MQTTnet.PowerShell/Test.ps1 new file mode 100644 index 000000000..985330eab --- /dev/null +++ b/Source/MQTTnet.PowerShell/Test.ps1 @@ -0,0 +1,15 @@ +Import-Module ./bin/Debug/net8.0/MQTTnet.PowerShell.dll + +$session = New-MqttSession + +Connect-MqttSession -Session $session -Host "192.168.1.16" + +Publish-MqttMessage -Session $session -Topic "Test" -Payload "Hello from PowerShell" + +Subscribe-MqttTopic -Session $session -Topic "test/demo" + +Receive-MqttMessage -Session $session -TimeoutSeconds 200 + +Disconnect-MqttSession -Session $session +Remove-MqttSession -Session $session + diff --git a/Source/MQTTnet.PowerShell/bin/Debug/net8.0/MQTTnet.PowerShell.deps.json b/Source/MQTTnet.PowerShell/bin/Debug/net8.0/MQTTnet.PowerShell.deps.json new file mode 100644 index 000000000..9159334b2 --- /dev/null +++ b/Source/MQTTnet.PowerShell/bin/Debug/net8.0/MQTTnet.PowerShell.deps.json @@ -0,0 +1,55 @@ +{ + "runtimeTarget": { + "name": ".NETCoreApp,Version=v8.0", + "signature": "" + }, + "compilationOptions": {}, + "targets": { + ".NETCoreApp,Version=v8.0": { + "MQTTnet.PowerShell/1.0.0": { + "dependencies": { + "MQTTnet": "1.0.0", + "PowerShellStandard.Library": "5.1.1" + }, + "runtime": { + "MQTTnet.PowerShell.dll": {} + } + }, + "PowerShellStandard.Library/5.1.1": { + "runtime": { + "lib/netstandard2.0/System.Management.Automation.dll": { + "assemblyVersion": "3.0.0.0", + "fileVersion": "5.1.1.0" + } + } + }, + "MQTTnet/1.0.0": { + "runtime": { + "MQTTnet.dll": { + "assemblyVersion": "1.0.0.0", + "fileVersion": "1.0.0.0" + } + } + } + } + }, + "libraries": { + "MQTTnet.PowerShell/1.0.0": { + "type": "project", + "serviceable": false, + "sha512": "" + }, + "PowerShellStandard.Library/5.1.1": { + "type": "package", + "serviceable": true, + "sha512": "sha512-e31xJjG+Kjbv6YF3Yq6D4Dl3or8v7LrNF41k3CXrWozW6hR1zcOe5KYuZJaGSiAgLnwP8wcW+I3+IWEzMPZKXQ==", + "path": "powershellstandard.library/5.1.1", + "hashPath": "powershellstandard.library.5.1.1.nupkg.sha512" + }, + "MQTTnet/1.0.0": { + "type": "project", + "serviceable": false, + "sha512": "" + } + } +} \ No newline at end of file diff --git a/Source/MQTTnet.PowerShell/bin/Debug/net8.0/MQTTnet.PowerShell.dll b/Source/MQTTnet.PowerShell/bin/Debug/net8.0/MQTTnet.PowerShell.dll new file mode 100644 index 000000000..d6185832d Binary files /dev/null and b/Source/MQTTnet.PowerShell/bin/Debug/net8.0/MQTTnet.PowerShell.dll differ diff --git a/Source/MQTTnet.PowerShell/bin/Debug/net8.0/MQTTnet.PowerShell.pdb b/Source/MQTTnet.PowerShell/bin/Debug/net8.0/MQTTnet.PowerShell.pdb new file mode 100644 index 000000000..8c86d2d45 Binary files /dev/null and b/Source/MQTTnet.PowerShell/bin/Debug/net8.0/MQTTnet.PowerShell.pdb differ diff --git a/Source/MQTTnet.PowerShell/bin/Debug/net8.0/MQTTnet.dll b/Source/MQTTnet.PowerShell/bin/Debug/net8.0/MQTTnet.dll new file mode 100644 index 000000000..6a1629bc6 Binary files /dev/null and b/Source/MQTTnet.PowerShell/bin/Debug/net8.0/MQTTnet.dll differ diff --git a/Source/MQTTnet.PowerShell/bin/Debug/net8.0/MQTTnet.pdb b/Source/MQTTnet.PowerShell/bin/Debug/net8.0/MQTTnet.pdb new file mode 100644 index 000000000..c3f843a4e Binary files /dev/null and b/Source/MQTTnet.PowerShell/bin/Debug/net8.0/MQTTnet.pdb differ diff --git a/Source/MQTTnet.PowerShell/bin/Debug/net8.0/MQTTnet.xml b/Source/MQTTnet.PowerShell/bin/Debug/net8.0/MQTTnet.xml new file mode 100644 index 000000000..9176cb5c0 --- /dev/null +++ b/Source/MQTTnet.PowerShell/bin/Debug/net8.0/MQTTnet.xml @@ -0,0 +1,1182 @@ + + + + MQTTnet + + + + + Gets the authentication result. + MQTT 5.0.0+ feature. + + + + + Gets the client identifier which was chosen by the server. + MQTTv5 only. + + + + + Gets the authentication data. + MQTTv5 only. + + + + + Gets the authentication method. + MQTTv5 only. + + + + + Gets a value indicating whether a session was already available or not. + + + + + Gets the maximum QoS which is supported by the server. + MQTTv5 only. + + + + + Gets the reason string. + MQTTv5 only. + + + + + Gets the response information. + MQTTv5 only. + + + + + Gets the result code. + + + + + Gets whether the server supports retained messages. + MQTTv5 only. + + + + + MQTTv5 only. + Gets the keep alive interval which was chosen by the server instead of the + keep alive interval from the client CONNECT packet. + A value of 0 indicates that the feature is not used. + + + + + Gets an alternate server which should be used instead of the current one. + MQTTv5 only. + + + + + Gets a value indicating whether the shared subscriptions are available or not. + MQTTv5 only. + + + + + Gets a value indicating whether the subscription identifiers are available or not. + MQTTv5 only. + + + + + Gets the maximum value for a topic alias. 0 means not supported. + MQTTv5 only. + + + + + Gets the user properties. + In MQTT 5, user properties are basic UTF-8 string key-value pairs that you can append to almost every type of MQTT + packet. + As long as you don’t exceed the maximum message size, you can use an unlimited number of user properties to add + metadata to MQTT messages and pass information between publisher, broker, and subscriber. + The feature is very similar to the HTTP header concept. + MQTTv5 only. + + + + + Gets a value indicating whether wildcards can be used in subscriptions at the current server. + MQTTv5 only. + + + + + This logger fires an event when a new message was published. + + + + + This logger fires an event when a new message was published. + + + + + This logger does nothing with the messages. + + + + + Gets the authentication result. + MQTT 5.0.0+ feature. + + + + + Gets or sets the reason. + MQTT 5.0.0+ feature. + + + + + Gets or sets the reason code. + MQTT 5.0.0+ feature. + + + + + Gets or sets the reason string. + MQTT 5.0.0+ feature. + + + + + Gets or sets the session expiry interval. + MQTT 5.0.0+ feature. + + + + + Gets or sets the user properties. + MQTT 5.0.0+ feature. + + + + + This enum only contains values which are valid when a client sends the reason to the server. + + + + + This is a custom implementation of a memory stream which provides only MQTTnet relevant features. + The goal is to avoid lots of argument checks like in the original stream. The growth rule is the + same as for the original MemoryStream in .net. Also this implementation allows accessing the internal + buffer for all platforms and .net framework versions (which is not available at the regular MemoryStream). + + + + + Gets or sets the content type. + The content type must be a UTF-8 encoded string. The content type value identifies the kind of UTF-8 encoded + payload. + + + + + Gets or sets the correlation data. + In order for the sender to know what sent message the response refers to it can also send correlation data with the + published message. + Hint: MQTT 5 feature only. + + + + + If the DUP flag is set to 0, it indicates that this is the first occasion that the Client or Server has attempted + to send this MQTT PUBLISH Packet. + If the DUP flag is set to 1, it indicates that this might be re-delivery of an earlier attempt to send the Packet. + The DUP flag MUST be set to 1 by the Client or Server when it attempts to re-deliver a PUBLISH Packet + [MQTT-3.3.1.-1]. + The DUP flag MUST be set to 0 for all QoS 0 messages [MQTT-3.3.1-2]. + + + + + Gets or sets the message expiry interval. + A client can set the message expiry interval in seconds for each PUBLISH message individually. + This interval defines the period of time that the broker stores the PUBLISH message for any matching subscribers + that are not currently connected. + When no message expiry interval is set, the broker must store the message for matching subscribers indefinitely. + When the retained=true option is set on the PUBLISH message, this interval also defines how long a message is + retained on a topic. + Hint: MQTT 5 feature only. + + + + + Set an ArraySegment as Payload. + + + + + Get or set ReadOnlySequence style of Payload. + This payload type is used internally and is recommended for public use. + It can be used in combination with a RecyclableMemoryStream to publish + large buffered messages without allocating large chunks of memory. + + + + + Gets or sets the payload format indicator. + The payload format indicator is part of any MQTT packet that can contain a payload. The indicator is an optional + byte value. + A value of 0 indicates an “unspecified byte stream”. + A value of 1 indicates a "UTF-8 encoded payload". + If no payload format indicator is provided, the default value is 0. + Hint: MQTT 5 feature only. + + + + + Gets or sets the quality of service level. + The Quality of Service (QoS) level is an agreement between the sender of a message and the receiver of a message + that defines the guarantee of delivery for a specific message. + There are 3 QoS levels in MQTT: + - At most once (0): Message gets delivered no time, once or multiple times. + - At least once (1): Message gets delivered at least once (one time or more often). + - Exactly once (2): Message gets delivered exactly once (It's ensured that the message only comes once). + + + + + Gets or sets the response topic. + In MQTT 5 the ability to publish a response topic was added in the publish message which allows you to implement + the request/response pattern between clients that is common in web applications. + Hint: MQTT 5 feature only. + + + + + Gets or sets a value indicating whether the message should be retained or not. + A retained message is a normal MQTT message with the retained flag set to true. + The broker stores the last retained message and the corresponding QoS for that topic. + + + + + Gets or sets the subscription identifiers. + The client can specify a subscription identifier when subscribing. + The broker will establish and store the mapping relationship between this subscription and subscription identifier + when successfully create or modify subscription. + The broker will return the subscription identifier associated with this PUBLISH packet and the PUBLISH packet to + the client when need to forward PUBLISH packets matching this subscription to this client. + Hint: MQTT 5 feature only. + + + + + Gets or sets the MQTT topic. + In MQTT, the word topic refers to an UTF-8 string that the broker uses to filter messages for each connected + client. + The topic consists of one or more topic levels. Each topic level is separated by a forward slash (topic level + separator). + + + + + Gets or sets the topic alias. + Topic aliases were introduced are a mechanism for reducing the size of published packets by reducing the size of + the topic field. + A value of 0 indicates no topic alias is used. + Hint: MQTT 5 feature only. + + + + + Gets or sets the user properties. + In MQTT 5, user properties are basic UTF-8 string key-value pairs that you can append to almost every type of MQTT + packet. + As long as you don’t exceed the maximum message size, you can use an unlimited number of user properties to add + metadata to MQTT messages and pass information between publisher, broker, and subscriber. + The feature is very similar to the HTTP header concept. + Hint: MQTT 5 feature only. + + + + + Adds the content type to the message. + MQTT 5.0.0+ feature. + + + + + Adds the correlation data to the message. + MQTT 5.0.0+ feature. + + + + + Adds the message expiry interval in seconds to the message. + MQTT 5.0.0+ feature. + + + + + Adds the payload format indicator to the message. + MQTT 5.0.0+ feature. + + + + + The quality of service level. + The Quality of Service (QoS) level is an agreement between the sender of a message and the receiver of a message + that defines the guarantee of delivery for a specific message. + There are 3 QoS levels in MQTT: + - At most once (0): Message gets delivered no time, once or multiple times. + - At least once (1): Message gets delivered at least once (one time or more often). + - Exactly once (2): Message gets delivered exactly once (It's ensured that the message only comes once). + + + + + Adds the response topic to the message. + MQTT 5.0.0+ feature. + + + + + A value indicating whether the message should be retained or not. + A retained message is a normal MQTT message with the retained flag set to true. + The broker stores the last retained message and the corresponding QoS for that topic. + + + + + Adds the subscription identifier to the message. + MQTT 5.0.0+ feature. + + + + + The MQTT topic. + In MQTT, the word topic refers to an UTF-8 string that the broker uses to filter messages for each connected + client. + The topic consists of one or more topic levels. Each topic level is separated by a forward slash (topic level + separator). + + + + + Adds the topic alias to the message. + MQTT 5.0.0+ feature. + + + + + Adds the user property to the message. + MQTT 5.0.0+ feature. + + + + + The quality of service level. + The Quality of Service (QoS) level is an agreement between the sender of a message and the receiver of a message that defines the guarantee of delivery for a specific message. + There are 3 QoS levels in MQTT: + - At most once (0): Message gets delivered no time, once or multiple times. + - At least once (1): Message gets delivered at least once (one time or more often). + - Exactly once (2): Message gets delivered exactly once (It's ensured that the message only comes once). + + + + + The MQTT topic. + In MQTT, the word topic refers to an UTF-8 string that the broker uses to filter messages for each connected client. + The topic consists of one or more topic levels. Each topic level is separated by a forward slash (topic level separator). + + + + + Usually the MQTT packets can be sent partially. This is done by using multiple TCP packets + or WebSocket frames etc. Unfortunately not all brokers (like Amazon Web Services (AWS)) do support this feature and + will close the connection when receiving such packets. If such a service is used this flag must + be set to _false_. + + + + + Gets or sets the authentication data. + MQTT 5.0.0+ feature. + + + + + Gets or sets the authentication method. + MQTT 5.0.0+ feature. + + + + + Gets or sets a value indicating whether clean sessions are used or not. + When a client connects to a broker it can connect using either a non persistent connection (clean session) or a + persistent connection. + With a non-persistent connection the broker doesn't store any subscription information or undelivered messages for + the client. + This mode is ideal when the client only publishes messages. + It can also connect as a durable client using a persistent connection. + In this mode, the broker will store subscription information, and undelivered messages for the client. + + + + + Gets the client identifier. + Hint: This identifier needs to be unique over all used clients / devices on the broker to avoid connection issues. + + + + + Gets or sets the handler for AUTH packets. + This can happen when connecting or at any time while being already connected. + MQTT 5.0.0+ feature. + + + + + Gets or sets the keep alive period. + The connection is normally left open by the client so that is can send and receive data at any time. + If no data flows over an open connection for a certain time period then the client will generate a PINGREQ and + expect to receive a PINGRESP from the broker. + This message exchange confirms that the connection is open and working. + This period is known as the keep alive period. + + + + + Gets or sets the maximum packet size. + MQTT 5.0.0+ feature. + + + + + Gets or sets the protocol version. + Default: 5.0.0. + + + + + Gets or sets the receive maximum. + This gives the maximum length of the received messages. + MQTT 5.0.0+ feature. + + + + + Gets or sets the request problem information. + MQTT 5.0.0+ feature. + + + + + Gets or sets the request response information. + MQTT 5.0.0+ feature. + + + + + Gets or sets the session expiry interval. + The time after a session expires when it's not actively used. + MQTT 5.0.0+ feature. + + + + + Gets or sets the timeout which will be applied at socket level and internal operations. + The default value is the same as for sockets in .NET in general. + + + + + Gets or sets the topic alias maximum. + This gives the maximum length of the topic alias. + MQTT 5.0.0+ feature. + + + + + If set to true, the bridge will attempt to indicate to the remote broker that it is a bridge not an ordinary + client. + If successful, this means that loop detection will be more effective and that retained messages will be propagated + correctly. + + Not all brokers support this feature so it may be necessary to set it to false if your bridge does not + connect properly. + + + + + + Gets or sets the user properties. + In MQTT 5, user properties are basic UTF-8 string key-value pairs that you can append to almost every type of MQTT + packet. + As long as you don’t exceed the maximum message size, you can use an unlimited number of user properties to add + metadata to MQTT messages and pass information between publisher, broker, and subscriber. + The feature is very similar to the HTTP header concept. + MQTT 5.0.0+ feature. + + + + + When this feature is enabled the client will check if used properties are supported in the selected protocol + version. + This feature can be validated if an application message is generated one time but sent via different protocol + versions. + Default values are applied if the validation is off and features are not supported. + + + + + Gets or sets the content type of the will message. + MQTT 5.0.0+ feature. + + + + + Gets or sets the correlation data of the will message. + MQTT 5.0.0+ feature. + + + + + Gets or sets the will delay interval. + This is the time between the client disconnect and the time the will message will be sent. + MQTT 5.0.0+ feature. + + + + + Gets or sets the message expiry interval of the will message. + MQTT 5.0.0+ feature. + + + + + Gets or sets the payload of the will message. + + + + + Gets or sets the payload format indicator of the will message. + MQTT 5.0.0+ feature. + + + + + Gets or sets the QoS level of the will message. + + + + + Gets or sets the response topic of the will message. + MQTT 5.0.0+ feature. + + + + + Gets or sets the retain flag of the will message. + + + + + Gets or sets the topic of the will message. + + + + + Gets or sets the user properties of the will message. + MQTT 5.0.0+ feature. + + + + + Gets or sets the default and initial size of the packet write buffer. + It is recommended to set this to a value close to the usual expected packet size * 1.5. + Do not change this value when no memory issues are experienced. + + + + + Gets or sets the maximum size of the buffer writer. The writer will reduce its internal buffer + to this value after serializing a packet. + Do not change this value when no memory issues are experienced. + + + + + Clean session is used in MQTT versions below 5.0.0. It is the same as setting "CleanStart". + + + + + Clean start is used in MQTT versions 5.0.0 and higher. It is the same as setting "CleanSession". + + + + + Usually the MQTT packets can be sent partially. This is done by using multiple TCP packets + or WebSocket frames etc. Unfortunately not all brokers (like Amazon Web Services (AWS)) do support this feature and + will close the connection when receiving such packets. If such a service is used this flag must + be set to _true_. + + + + + Sets the timeout which will be applied at socket level and internal operations. + The default value is the same as for sockets in .NET in general. + + + + + If set to true, the bridge will attempt to indicate to the remote broker that it is a bridge not an ordinary + client. + If successful, this means that loop detection will be more effective and that retained messages will be propagated + correctly. + Not all brokers support this feature so it may be necessary to set it to false if your bridge does not connect + properly. + + + + + Gets or sets whether the underlying socket should run in dual mode. + Leaving this _null_ will avoid setting this value at socket level. + Setting this a value other than _null_ will throw an exception when only IPv4 is supported on the machine. + + + + + Gets the local endpoint (network card) which is used by the client. + Set it to _null_ to let the OS select the network card. + + + + + Enables or disables the Nagle algorithm for the socket. + This is only supported for TCP. + For other protocol types the value is ignored. + Default: true + + + + + The MQTT transport is usually TCP but when using other endpoint types like + unix sockets it must be changed (IP for unix sockets). + + + + + Gets or sets the provider for certificates. + This provider gets called whenever the client wants to connect + with the server and requires certificates for authentication. + The implementation may return different certificates each time. + + + + + Gets or sets the target host. + If the value is null or empty the same host as the TCP socket host will be used. + + + + + Gets or sets the keep alive interval for the Web Socket connection. + This is not related to the keep alive interval for the MQTT protocol. + + + + + Gets or sets whether the default (system) credentials should be used when connecting via Web Socket connection. + This is not related to the credentials which are used for the MQTT protocol. + + + + + Allows the client to negotiate deflate compression on every message, by using the permessage-deflate WebSocket extension. + This adds the Sec-WebSocket-Extensions: permessage-deflate; client_max_window_bits header. + + + + + + + Gets the authentication data. + Hint: MQTT 5 feature only. + + + + + Gets the authentication method. + Hint: MQTT 5 feature only. + + + + + Gets the reason code. + Hint: MQTT 5 feature only. + + + + + Gets the reason string. + Hint: MQTT 5 feature only. + + + + + Gets the user properties. + In MQTT 5, user properties are basic UTF-8 string key-value pairs that you can append to almost every type of MQTT + packet. + As long as you don’t exceed the maximum message size, you can use an unlimited number of user properties to add + metadata to MQTT messages and pass information between publisher, broker, and subscriber. + The feature is very similar to the HTTP header concept. + Hint: MQTT 5 feature only. + + + + + Gets or sets the authentication data. + Authentication data is binary information used to transmit multiple iterations of cryptographic secrets of protocol + steps. + The content of the authentication data is highly dependent on the specific implementation of the authentication + method. + Hint: MQTT 5 feature only. + + + + + Gets or sets the reason code. + Hint: MQTT 5 feature only. + + + + + Gets or sets the reason string. + Hint: MQTT 5 feature only. + + + + + Gets or sets the user properties. + In MQTT 5, user properties are basic UTF-8 string key-value pairs that you can append to almost every type of MQTT + packet. + As long as you don’t exceed the maximum message size, you can use an unlimited number of user properties to add + metadata to MQTT messages and pass information between publisher, broker, and subscriber. + The feature is very similar to the HTTP header concept. + Hint: MQTT 5 feature only. + + + + Added in MQTTv5.0.0. + + + + Added in MQTTv5. + + + + + Added in MQTTv3.1.1. + + + + + Added in MQTTv5. + + + + + Also called "Clean Start" in MQTTv5. + + + + + Added in MQTTv5. + + + + + Added in MQTTv5. + + + + + Added in MQTTv5. + + + + + Added in MQTTv5. + + + + + Added in MQTTv5. + + + + + Added in MQTTv5. + + + + + Added in MQTTv5. + + + + + Added in MQTTv5. + + + + + Added in MQTTv5. + + + + + Added in MQTTv5. + + + + + Added in MQTTv5. + + + + + Added in MQTTv5. + + + + + Added in MQTTv5. + + + + + Added in MQTTv5. + + + + + Added in MQTTv5. + + + + + Added in MQTTv5. + + + + + Added in MQTTv5. + + + + + Reason Code is used in MQTTv5.0.0 and backward compatible to v.3.1.1. Return Code is used in MQTTv3.1.1 + + + + + Added in MQTTv5. + + + + + Added in MQTTv5. + + + + + It is a Protocol Error if the Subscription Identifier has a value of 0. + + + + + Added in MQTTv5. + + + + + Gets or sets a value indicating whether the sender will not receive its own published application messages. + MQTT 5.0.0+ feature. + + + + + Gets or sets the quality of service level. + The Quality of Service (QoS) level is an agreement between the sender of a message and the receiver of a message + that defines the guarantee of delivery for a specific message. + There are 3 QoS levels in MQTT: + - At most once (0): Message gets delivered no time, once or multiple times. + - At least once (1): Message gets delivered at least once (one time or more often). + - Exactly once (2): Message gets delivered exactly once (It's ensured that the message only comes once). + + + + + Gets or sets a value indicating whether messages are retained as published or not. + MQTT 5.0.0+ feature. + + + + + Gets or sets the retain handling. + MQTT 5.0.0+ feature. + + + + + Gets or sets the MQTT topic. + In MQTT, the word topic refers to an UTF-8 string that the broker uses to filter messages for each connected + client. + The topic consists of one or more topic levels. Each topic level is separated by a forward slash (topic level + separator). + + + + + Added in MQTTv5. + + + + + Added in MQTTv5. + + + + + Added in MQTTv5. + + + + + Added in MQTTv5. + + + + + The message is accepted but there are no subscribers. This is sent only by the Server. If the Server knows that there are no matching subscribers, it MAY use this Reason Code instead of 0x00 (Success). + + + + + Returns if the overall status of the publish is a success. This can be the reason code _Success_ or + _NoMatchingSubscribers_. _NoMatchingSubscribers_ usually indicates only that no other client is interested in the + topic but overall transmit + to the server etc. was a success. + + + + + Gets the packet identifier which was used for this publish. + + + + + Gets or sets the reason code. + MQTT 5.0.0+ feature. + + + + + Gets or sets the reason string. + MQTT 5.0.0+ feature. + + + + + Gets or sets the user properties. + In MQTT 5, user properties are basic UTF-8 string key-value pairs that you can append to almost every type of MQTT + packet. + As long as you don’t exceed the maximum message size, you can use an unlimited number of user properties to add + metadata to MQTT messages and pass information between publisher, broker, and subscriber. + The feature is very similar to the HTTP header concept. + MQTT 5.0.0+ feature. + + + + + Gets or sets whether the library should send MQTT ACK packets automatically if required. + + + + + Gets the client identifier. + Hint: This identifier needs to be unique over all used clients / devices on the broker to avoid connection issues. + + + + + Gets or sets whether this message was handled. + This value can be used in user code for custom control flow. + + + + + Gets the identifier of the MQTT packet + + + + + Indicates if the processing of this PUBLISH packet has failed. + If the processing has failed the client will not send an ACK packet etc. + + + + + Gets or sets the reason code which will be sent to the server. + + + + + Gets or sets the reason string which will be sent to the server in the ACK packet. + + + + + Gets or sets the user properties which will be sent to the server in the ACK packet etc. + + + + + Gets or sets the subscription identifier. + The client can specify a subscription identifier when subscribing. + The broker will establish and store the mapping relationship between this subscription and subscription identifier + when successfully create or modify subscription. + The broker will return the subscription identifier associated with this PUBLISH packet and the PUBLISH packet to + the client when need to forward PUBLISH packets matching this subscription to this client. + MQTT 5.0.0+ feature. + + + + + Gets or sets a list of topic filters the client wants to subscribe to. + Topic filters can include regular topics or wild cards. + + + + + Gets or sets the user properties. + In MQTT 5, user properties are basic UTF-8 string key-value pairs that you can append to almost every type of MQTT + packet. + As long as you don’t exceed the maximum message size, you can use an unlimited number of user properties to add + metadata to MQTT messages and pass information between publisher, broker, and subscriber. + The feature is very similar to the HTTP header concept. + MQTT 5.0.0+ feature. + + + + + Adds the user property to the subscribe options. + MQTT 5.0.0+ feature. + + + + + Gets the result for every topic filter item. + + + + + Gets the packet identifier which was used. + + + + + Gets the reason string. + MQTT 5.0.0+ feature. + + + + + Gets the user properties which were part of the SUBACK packet. + MQTT 5.0.0+ feature. + + + + + Gets or sets the result code. + MQTT 5.0.0+ feature. + + + + + Gets or sets the topic filter. + The topic filter can contain topics and wildcards. + + + + + Gets or sets a list of topic filters the client wants to unsubscribe from. + Topic filters can include regular topics or wild cards. + + + + + Gets or sets the user properties. + In MQTT 5, user properties are basic UTF-8 string key-value pairs that you can append to almost every type of MQTT + packet. + As long as you don’t exceed the maximum message size, you can use an unlimited number of user properties to add + metadata to MQTT messages and pass information between publisher, broker, and subscriber. + The feature is very similar to the HTTP header concept. + MQTT 5.0.0+ feature. + + + + + Adds the user property to the unsubscribe options. + MQTT 5.0.0+ feature. + + + + + Adds the user property to the unsubscribe options. + MQTT 5.0.0+ feature. + + + + + Gets the result for every topic filter item. + + + + + Gets the packet identifier which was used. + + + + + Gets the reason string. + MQTT 5.0.0+ feature. + + + + + Gets the user properties which were part of the UNSUBACK packet. + MQTT 5.0.0+ feature. + + + + + Gets or sets the result code. + MQTT 5.0.0+ feature. + + + + + Gets or sets the topic filter. + The topic filter can contain topics and wildcards. + + + + diff --git a/Source/MQTTnet.Tests/Server/Load_Tests.cs b/Source/MQTTnet.Tests/Server/Load_Tests.cs index 2c8276e64..a302d4140 100644 --- a/Source/MQTTnet.Tests/Server/Load_Tests.cs +++ b/Source/MQTTnet.Tests/Server/Load_Tests.cs @@ -1,6 +1,7 @@ #if DEBUG using System; +using System.Globalization; using System.Threading; using System.Threading.Tasks; using Microsoft.VisualStudio.TestTools.UnitTesting; @@ -56,7 +57,7 @@ await client.SendAsync( for (var j = 0; j < 1000; j++) { - publishPacket.Topic = j.ToString(); + publishPacket.Topic = j.ToString(CultureInfo.InvariantCulture); await client.SendAsync(publishPacket, CancellationToken.None); } @@ -143,7 +144,7 @@ public async Task Handle_100_000_Messages_In_Server() for (var j = 0; j < 1000; j++) { - var message = applicationMessageBuilder.WithTopic(j.ToString()).Build(); + var message = applicationMessageBuilder.WithTopic(j.ToString(CultureInfo.InvariantCulture)).Build(); await client.PublishAsync(message); }