瀏覽代碼

Initial commit.

release/3.x.x
Christian Kratky 7 年之前
父節點
當前提交
9b720d2325
共有 70 個檔案被更改,包括 3487 行新增0 行删除
  1. +63
    -0
      .gitattributes
  2. 二進制
     
  3. +30
    -0
      MQTT.NET.Core.Tests/ByteReaderTests.cs
  4. +51
    -0
      MQTT.NET.Core.Tests/ByteWriterTests.cs
  5. +434
    -0
      MQTT.NET.Core.Tests/DefaultMqttV311PacketSerializerTests.cs
  6. +66
    -0
      MQTT.NET.Core.Tests/MQTTnet.Core.Tests.csproj
  7. +15
    -0
      MQTT.NET.Core.Tests/Properties/AssemblyInfo.cs
  8. +18
    -0
      MQTT.NET.Core/Adapter/IMqttAdapter.cs
  9. +72
    -0
      MQTT.NET.Core/Adapter/MqttChannelAdapter.cs
  10. +16
    -0
      MQTT.NET.Core/Adapter/MqttConnectingFailedException.cs
  11. +16
    -0
      MQTT.NET.Core/Channel/IMqttTransportChannel.cs
  12. +350
    -0
      MQTT.NET.Core/Client/MqttClient.cs
  13. +21
    -0
      MQTT.NET.Core/Client/MqttClientOptions.cs
  14. +7
    -0
      MQTT.NET.Core/Client/MqttClientStatistics.cs
  15. +32
    -0
      MQTT.NET.Core/Client/MqttPacketAwaiter.cs
  16. +84
    -0
      MQTT.NET.Core/Client/MqttPacketDispatcher.cs
  17. +18
    -0
      MQTT.NET.Core/Client/MqttSubscribeResult.cs
  18. +39
    -0
      MQTT.NET.Core/Diagnostics/MqttTrace.cs
  19. +10
    -0
      MQTT.NET.Core/Diagnostics/MqttTraceLevel.cs
  20. +26
    -0
      MQTT.NET.Core/Diagnostics/MqttTraceMessagePublishedEventArgs.cs
  21. +21
    -0
      MQTT.NET.Core/DictionaryExtensions.cs
  22. +21
    -0
      MQTT.NET.Core/Exceptions/MqttCommunicationException.cs
  23. +6
    -0
      MQTT.NET.Core/Exceptions/MqttCommunicationTimedOutException.cs
  24. +12
    -0
      MQTT.NET.Core/Exceptions/MqttProtocolViolationException.cs
  25. +96
    -0
      MQTT.NET.Core/MQTTnet.Core.csproj
  26. +27
    -0
      MQTT.NET.Core/MqttApplicationMessage.cs
  27. +16
    -0
      MQTT.NET.Core/MqttApplicationMessageReceivedEventArgs.cs
  28. +6
    -0
      MQTT.NET.Core/Packets/MqttBasePacket.cs
  29. +16
    -0
      MQTT.NET.Core/Packets/MqttConnAckPacket.cs
  30. +17
    -0
      MQTT.NET.Core/Packets/MqttConnectPacket.cs
  31. +6
    -0
      MQTT.NET.Core/Packets/MqttDisconnectPacket.cs
  32. +12
    -0
      MQTT.NET.Core/Packets/MqttPingReqPacket.cs
  33. +10
    -0
      MQTT.NET.Core/Packets/MqttPingRespPacket.cs
  34. +7
    -0
      MQTT.NET.Core/Packets/MqttPubAckPacket.cs
  35. +7
    -0
      MQTT.NET.Core/Packets/MqttPubCompPacket.cs
  36. +7
    -0
      MQTT.NET.Core/Packets/MqttPubRecPacket.cs
  37. +7
    -0
      MQTT.NET.Core/Packets/MqttPubRelPacket.cs
  38. +19
    -0
      MQTT.NET.Core/Packets/MqttPublishPacket.cs
  39. +12
    -0
      MQTT.NET.Core/Packets/MqttSubAckPacket.cs
  40. +11
    -0
      MQTT.NET.Core/Packets/MqttSubscribePacket.cs
  41. +7
    -0
      MQTT.NET.Core/Packets/MqttUnsubAckPacket.cs
  42. +11
    -0
      MQTT.NET.Core/Packets/MqttUnsubscribe.cs
  43. +17
    -0
      MQTT.NET.Core/Packets/TopicFilter.cs
  44. +15
    -0
      MQTT.NET.Core/Properties/AssemblyInfo.cs
  45. +12
    -0
      MQTT.NET.Core/Protocol/MqttConnectReturnCode.cs
  46. +20
    -0
      MQTT.NET.Core/Protocol/MqttControlPacketType.cs
  47. +9
    -0
      MQTT.NET.Core/Protocol/MqttQualityOfServiceLevel.cs
  48. +10
    -0
      MQTT.NET.Core/Protocol/MqttSubscribeReturnCode.cs
  49. +42
    -0
      MQTT.NET.Core/Serializer/ByteReader.cs
  50. +36
    -0
      MQTT.NET.Core/Serializer/ByteWriter.cs
  51. +632
    -0
      MQTT.NET.Core/Serializer/DefaultMqttV311PacketSerializer.cs
  52. +13
    -0
      MQTT.NET.Core/Serializer/IMqttPacketSerializer.cs
  53. +130
    -0
      MQTT.NET.Core/Serializer/MqttPacketReader.cs
  54. +107
    -0
      MQTT.NET.Core/Serializer/MqttPacketWriter.cs
  55. +11
    -0
      MQTT.NET.Core/TaskExtensions.cs
  56. +6
    -0
      MQTT.NET.TestConsole/App.config
  57. +71
    -0
      MQTT.NET.TestConsole/MQTTnet.TestConsole.csproj
  58. +109
    -0
      MQTT.NET.TestConsole/Program.cs
  59. +15
    -0
      MQTT.NET.TestConsole/Properties/AssemblyInfo.cs
  60. +56
    -0
      MQTTnet.NET/MQTTnet.NETFramework.csproj
  61. +17
    -0
      MQTTnet.NET/MqttClientFactory.cs
  62. +46
    -0
      MQTTnet.NET/MqttTcpChannel.cs
  63. +15
    -0
      MQTTnet.NET/Properties/AssemblyInfo.cs
  64. +132
    -0
      MQTTnet.Universal/MQTTnet.Universal.csproj
  65. +17
    -0
      MQTTnet.Universal/MqttClientFactory.cs
  66. +52
    -0
      MQTTnet.Universal/MqttTcpChannel.cs
  67. +14
    -0
      MQTTnet.Universal/Properties/AssemblyInfo.cs
  68. +33
    -0
      MQTTnet.Universal/Properties/MQTTnet.Universal.rd.xml
  69. +16
    -0
      MQTTnet.Universal/project.json
  70. +112
    -0
      MQTTnet.sln

+ 63
- 0
.gitattributes 查看文件

@@ -0,0 +1,63 @@
###############################################################################
# Set default behavior to automatically normalize line endings.
###############################################################################
* text=auto

###############################################################################
# Set default behavior for command prompt diff.
#
# This is need for earlier builds of msysgit that does not have it on by
# default for csharp files.
# Note: This is only used by command line
###############################################################################
#*.cs diff=csharp

###############################################################################
# Set the merge driver for project and solution files
#
# Merging from the command prompt will add diff markers to the files if there
# are conflicts (Merging from VS is not affected by the settings below, in VS
# the diff markers are never inserted). Diff markers may cause the following
# file extensions to fail to load in VS. An alternative would be to treat
# these files as binary and thus will always conflict and require user
# intervention with every merge. To do so, just uncomment the entries below
###############################################################################
#*.sln merge=binary
#*.csproj merge=binary
#*.vbproj merge=binary
#*.vcxproj merge=binary
#*.vcproj merge=binary
#*.dbproj merge=binary
#*.fsproj merge=binary
#*.lsproj merge=binary
#*.wixproj merge=binary
#*.modelproj merge=binary
#*.sqlproj merge=binary
#*.wwaproj merge=binary

###############################################################################
# behavior for image files
#
# image files are treated as binary by default.
###############################################################################
#*.jpg binary
#*.png binary
#*.gif binary

###############################################################################
# diff behavior for common document formats
#
# Convert binary document formats to text before diffing them. This feature
# is only available from the command line. Turn it on by uncommenting the
# entries below.
###############################################################################
#*.doc diff=astextplain
#*.DOC diff=astextplain
#*.docx diff=astextplain
#*.DOCX diff=astextplain
#*.dot diff=astextplain
#*.DOT diff=astextplain
#*.pdf diff=astextplain
#*.PDF diff=astextplain
#*.rtf diff=astextplain
#*.RTF diff=astextplain

二進制
查看文件


+ 30
- 0
MQTT.NET.Core.Tests/ByteReaderTests.cs 查看文件

@@ -0,0 +1,30 @@
using Microsoft.VisualStudio.TestTools.UnitTesting;
using MQTTnet.Core.Serializer;

namespace MQTTnet.Core.Tests
{
[TestClass]
public class ByteReaderTests
{
[TestMethod]
public void ByteReader_ReadToEnd()
{
var reader = new ByteReader(85);
Assert.IsTrue(reader.Read());
Assert.IsFalse(reader.Read());
Assert.IsTrue(reader.Read());
Assert.IsFalse(reader.Read());
Assert.IsTrue(reader.Read());
Assert.IsFalse(reader.Read());
Assert.IsTrue(reader.Read());
Assert.IsFalse(reader.Read());
}

[TestMethod]
public void ByteReader_ReadPartial()
{
var reader = new ByteReader(15);
Assert.AreEqual(3, reader.Read(2));
}
}
}

+ 51
- 0
MQTT.NET.Core.Tests/ByteWriterTests.cs 查看文件

@@ -0,0 +1,51 @@
using Microsoft.VisualStudio.TestTools.UnitTesting;
using MQTTnet.Core.Serializer;

namespace MQTTnet.Core.Tests
{
[TestClass]
public class ByteWriterTests
{
[TestMethod]
public void ByteWriter_WriteMultipleAll()
{
var b = new ByteWriter();
Assert.AreEqual(0, b.Value);
b.Write(3, 2);
Assert.AreEqual(3, b.Value);
}

[TestMethod]
public void ByteWriter_WriteMultiplePartial()
{
var b = new ByteWriter();
Assert.AreEqual(0, b.Value);
b.Write(255, 2);
Assert.AreEqual(3, b.Value);
}

[TestMethod]
public void ByteWriter_WriteTo0xFF()
{
var b = new ByteWriter();

Assert.AreEqual(0, b.Value);
b.Write(true);
Assert.AreEqual(1, b.Value);
b.Write(true);
Assert.AreEqual(3, b.Value);
b.Write(true);
Assert.AreEqual(7, b.Value);
b.Write(true);
Assert.AreEqual(15, b.Value);
b.Write(true);
Assert.AreEqual(31, b.Value);
b.Write(true);
Assert.AreEqual(63, b.Value);
b.Write(true);
Assert.AreEqual(127, b.Value);
b.Write(true);
Assert.AreEqual(255, b.Value);
}
}
}

+ 434
- 0
MQTT.NET.Core.Tests/DefaultMqttV311PacketSerializerTests.cs 查看文件

@@ -0,0 +1,434 @@
using System;
using System.IO;
using System.Text;
using System.Threading.Tasks;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using MQTTnet.Core.Channel;
using MQTTnet.Core.Client;
using MQTTnet.Core.Packets;
using MQTTnet.Core.Protocol;
using MQTTnet.Core.Serializer;

namespace MQTTnet.Core.Tests
{
[TestClass]
public class DefaultMqttV311PacketSerializerTests
{
[TestMethod]
public void SerializeV311_MqttConnectPacket()
{
var p = new MqttConnectPacket
{
ClientId = "XYZ",
Password = "PASS",
Username = "USER",
KeepAlivePeriod = 123,
CleanSession = true
};

SerializeAndCompare(p, "EBsABE1RVFQEwgB7AANYWVoABFVTRVIABFBBU1M=");
}

[TestMethod]
public void SerializeV311_MqttConnectPacketWithWillMessage()
{
var p = new MqttConnectPacket
{
ClientId = "XYZ",
Password = "PASS",
Username = "USER",
KeepAlivePeriod = 123,
CleanSession = true,
WillMessage = new MqttApplicationMessage(
"My/last/will",
Encoding.UTF8.GetBytes("Good byte."),
MqttQualityOfServiceLevel.AtLeastOnce,
true)
};

SerializeAndCompare(p, "EDUABE1RVFQE7gB7AANYWVoADE15L2xhc3Qvd2lsbAAKR29vZCBieXRlLgAEVVNFUgAEUEFTUw==");
}

[TestMethod]
public void DeserializeV311_MqttConnectPacket()
{
var p = new MqttConnectPacket
{
ClientId = "XYZ",
Password = "PASS",
Username = "USER",
KeepAlivePeriod = 123,
CleanSession = true
};

DeserializeAndCompare(p, "EBsABE1RVFQEwgB7AANYWVoABFVTRVIABFBBU1M=");
}

[TestMethod]
public void DeserializeV311_MqttConnectPacketWithWillMessage()
{
var p = new MqttConnectPacket
{
ClientId = "XYZ",
Password = "PASS",
Username = "USER",
KeepAlivePeriod = 123,
CleanSession = true,
WillMessage = new MqttApplicationMessage(
"My/last/will",
Encoding.UTF8.GetBytes("Good byte."),
MqttQualityOfServiceLevel.AtLeastOnce,
true)
};

DeserializeAndCompare(p, "EDUABE1RVFQE7gB7AANYWVoADE15L2xhc3Qvd2lsbAAKR29vZCBieXRlLgAEVVNFUgAEUEFTUw==");
}

[TestMethod]
public void SerializeV311_MqttConnAckPacket()
{
var p = new MqttConnAckPacket
{
IsSessionPresent = true,
ConnectReturnCode = MqttConnectReturnCode.ConnectionRefusedNotAuthorized
};

SerializeAndCompare(p, "IAIBBQ==");
}

[TestMethod]
public void DeserializeV311_MqttConnAckPacket()
{
var p = new MqttConnAckPacket
{
IsSessionPresent = true,
ConnectReturnCode = MqttConnectReturnCode.ConnectionRefusedNotAuthorized
};

DeserializeAndCompare(p, "IAIBBQ==");
}

[TestMethod]
public void SerializeV311_MqttDisconnectPacket()
{
SerializeAndCompare(new MqttDisconnectPacket(), "4AA=");
}

[TestMethod]
public void SerializeV311_MqttPingReqPacket()
{
SerializeAndCompare(new MqttPingReqPacket(), "wAA=");
}

[TestMethod]
public void SerializeV311_MqttPingRespPacket()
{
SerializeAndCompare(new MqttPingRespPacket(), "0AA=");
}

[TestMethod]
public void SerializeV311_MqttPublishPacket()
{
var p = new MqttPublishPacket
{
PacketIdentifier = 123,
Dup = true,
Retain = true,
Payload = Encoding.ASCII.GetBytes("HELLO"),
QualityOfServiceLevel = MqttQualityOfServiceLevel.AtLeastOnce,
Topic = "A/B/C"
};

SerializeAndCompare(p, "Ow4ABUEvQi9DAHtIRUxMTw==");
}

[TestMethod]
public void DeserializeV311_MqttPublishPacket()
{
var p = new MqttPublishPacket
{
PacketIdentifier = 123,
Dup = true,
Retain = true,
Payload = Encoding.ASCII.GetBytes("HELLO"),
QualityOfServiceLevel = MqttQualityOfServiceLevel.AtLeastOnce,
Topic = "A/B/C"
};

DeserializeAndCompare(p, "Ow4ABUEvQi9DAHtIRUxMTw==");
}

[TestMethod]
public void SerializeV311_MqttPubAckPacket()
{
var p = new MqttPubAckPacket
{
PacketIdentifier = 123
};

SerializeAndCompare(p, "QAIAew==");
}

[TestMethod]
public void DeserializeV311_MqttPubAckPacket()
{
var p = new MqttPubAckPacket
{
PacketIdentifier = 123
};

DeserializeAndCompare(p, "QAIAew==");
}

[TestMethod]
public void SerializeV311_MqttPubRecPacket()
{
var p = new MqttPubRecPacket
{
PacketIdentifier = 123
};

SerializeAndCompare(p, "UAIAew==");
}

[TestMethod]
public void DeserializeV311_MqttPubRecPacket()
{
var p = new MqttPubRecPacket
{
PacketIdentifier = 123
};

DeserializeAndCompare(p, "UAIAew==");
}

[TestMethod]
public void SerializeV311_MqttPubRelPacket()
{
var p = new MqttPubRelPacket
{
PacketIdentifier = 123
};

SerializeAndCompare(p, "YgIAew==");
}

[TestMethod]
public void DeserializeV311_MqttPubRelPacket()
{
var p = new MqttPubRelPacket
{
PacketIdentifier = 123
};

DeserializeAndCompare(p, "YgIAew==");
}

[TestMethod]
public void SerializeV311_MqttPubCompPacket()
{
var p = new MqttPubCompPacket
{
PacketIdentifier = 123
};

SerializeAndCompare(p, "cAIAew==");
}

[TestMethod]
public void DeserializeV311_MqttPubCompPacket()
{
var p = new MqttPubCompPacket
{
PacketIdentifier = 123
};

DeserializeAndCompare(p, "cAIAew==");
}

[TestMethod]
public void SerializeV311_MqttSubscribePacket()
{
var p = new MqttSubscribePacket
{
PacketIdentifier = 123
};

p.TopicFilters.Add(new TopicFilter("A/B/C", MqttQualityOfServiceLevel.ExactlyOnce));
p.TopicFilters.Add(new TopicFilter("1/2/3", MqttQualityOfServiceLevel.AtLeastOnce));
p.TopicFilters.Add(new TopicFilter("x/y/z", MqttQualityOfServiceLevel.AtMostOnce));

SerializeAndCompare(p, "ghoAewAFQS9CL0MCAAUxLzIvMwEABXgveS96AA==");
}

[TestMethod]
public void DeserializeV311_MqttSubscribePacket()
{
var p = new MqttSubscribePacket
{
PacketIdentifier = 123
};

p.TopicFilters.Add(new TopicFilter("A/B/C", MqttQualityOfServiceLevel.ExactlyOnce));
p.TopicFilters.Add(new TopicFilter("1/2/3", MqttQualityOfServiceLevel.AtLeastOnce));
p.TopicFilters.Add(new TopicFilter("x/y/z", MqttQualityOfServiceLevel.AtMostOnce));

DeserializeAndCompare(p, "ghoAewAFQS9CL0MCAAUxLzIvMwEABXgveS96AA==");
}

[TestMethod]
public void SerializeV311_MqttSubAckPacket()
{
var p = new MqttSubAckPacket
{
PacketIdentifier = 123
};

p.SubscribeReturnCodes.Add(MqttSubscribeReturnCode.SuccessMaximumQoS0);
p.SubscribeReturnCodes.Add(MqttSubscribeReturnCode.SuccessMaximumQoS1);
p.SubscribeReturnCodes.Add(MqttSubscribeReturnCode.SuccessMaximumQoS2);
p.SubscribeReturnCodes.Add(MqttSubscribeReturnCode.Failure);

SerializeAndCompare(p, "kAYAewABAoA=");
}

[TestMethod]
public void DeserializeV311_MqttSubAckPacket()
{
var p = new MqttSubAckPacket
{
PacketIdentifier = 123
};

p.SubscribeReturnCodes.Add(MqttSubscribeReturnCode.SuccessMaximumQoS0);
p.SubscribeReturnCodes.Add(MqttSubscribeReturnCode.SuccessMaximumQoS1);
p.SubscribeReturnCodes.Add(MqttSubscribeReturnCode.SuccessMaximumQoS2);
p.SubscribeReturnCodes.Add(MqttSubscribeReturnCode.Failure);

DeserializeAndCompare(p, "kAYAewABAoA=");
}

[TestMethod]
public void SerializeV311_MqttUnsubscribePacket()
{
var p = new MqttUnsubscribePacket
{
PacketIdentifier = 123
};

p.TopicFilters.Add("A/B/C");
p.TopicFilters.Add("1/2/3");
p.TopicFilters.Add("x/y/z");

SerializeAndCompare(p, "ohcAewAFQS9CL0MABTEvMi8zAAV4L3kveg==");
}

[TestMethod]
public void DeserializeV311_MqttUnsubscribePacket()
{
var p = new MqttUnsubscribePacket
{
PacketIdentifier = 123
};

p.TopicFilters.Add("A/B/C");
p.TopicFilters.Add("1/2/3");
p.TopicFilters.Add("x/y/z");

DeserializeAndCompare(p, "ohcAewAFQS9CL0MABTEvMi8zAAV4L3kveg==");
}

[TestMethod]
public void SerializeV311_MqttUnsubAckPacket()
{
var p = new MqttUnsubAckPacket
{
PacketIdentifier = 123
};

SerializeAndCompare(p, "sAIAew==");
}

[TestMethod]
public void DeserializeV311_MqttUnsubAckPacket()
{
var p = new MqttUnsubAckPacket
{
PacketIdentifier = 123
};

DeserializeAndCompare(p, "sAIAew==");
}


public class TestChannel : IMqttTransportChannel
{
private readonly MemoryStream _stream = new MemoryStream();

public bool IsConnected { get; } = true;

public TestChannel()
{
}

public TestChannel(byte[] initialData)
{
_stream.Write(initialData, 0, initialData.Length);
_stream.Position = 0;
}

public async Task ConnectAsync(MqttClientOptions options)
{
await Task.FromResult(0);
}

public async Task DisconnectAsync()
{
await Task.FromResult(0);
}

public async Task WriteAsync(byte[] buffer)
{
await _stream.WriteAsync(buffer, 0, buffer.Length);
}

public async Task ReadAsync(byte[] buffer)
{
await _stream.ReadAsync(buffer, 0, buffer.Length);
}

public byte[] ToArray()
{
return _stream.ToArray();
}
}

private void SerializeAndCompare(MqttBasePacket packet, string expectedBase64Value)
{
var serializer = new DefaultMqttV311PacketSerializer();
var channel = new TestChannel();
serializer.SerializeAsync(packet, channel).Wait();
var buffer = channel.ToArray();

Assert.AreEqual(expectedBase64Value, Convert.ToBase64String(buffer));
}

private void DeserializeAndCompare(MqttBasePacket packet, string expectedBase64Value)
{
var serializer = new DefaultMqttV311PacketSerializer();

var channel1 = new TestChannel();
serializer.SerializeAsync(packet, channel1).Wait();
var buffer1 = channel1.ToArray();

var channel2 = new TestChannel(buffer1);
var deserializedPacket = serializer.DeserializeAsync(channel2).Result;
var buffer2 = channel2.ToArray();

var channel3 = new TestChannel(buffer2);
serializer.SerializeAsync(deserializedPacket, channel3).Wait();

Assert.AreEqual(expectedBase64Value, Convert.ToBase64String(channel3.ToArray()));
}
}
}

+ 66
- 0
MQTT.NET.Core.Tests/MQTTnet.Core.Tests.csproj 查看文件

@@ -0,0 +1,66 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{A7FF0C91-25DE-4BA6-B39E-F54E8DADF1CC}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>MQTTnet.Core.Tests</RootNamespace>
<AssemblyName>MQTTnet.Core.Tests</AssemblyName>
<TargetFrameworkVersion>v4.6.1</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<Reference Include="Microsoft.VisualStudio.QualityTools.UnitTestFramework, Version=10.1.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL" />
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Data" />
<Reference Include="System.Net.Http" />
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="ByteReaderTests.cs" />
<Compile Include="ByteWriterTests.cs" />
<Compile Include="DefaultMqttV311PacketSerializerTests.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\MQTT.NET.Core\MQTTnet.Core.csproj">
<Project>{99C884F3-B4B9-417D-AA92-DC7DD1C4CFEE}</Project>
<Name>MQTTnet.Core</Name>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
</Project>

+ 15
- 0
MQTT.NET.Core.Tests/Properties/AssemblyInfo.cs 查看文件

@@ -0,0 +1,15 @@
using System.Reflection;
using System.Runtime.InteropServices;

[assembly: AssemblyTitle("MQTTnet.Core.Tests")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("Christian Kratky")]
[assembly: AssemblyProduct("MQTTnet")]
[assembly: AssemblyCopyright("Copyright © Christian Kratky 2015-2017")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
[assembly: ComVisible(false)]
[assembly: Guid("a7ff0c91-25de-4ba6-b39e-f54e8dadf1cc")]
[assembly: AssemblyVersion("2.1.0.4")]
[assembly: AssemblyFileVersion("2.1.0.4")]

+ 18
- 0
MQTT.NET.Core/Adapter/IMqttAdapter.cs 查看文件

@@ -0,0 +1,18 @@
using System;
using System.Threading.Tasks;
using MQTTnet.Core.Client;
using MQTTnet.Core.Packets;

namespace MQTTnet.Core.Adapter
{
public interface IMqttAdapter
{
Task ConnectAsync(MqttClientOptions options, TimeSpan timeout);

Task DisconnectAsync();

Task SendPacketAsync(MqttBasePacket packet, TimeSpan timeout);

Task<MqttBasePacket> ReceivePacket();
}
}

+ 72
- 0
MQTT.NET.Core/Adapter/MqttChannelAdapter.cs 查看文件

@@ -0,0 +1,72 @@
using System;
using System.Threading.Tasks;
using MQTTnet.Core.Channel;
using MQTTnet.Core.Client;
using MQTTnet.Core.Diagnostics;
using MQTTnet.Core.Exceptions;
using MQTTnet.Core.Packets;
using MQTTnet.Core.Serializer;

namespace MQTTnet.Core.Adapter
{
public class MqttChannelAdapter : IMqttAdapter
{
private readonly IMqttPacketSerializer _serializer;
private readonly IMqttTransportChannel _channel;

public MqttChannelAdapter(IMqttTransportChannel channel, IMqttPacketSerializer serializer)
{
if (channel == null) throw new ArgumentNullException(nameof(channel));
if (serializer == null) throw new ArgumentNullException(nameof(serializer));

_channel = channel;
_serializer = serializer;
}

public async Task ConnectAsync(MqttClientOptions options, TimeSpan timeout)
{
var task = _channel.ConnectAsync(options);
if (await Task.WhenAny(Task.Delay(timeout), task) != task)
{
throw new MqttCommunicationTimedOutException();
}
}

public async Task DisconnectAsync()
{
await _channel.DisconnectAsync();
}

public async Task SendPacketAsync(MqttBasePacket packet, TimeSpan timeout)
{
MqttTrace.Information(nameof(MqttChannelAdapter), $"Sending with timeout {timeout} >>> {packet}");

bool hasTimeout;
try
{
var task = _serializer.SerializeAsync(packet, _channel);
hasTimeout = await Task.WhenAny(Task.Delay(timeout), task) != task;
}
catch (Exception exception)
{
throw new MqttCommunicationException(exception);
}

if (hasTimeout)
{
throw new MqttCommunicationTimedOutException();
}
}

public async Task<MqttBasePacket> ReceivePacket()
{
var mqttPacket = await _serializer.DeserializeAsync(_channel);
if (mqttPacket == null)
{
throw new MqttProtocolViolationException("Received malformed packet.");
}

return mqttPacket;
}
}
}

+ 16
- 0
MQTT.NET.Core/Adapter/MqttConnectingFailedException.cs 查看文件

@@ -0,0 +1,16 @@
using MQTTnet.Core.Exceptions;
using MQTTnet.Core.Protocol;

namespace MQTTnet.Core.Adapter
{
public class MqttConnectingFailedException : MqttCommunicationException
{
public MqttConnectingFailedException(MqttConnectReturnCode returnCode)
: base($"Connecting with MQTT server failed ({returnCode}).")
{
ReturnCode = returnCode;
}

public MqttConnectReturnCode ReturnCode { get; }
}
}

+ 16
- 0
MQTT.NET.Core/Channel/IMqttTransportChannel.cs 查看文件

@@ -0,0 +1,16 @@
using System.Threading.Tasks;
using MQTTnet.Core.Client;

namespace MQTTnet.Core.Channel
{
public interface IMqttTransportChannel
{
Task ConnectAsync(MqttClientOptions options);

Task DisconnectAsync();

Task WriteAsync(byte[] buffer);

Task ReadAsync(byte[] buffer);
}
}

+ 350
- 0
MQTT.NET.Core/Client/MqttClient.cs 查看文件

@@ -0,0 +1,350 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using MQTTnet.Core.Adapter;
using MQTTnet.Core.Diagnostics;
using MQTTnet.Core.Exceptions;
using MQTTnet.Core.Packets;
using MQTTnet.Core.Protocol;

namespace MQTTnet.Core.Client
{
public class MqttClient
{
private readonly Dictionary<ushort, MqttPublishPacket> _pendingExactlyOncePublishPackets = new Dictionary<ushort, MqttPublishPacket>();
private readonly HashSet<ushort> _processedPublishPackets = new HashSet<ushort>();
private readonly MqttPacketDispatcher _packetDispatcher = new MqttPacketDispatcher();
private readonly MqttClientOptions _options;
private readonly IMqttAdapter _adapter;

private int _latestPacketIdentifier;
private CancellationTokenSource _cancellationTokenSource;

public MqttClient(MqttClientOptions options, IMqttAdapter adapter)
{
if (options == null) throw new ArgumentNullException(nameof(options));
if (adapter == null) throw new ArgumentNullException(nameof(adapter));

_options = options;
_adapter = adapter;
}

public event EventHandler Connected;

public event EventHandler Disconnected;

public event EventHandler<MqttApplicationMessageReceivedEventArgs> ApplicationMessageReceived;

public bool IsConnected { get; private set; }

public async Task ConnectAsync(MqttApplicationMessage willApplicationMessage = null)
{
MqttTrace.Verbose(nameof(MqttClient), "Trying to connect.");

if (IsConnected)
{
throw new MqttProtocolViolationException("It is not allowed to connect with a server after the connection is established.");
}

var connectPacket = new MqttConnectPacket
{
ClientId = _options.ClientId,
Username = _options.UserName,
Password = _options.Password,
KeepAlivePeriod = (ushort)_options.KeepAlivePeriod.TotalSeconds,
WillMessage = willApplicationMessage
};
await _adapter.ConnectAsync(_options, _options.DefaultCommunicationTimeout);
MqttTrace.Verbose(nameof(MqttClient), "Connection with server established.");

_cancellationTokenSource = new CancellationTokenSource();
_latestPacketIdentifier = 0;
_processedPublishPackets.Clear();
_packetDispatcher.Reset();
IsConnected = true;

Task.Factory.StartNew(async () => await ReceivePackets(
_cancellationTokenSource.Token), _cancellationTokenSource.Token, TaskCreationOptions.LongRunning, TaskScheduler.Default).Forget();

var response = await SendAndReceiveAsync<MqttConnAckPacket>(connectPacket, p => true);
if (response.ConnectReturnCode != MqttConnectReturnCode.ConnectionAccepted)
{
throw new MqttConnectingFailedException(response.ConnectReturnCode);
}

if (_options.KeepAlivePeriod != TimeSpan.Zero)
{
Task.Factory.StartNew(async () => await SendKeepAliveMessagesAsync(
_cancellationTokenSource.Token), _cancellationTokenSource.Token, TaskCreationOptions.LongRunning, TaskScheduler.Default).Forget();
}

Connected?.Invoke(this, EventArgs.Empty);
}

public async Task DisconnectAsync()
{
await SendAsync(new MqttDisconnectPacket());
await DisconnectInternalAsync();
}

private void ThrowIfNotConnected()
{
if (!IsConnected)
{
throw new MqttCommunicationException("The client is not connected.");
}
}

public async Task<IList<MqttSubscribeResult>> SubscribeAsync(IList<TopicFilter> topicFilters)
{
if (topicFilters == null) throw new ArgumentNullException(nameof(topicFilters));
if (!topicFilters.Any()) throw new MqttProtocolViolationException("At least one topic filter must be set [MQTT-3.8.3-3].");
ThrowIfNotConnected();

var subscribePacket = new MqttSubscribePacket
{
PacketIdentifier = GetNewPacketIdentifier(),
TopicFilters = topicFilters
};

Func<MqttSubAckPacket, bool> packetSelector = p => p.PacketIdentifier == subscribePacket.PacketIdentifier;
var response = await SendAndReceiveAsync(subscribePacket, packetSelector);

if (response.SubscribeReturnCodes.Count != topicFilters.Count)
{
throw new MqttProtocolViolationException("The return codes are not matching the topic filters [MQTT-3.9.3-1].");
}

var result = new List<MqttSubscribeResult>();
for (var i = 0; i < topicFilters.Count; i++)
{
result.Add(new MqttSubscribeResult(topicFilters[i], response.SubscribeReturnCodes[i]));
}

return result;
}

public async Task Unsubscribe(IList<string> topicFilters)
{
if (topicFilters == null) throw new ArgumentNullException(nameof(topicFilters));
if (!topicFilters.Any()) throw new MqttProtocolViolationException("At least one topic filter must be set [MQTT-3.10.3-2].");
ThrowIfNotConnected();

var unsubscribePacket = new MqttUnsubscribePacket
{
PacketIdentifier = GetNewPacketIdentifier(),
TopicFilters = topicFilters
};

Func<MqttUnsubAckPacket, bool> packetSelector = p => p.PacketIdentifier == unsubscribePacket.PacketIdentifier;
await SendAndReceiveAsync(unsubscribePacket, packetSelector);
}

public async Task PublishAsync(MqttApplicationMessage applicationMessage)
{
if (applicationMessage == null) throw new ArgumentNullException(nameof(applicationMessage));
ThrowIfNotConnected();

var publishPacket = new MqttPublishPacket
{
Topic = applicationMessage.Topic,
Payload = applicationMessage.Payload,
QualityOfServiceLevel = applicationMessage.QualityOfServiceLevel,
Retain = applicationMessage.Retain,
Dup = false
};

if (publishPacket.QualityOfServiceLevel != MqttQualityOfServiceLevel.AtMostOnce)
{
publishPacket.PacketIdentifier = GetNewPacketIdentifier();
}

if (publishPacket.QualityOfServiceLevel == MqttQualityOfServiceLevel.AtLeastOnce)
{
if (!publishPacket.PacketIdentifier.HasValue) throw new InvalidOperationException();

Func<MqttPubAckPacket, bool> packageSelector = p => p.PacketIdentifier == publishPacket.PacketIdentifier.Value;
await SendAndReceiveAsync(publishPacket, packageSelector);
}
else if (publishPacket.QualityOfServiceLevel == MqttQualityOfServiceLevel.ExactlyOnce)
{
if (!publishPacket.PacketIdentifier.HasValue) throw new InvalidOperationException();

Func<MqttPubRecPacket, bool> packageSelector = p => p.PacketIdentifier == publishPacket.PacketIdentifier.Value;
await SendAndReceiveAsync(publishPacket, packageSelector);
await SendAsync(new MqttPubCompPacket { PacketIdentifier = publishPacket.PacketIdentifier.Value });
}
}

private async Task DisconnectInternalAsync()
{
try
{
await _adapter.DisconnectAsync();
}
catch
{
}
finally
{
_cancellationTokenSource?.Cancel();
IsConnected = false;
Disconnected?.Invoke(this, EventArgs.Empty);
}
}

private async void ProcessIncomingPacket(MqttBasePacket mqttPacket)
{
var publishPacket = mqttPacket as MqttPublishPacket;
if (publishPacket != null)
{
await ProcessReceivedPublishPacket(publishPacket);
return;
}

var pingReqPacket = mqttPacket as MqttPingReqPacket;
if (pingReqPacket != null)
{
await SendAsync(new MqttPingRespPacket());
return;
}

var pubRelPacket = mqttPacket as MqttPubRelPacket;
if (pubRelPacket != null)
{
await ProcessReceivedPubRelPacket(pubRelPacket);
return;
}

_packetDispatcher.Dispatch(mqttPacket);
}

private void FireApplicationMessageReceivedEvent(MqttPublishPacket publishPacket)
{
if (publishPacket.QualityOfServiceLevel != MqttQualityOfServiceLevel.AtMostOnce)
{
if (publishPacket.PacketIdentifier == null) throw new InvalidOperationException();
_processedPublishPackets.Add(publishPacket.PacketIdentifier.Value);
}

var applicationMessage = new MqttApplicationMessage(
publishPacket.Topic,
publishPacket.Payload,
publishPacket.QualityOfServiceLevel,
publishPacket.Retain
);

ApplicationMessageReceived?.Invoke(this, new MqttApplicationMessageReceivedEventArgs(applicationMessage));
}

private async Task ProcessReceivedPubRelPacket(MqttPubRelPacket pubRelPacket)
{
var originalPublishPacket = _pendingExactlyOncePublishPackets.Take(pubRelPacket.PacketIdentifier);
if (originalPublishPacket == null) throw new MqttCommunicationException();
await SendAsync(new MqttPubCompPacket { PacketIdentifier = pubRelPacket.PacketIdentifier });

FireApplicationMessageReceivedEvent(originalPublishPacket);
}

private async Task ProcessReceivedPublishPacket(MqttPublishPacket publishPacket)
{
if (publishPacket.QualityOfServiceLevel == MqttQualityOfServiceLevel.AtMostOnce)
{
FireApplicationMessageReceivedEvent(publishPacket);
}
else
{
if (!publishPacket.PacketIdentifier.HasValue) { throw new InvalidOperationException(); }

if (publishPacket.QualityOfServiceLevel == MqttQualityOfServiceLevel.AtLeastOnce)
{
FireApplicationMessageReceivedEvent(publishPacket);
await SendAsync(new MqttPubAckPacket { PacketIdentifier = publishPacket.PacketIdentifier.Value });
}
else if (publishPacket.QualityOfServiceLevel == MqttQualityOfServiceLevel.ExactlyOnce)
{
_pendingExactlyOncePublishPackets.Add(publishPacket.PacketIdentifier.Value, publishPacket);
await SendAsync(new MqttPubRecPacket { PacketIdentifier = publishPacket.PacketIdentifier.Value });
}
}
}
private async Task SendAsync(MqttBasePacket packet)
{
await _adapter.SendPacketAsync(packet, _options.DefaultCommunicationTimeout);
}

private async Task<TResponsePacket> SendAndReceiveAsync<TResponsePacket>(
MqttBasePacket requestPacket, Func<TResponsePacket, bool> responsePacketSelector) where TResponsePacket : MqttBasePacket
{
Func<MqttBasePacket, bool> selector = p =>
{
var p1 = p as TResponsePacket;
return p1 != null && responsePacketSelector(p1);
};

return (TResponsePacket)await SendAndReceiveAsync(requestPacket, selector);
}

private async Task<MqttBasePacket> SendAndReceiveAsync(MqttBasePacket requestPacket, Func<MqttBasePacket, bool> responsePacketSelector)
{
var waitTask = _packetDispatcher.WaitForPacketAsync(responsePacketSelector, _options.DefaultCommunicationTimeout);
await _adapter.SendPacketAsync(requestPacket, _options.DefaultCommunicationTimeout);
return await waitTask;
}

private ushort GetNewPacketIdentifier()
{
return (ushort)Interlocked.Increment(ref _latestPacketIdentifier);
}

private async Task SendKeepAliveMessagesAsync(CancellationToken cancellationToken)
{
MqttTrace.Information(nameof(MqttClient), "Start sending keep alive packets.");

try
{
while (!cancellationToken.IsCancellationRequested)
{
await Task.Delay(_options.KeepAlivePeriod, cancellationToken);
await SendAndReceiveAsync<MqttPingRespPacket>(new MqttPingReqPacket(), p => true);
}
}
catch (Exception exception)
{
MqttTrace.Error(nameof(MqttClient), exception, "Error while sending keep alive packets.");
}
finally
{
MqttTrace.Information(nameof(MqttClient), "Stopped sending keep alive packets.");
}
}

private async Task ReceivePackets(CancellationToken cancellationToken)
{
MqttTrace.Information(nameof(MqttClient), "Start receiving packets.");
try
{
while (!cancellationToken.IsCancellationRequested)
{
var mqttPacket = await _adapter.ReceivePacket();
MqttTrace.Information(nameof(MqttChannelAdapter), $"Received <<< {mqttPacket}");

Task.Run(() => ProcessIncomingPacket(mqttPacket), cancellationToken).Forget();
}
}
catch (Exception exception)
{
MqttTrace.Error(nameof(MqttClient), exception, "Error while receiving packets.");
await DisconnectInternalAsync();
}
finally
{
MqttTrace.Information(nameof(MqttClient), "Stopped receiving packets.");
}
}
}
}

+ 21
- 0
MQTT.NET.Core/Client/MqttClientOptions.cs 查看文件

@@ -0,0 +1,21 @@
using System;

namespace MQTTnet.Core.Client
{
public class MqttClientOptions
{
public string Server { get; set; }

public int Port { get; set; } = 1883;

public string UserName { get; set; }

public string Password { get; set; }

public string ClientId { get; set; } = Guid.NewGuid().ToString().Replace("-", string.Empty);

public TimeSpan KeepAlivePeriod { get; set; } = TimeSpan.FromSeconds(5);

public TimeSpan DefaultCommunicationTimeout { get; set; } = TimeSpan.FromSeconds(10);
}
}

+ 7
- 0
MQTT.NET.Core/Client/MqttClientStatistics.cs 查看文件

@@ -0,0 +1,7 @@
namespace MQTTnet.Core.Client
{
public class MqttClientStatistics
{
public int SentPackets { get; set; }
}
}

+ 32
- 0
MQTT.NET.Core/Client/MqttPacketAwaiter.cs 查看文件

@@ -0,0 +1,32 @@
using System;
using System.Threading.Tasks;
using MQTTnet.Core.Packets;

namespace MQTTnet.Core.Client
{
public class MqttPacketAwaiter
{
private readonly TaskCompletionSource<MqttBasePacket> _taskCompletionSource = new TaskCompletionSource<MqttBasePacket>();
private readonly Func<MqttBasePacket, bool> _packetSelector;

public MqttPacketAwaiter(Func<MqttBasePacket, bool> packetSelector)
{
if (packetSelector == null) throw new ArgumentNullException(nameof(packetSelector));

_packetSelector = packetSelector;
}

public Task<MqttBasePacket> Task => _taskCompletionSource.Task;

public bool CheckPacket(MqttBasePacket packet)
{
if (!_packetSelector(packet))
{
return false;
}

_taskCompletionSource.SetResult(packet);
return true;
}
}
}

+ 84
- 0
MQTT.NET.Core/Client/MqttPacketDispatcher.cs 查看文件

@@ -0,0 +1,84 @@
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using MQTTnet.Core.Diagnostics;
using MQTTnet.Core.Exceptions;
using MQTTnet.Core.Packets;

namespace MQTTnet.Core.Client
{
public class MqttPacketDispatcher
{
private readonly List<MqttPacketAwaiter> _packetAwaiters = new List<MqttPacketAwaiter>();

public async Task<MqttBasePacket> WaitForPacketAsync(Func<MqttBasePacket, bool> selector, TimeSpan timeout)
{
if (selector == null) throw new ArgumentNullException(nameof(selector));

var waitHandle = new MqttPacketAwaiter(selector);
AddPacketAwaiter(waitHandle);

var hasTimeout = await Task.WhenAny(Task.Delay(timeout), waitHandle.Task) != waitHandle.Task;
RemovePacketAwaiter(waitHandle);

if (hasTimeout)
{
MqttTrace.Error(nameof(MqttPacketDispatcher), $"Timeout while waiting for packet.");
throw new MqttCommunicationTimedOutException();
}

return waitHandle.Task.Result;
}

public void Dispatch(MqttBasePacket packet)
{
if (packet == null) throw new ArgumentNullException(nameof(packet));

var packetDispatched = false;
foreach (var packetAwaiter in GetPacketAwaiters())
{
if (packetAwaiter.CheckPacket(packet))
{
packetDispatched = true;
}
}

if (!packetDispatched)
{
MqttTrace.Warning(nameof(MqttPacketDispatcher), $"Received packet '{packet}' not dispatched.");
}
}

private List<MqttPacketAwaiter> GetPacketAwaiters()
{
lock (_packetAwaiters)
{
return new List<MqttPacketAwaiter>(_packetAwaiters);
}
}

private void AddPacketAwaiter(MqttPacketAwaiter packetAwaiter)
{
lock (_packetAwaiters)
{
_packetAwaiters.Add(packetAwaiter);
}
}

private void RemovePacketAwaiter(MqttPacketAwaiter packetAwaiter)
{
lock (_packetAwaiters)
{
_packetAwaiters.Remove(packetAwaiter);
}
}

public void Reset()
{
lock (_packetAwaiters)
{
_packetAwaiters.Clear();
}
}
}
}

+ 18
- 0
MQTT.NET.Core/Client/MqttSubscribeResult.cs 查看文件

@@ -0,0 +1,18 @@
using MQTTnet.Core.Packets;
using MQTTnet.Core.Protocol;

namespace MQTTnet.Core.Client
{
public class MqttSubscribeResult
{
public MqttSubscribeResult(TopicFilter topicFilter, MqttSubscribeReturnCode returnCode)
{
TopicFilter = topicFilter;
ReturnCode = returnCode;
}

public TopicFilter TopicFilter { get; }

public MqttSubscribeReturnCode ReturnCode { get; }
}
}

+ 39
- 0
MQTT.NET.Core/Diagnostics/MqttTrace.cs 查看文件

@@ -0,0 +1,39 @@
using System;

namespace MQTTnet.Core.Diagnostics
{
public static class MqttTrace
{
public static event EventHandler<MqttTraceMessagePublishedEventArgs> TraceMessagePublished;

public static void Verbose(string source, string message)
{
TraceMessagePublished?.Invoke(null, new MqttTraceMessagePublishedEventArgs(Environment.CurrentManagedThreadId, source, MqttTraceLevel.Verbose, message, null));
}

public static void Information(string source, string message)
{
TraceMessagePublished?.Invoke(null, new MqttTraceMessagePublishedEventArgs(Environment.CurrentManagedThreadId, source, MqttTraceLevel.Information, message, null));
}

public static void Warning(string source, string message)
{
TraceMessagePublished?.Invoke(null, new MqttTraceMessagePublishedEventArgs(Environment.CurrentManagedThreadId, source, MqttTraceLevel.Warning, message, null));
}

public static void Warning(string source, Exception exception, string message)
{
TraceMessagePublished?.Invoke(null, new MqttTraceMessagePublishedEventArgs(Environment.CurrentManagedThreadId, source, MqttTraceLevel.Warning, message, exception));
}

public static void Error(string source, string message)
{
TraceMessagePublished?.Invoke(null, new MqttTraceMessagePublishedEventArgs(Environment.CurrentManagedThreadId, source, MqttTraceLevel.Error, message, null));
}

public static void Error(string source, Exception exception, string message)
{
TraceMessagePublished?.Invoke(null, new MqttTraceMessagePublishedEventArgs(Environment.CurrentManagedThreadId, source, MqttTraceLevel.Error, message, exception));
}
}
}

+ 10
- 0
MQTT.NET.Core/Diagnostics/MqttTraceLevel.cs 查看文件

@@ -0,0 +1,10 @@
namespace MQTTnet.Core.Diagnostics
{
public enum MqttTraceLevel
{
Verbose,
Information,
Warning,
Error
}
}

+ 26
- 0
MQTT.NET.Core/Diagnostics/MqttTraceMessagePublishedEventArgs.cs 查看文件

@@ -0,0 +1,26 @@
using System;

namespace MQTTnet.Core.Diagnostics
{
public class MqttTraceMessagePublishedEventArgs : EventArgs
{
public MqttTraceMessagePublishedEventArgs(int threadId, string source, MqttTraceLevel level, string message, Exception exception)
{
ThreadId = threadId;
Source = source;
Level = level;
Message = message;
Exception = exception;
}

public int ThreadId { get; }

public string Source { get; }

public MqttTraceLevel Level { get; }

public string Message { get; }

public Exception Exception { get; }
}
}

+ 21
- 0
MQTT.NET.Core/DictionaryExtensions.cs 查看文件

@@ -0,0 +1,21 @@
using System;
using System.Collections.Generic;

namespace MQTTnet.Core
{
public static class DictionaryExtensions
{
public static TValue Take<TKey, TValue>(this IDictionary<TKey, TValue> dictionary, TKey key)
{
if (dictionary == null) throw new ArgumentNullException(nameof(dictionary));

TValue value;
if (dictionary.TryGetValue(key, out value))
{
dictionary.Remove(key);
}

return value;
}
}
}

+ 21
- 0
MQTT.NET.Core/Exceptions/MqttCommunicationException.cs 查看文件

@@ -0,0 +1,21 @@
using System;

namespace MQTTnet.Core.Exceptions
{
public class MqttCommunicationException : Exception
{
public MqttCommunicationException()
{
}

public MqttCommunicationException(Exception innerException)
: base(innerException.Message, innerException)
{
}

public MqttCommunicationException(string message)
: base(message)
{
}
}
}

+ 6
- 0
MQTT.NET.Core/Exceptions/MqttCommunicationTimedOutException.cs 查看文件

@@ -0,0 +1,6 @@
namespace MQTTnet.Core.Exceptions
{
public class MqttCommunicationTimedOutException : MqttCommunicationException
{
}
}

+ 12
- 0
MQTT.NET.Core/Exceptions/MqttProtocolViolationException.cs 查看文件

@@ -0,0 +1,12 @@
using System;

namespace MQTTnet.Core.Exceptions
{
public class MqttProtocolViolationException : Exception
{
public MqttProtocolViolationException(string message) : base(message)
{

}
}
}

+ 96
- 0
MQTT.NET.Core/MQTTnet.Core.csproj 查看文件

@@ -0,0 +1,96 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<MinimumVisualStudioVersion>10.0</MinimumVisualStudioVersion>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{99C884F3-B4B9-417D-AA92-DC7DD1C4CFEE}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>MQTTnet.Core</RootNamespace>
<AssemblyName>MQTTnet.Core</AssemblyName>
<DefaultLanguage>en-US</DefaultLanguage>
<FileAlignment>512</FileAlignment>
<ProjectTypeGuids>{786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
<TargetFrameworkProfile>Profile111</TargetFrameworkProfile>
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<!-- A reference to the entire .NET Framework is automatically included -->
</ItemGroup>
<ItemGroup>
<Compile Include="Adapter\IMqttAdapter.cs" />
<Compile Include="Adapter\MqttConnectingFailedException.cs" />
<Compile Include="Adapter\MqttChannelAdapter.cs" />
<Compile Include="Channel\IMqttTransportChannel.cs" />
<Compile Include="Client\MqttClientStatistics.cs" />
<Compile Include="Client\MqttPacketDispatcher.cs" />
<Compile Include="Client\MqttSubscribeResult.cs" />
<Compile Include="Client\MqttPacketAwaiter.cs" />
<Compile Include="Diagnostics\MqttTrace.cs" />
<Compile Include="Diagnostics\MqttTraceLevel.cs" />
<Compile Include="Diagnostics\MqttTraceMessagePublishedEventArgs.cs" />
<Compile Include="DictionaryExtensions.cs" />
<Compile Include="Exceptions\MqttCommunicationException.cs" />
<Compile Include="Exceptions\MqttCommunicationTimedOutException.cs" />
<Compile Include="Exceptions\MqttProtocolViolationException.cs" />
<Compile Include="MqttApplicationMessageReceivedEventArgs.cs" />
<Compile Include="Packets\MqttConnAckPacket.cs" />
<Compile Include="Packets\MqttBasePacket.cs" />
<Compile Include="Packets\MqttConnectPacket.cs" />
<Compile Include="Packets\MqttDisconnectPacket.cs" />
<Compile Include="MqttApplicationMessage.cs" />
<Compile Include="Client\MqttClient.cs" />
<Compile Include="Client\MqttClientOptions.cs" />
<Compile Include="Packets\MqttPingReqPacket.cs" />
<Compile Include="Packets\MqttPubCompPacket.cs" />
<Compile Include="Packets\MqttUnsubAckPacket.cs" />
<Compile Include="Packets\MqttSubAckPacket.cs" />
<Compile Include="Packets\MqttPubRelPacket.cs" />
<Compile Include="Packets\MqttPingRespPacket.cs" />
<Compile Include="Packets\MqttPubAckPacket.cs" />
<Compile Include="Packets\MqttPublishPacket.cs" />
<Compile Include="Packets\MqttPubRecPacket.cs" />
<Compile Include="Packets\MqttUnsubscribe.cs" />
<Compile Include="Packets\MqttSubscribePacket.cs" />
<Compile Include="Packets\TopicFilter.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Protocol\MqttConnectReturnCode.cs" />
<Compile Include="Protocol\MqttControlPacketType.cs" />
<Compile Include="Protocol\MqttQualityOfServiceLevel.cs" />
<Compile Include="Protocol\MqttSubscribeReturnCode.cs" />
<Compile Include="Serializer\ByteReader.cs" />
<Compile Include="Serializer\ByteWriter.cs" />
<Compile Include="Serializer\DefaultMqttV311PacketSerializer.cs" />
<Compile Include="Serializer\IMqttPacketSerializer.cs" />
<Compile Include="Serializer\MqttPacketReader.cs" />
<Compile Include="Serializer\MqttPacketWriter.cs" />
<Compile Include="TaskExtensions.cs" />
</ItemGroup>
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\Portable\$(TargetFrameworkVersion)\Microsoft.Portable.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
</Project>

+ 27
- 0
MQTT.NET.Core/MqttApplicationMessage.cs 查看文件

@@ -0,0 +1,27 @@
using System;
using MQTTnet.Core.Protocol;

namespace MQTTnet.Core
{
public class MqttApplicationMessage
{
public MqttApplicationMessage(string topic, byte[] payload, MqttQualityOfServiceLevel qualityOfServiceLevel, bool retain)
{
if (topic == null) throw new ArgumentNullException(nameof(topic));
if (payload == null) throw new ArgumentNullException(nameof(payload));

Topic = topic;
Payload = payload;
QualityOfServiceLevel = qualityOfServiceLevel;
Retain = retain;
}

public string Topic { get; }

public byte[] Payload { get; }

public MqttQualityOfServiceLevel QualityOfServiceLevel { get; }

public bool Retain { get; }
}
}

+ 16
- 0
MQTT.NET.Core/MqttApplicationMessageReceivedEventArgs.cs 查看文件

@@ -0,0 +1,16 @@
using System;

namespace MQTTnet.Core
{
public class MqttApplicationMessageReceivedEventArgs : EventArgs
{
public MqttApplicationMessageReceivedEventArgs(MqttApplicationMessage applicationMessage)
{
if (applicationMessage == null) throw new ArgumentNullException(nameof(applicationMessage));

ApplicationMessage = applicationMessage;
}

public MqttApplicationMessage ApplicationMessage { get; }
}
}

+ 6
- 0
MQTT.NET.Core/Packets/MqttBasePacket.cs 查看文件

@@ -0,0 +1,6 @@
namespace MQTTnet.Core.Packets
{
public abstract class MqttBasePacket
{
}
}

+ 16
- 0
MQTT.NET.Core/Packets/MqttConnAckPacket.cs 查看文件

@@ -0,0 +1,16 @@
using MQTTnet.Core.Protocol;

namespace MQTTnet.Core.Packets
{
public class MqttConnAckPacket : MqttBasePacket
{
public bool IsSessionPresent { get; set; }

public MqttConnectReturnCode ConnectReturnCode { get; set; }

public override string ToString()
{
return $"{nameof(MqttConnAckPacket)}: [ConnectReturnCode={ConnectReturnCode}] [IsSessionPresent={IsSessionPresent}]";
}
}
}

+ 17
- 0
MQTT.NET.Core/Packets/MqttConnectPacket.cs 查看文件

@@ -0,0 +1,17 @@
namespace MQTTnet.Core.Packets
{
public class MqttConnectPacket: MqttBasePacket
{
public string ClientId { get; set; }

public string Username { get; set; }

public string Password { get; set; }

public ushort KeepAlivePeriod { get; set; }

public bool CleanSession { get; set; }

public MqttApplicationMessage WillMessage { get; set; }
}
}

+ 6
- 0
MQTT.NET.Core/Packets/MqttDisconnectPacket.cs 查看文件

@@ -0,0 +1,6 @@
namespace MQTTnet.Core.Packets
{
public class MqttDisconnectPacket : MqttBasePacket
{
}
}

+ 12
- 0
MQTT.NET.Core/Packets/MqttPingReqPacket.cs 查看文件

@@ -0,0 +1,12 @@
using System.Xml;

namespace MQTTnet.Core.Packets
{
public class MqttPingReqPacket : MqttBasePacket
{
public override string ToString()
{
return nameof(MqttPingReqPacket);
}
}
}

+ 10
- 0
MQTT.NET.Core/Packets/MqttPingRespPacket.cs 查看文件

@@ -0,0 +1,10 @@
namespace MQTTnet.Core.Packets
{
public class MqttPingRespPacket : MqttBasePacket
{
public override string ToString()
{
return nameof(MqttPingRespPacket);
}
}
}

+ 7
- 0
MQTT.NET.Core/Packets/MqttPubAckPacket.cs 查看文件

@@ -0,0 +1,7 @@
namespace MQTTnet.Core.Packets
{
public class MqttPubAckPacket : MqttBasePacket
{
public ushort PacketIdentifier { get; set; }
}
}

+ 7
- 0
MQTT.NET.Core/Packets/MqttPubCompPacket.cs 查看文件

@@ -0,0 +1,7 @@
namespace MQTTnet.Core.Packets
{
public class MqttPubCompPacket : MqttBasePacket
{
public ushort PacketIdentifier { get; set; }
}
}

+ 7
- 0
MQTT.NET.Core/Packets/MqttPubRecPacket.cs 查看文件

@@ -0,0 +1,7 @@
namespace MQTTnet.Core.Packets
{
public class MqttPubRecPacket : MqttBasePacket
{
public ushort PacketIdentifier { get; set; }
}
}

+ 7
- 0
MQTT.NET.Core/Packets/MqttPubRelPacket.cs 查看文件

@@ -0,0 +1,7 @@
namespace MQTTnet.Core.Packets
{
public class MqttPubRelPacket : MqttBasePacket
{
public ushort PacketIdentifier { get; set; }
}
}

+ 19
- 0
MQTT.NET.Core/Packets/MqttPublishPacket.cs 查看文件

@@ -0,0 +1,19 @@
using MQTTnet.Core.Protocol;

namespace MQTTnet.Core.Packets
{
public class MqttPublishPacket : MqttBasePacket
{
public ushort? PacketIdentifier { get; set; }

public bool Retain { get; set; }

public MqttQualityOfServiceLevel QualityOfServiceLevel { get; set; }

public bool Dup { get; set; }

public string Topic { get; set; }

public byte[] Payload { get; set; }
}
}

+ 12
- 0
MQTT.NET.Core/Packets/MqttSubAckPacket.cs 查看文件

@@ -0,0 +1,12 @@
using System.Collections.Generic;
using MQTTnet.Core.Protocol;

namespace MQTTnet.Core.Packets
{
public class MqttSubAckPacket : MqttBasePacket
{
public ushort PacketIdentifier { get; set; }

public List<MqttSubscribeReturnCode> SubscribeReturnCodes { get; set; } = new List<MqttSubscribeReturnCode>();
}
}

+ 11
- 0
MQTT.NET.Core/Packets/MqttSubscribePacket.cs 查看文件

@@ -0,0 +1,11 @@
using System.Collections.Generic;

namespace MQTTnet.Core.Packets
{
public class MqttSubscribePacket : MqttBasePacket
{
public ushort PacketIdentifier { get; set; }
public IList<TopicFilter> TopicFilters { get; set; } = new List<TopicFilter>();
}
}

+ 7
- 0
MQTT.NET.Core/Packets/MqttUnsubAckPacket.cs 查看文件

@@ -0,0 +1,7 @@
namespace MQTTnet.Core.Packets
{
public class MqttUnsubAckPacket : MqttBasePacket
{
public ushort PacketIdentifier { get; set; }
}
}

+ 11
- 0
MQTT.NET.Core/Packets/MqttUnsubscribe.cs 查看文件

@@ -0,0 +1,11 @@
using System.Collections.Generic;

namespace MQTTnet.Core.Packets
{
public class MqttUnsubscribePacket : MqttBasePacket
{
public ushort PacketIdentifier { get; set; }
public IList<string> TopicFilters { get; set; } = new List<string>();
}
}

+ 17
- 0
MQTT.NET.Core/Packets/TopicFilter.cs 查看文件

@@ -0,0 +1,17 @@
using MQTTnet.Core.Protocol;

namespace MQTTnet.Core.Packets
{
public class TopicFilter
{
public TopicFilter(string topic, MqttQualityOfServiceLevel qualityOfServiceLevel)
{
Topic = topic;
QualityOfServiceLevel = qualityOfServiceLevel;
}

public string Topic { get; }

public MqttQualityOfServiceLevel QualityOfServiceLevel { get; }
}
}

+ 15
- 0
MQTT.NET.Core/Properties/AssemblyInfo.cs 查看文件

@@ -0,0 +1,15 @@
using System.Reflection;
using System.Runtime.InteropServices;

[assembly: AssemblyTitle("MQTTnet.Core")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("Christian Kratky")]
[assembly: AssemblyProduct("MQTTnet")]
[assembly: AssemblyCopyright("Copyright © Christian Kratky 2016-2017")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
[assembly: ComVisible(false)]
[assembly: Guid("0e10d0ea-8e4b-4903-ab9e-93a187d07922")]
[assembly: AssemblyVersion("2.1.0.4")]
[assembly: AssemblyFileVersion("2.1.0.4")]

+ 12
- 0
MQTT.NET.Core/Protocol/MqttConnectReturnCode.cs 查看文件

@@ -0,0 +1,12 @@
namespace MQTTnet.Core.Protocol
{
public enum MqttConnectReturnCode
{
ConnectionAccepted = 0x00,
ConnectionRefusedUnacceptableProtocolVersion = 0x01,
ConnectionRefusedIdentifierRejected = 0x02,
ConnectionRefusedServerUnavailable = 0x03,
ConnectionRefusedBadUsernameOrPassword = 0x04,
ConnectionRefusedNotAuthorized = 0x05
}
}

+ 20
- 0
MQTT.NET.Core/Protocol/MqttControlPacketType.cs 查看文件

@@ -0,0 +1,20 @@
namespace MQTTnet.Core.Protocol
{
public enum MqttControlPacketType
{
Connect = 1,
ConnAck = 2,
Publish = 3,
PubAck = 4,
PubRec = 5,
PubRel = 6,
PubComp = 7,
Subscribe = 8,
SubAck = 9,
Unsubscibe = 10,
UnsubAck = 11,
PingReq = 12,
PingResp = 13,
Disconnect = 14
}
}

+ 9
- 0
MQTT.NET.Core/Protocol/MqttQualityOfServiceLevel.cs 查看文件

@@ -0,0 +1,9 @@
namespace MQTTnet.Core.Protocol
{
public enum MqttQualityOfServiceLevel
{
AtMostOnce = 0x00,
AtLeastOnce = 0x01,
ExactlyOnce = 0x02
}
}

+ 10
- 0
MQTT.NET.Core/Protocol/MqttSubscribeReturnCode.cs 查看文件

@@ -0,0 +1,10 @@
namespace MQTTnet.Core.Protocol
{
public enum MqttSubscribeReturnCode
{
SuccessMaximumQoS0 = 0x00,
SuccessMaximumQoS1 = 0x01,
SuccessMaximumQoS2 = 0x02,
Failure = 0x80
}
}

+ 42
- 0
MQTT.NET.Core/Serializer/ByteReader.cs 查看文件

@@ -0,0 +1,42 @@
using System;

namespace MQTTnet.Core.Serializer
{
public class ByteReader
{
private int _index;
private readonly int _byte;

public ByteReader(byte @byte)
{
_byte = @byte;
}

public bool Read()
{
if (_index >= 8)
{
throw new InvalidOperationException("End of the byte reached.");
}

var result = ((1 << _index) & _byte) > 0;
_index++;

return result;
}

public byte Read(int count)
{
var result = 0;
for (var i = 0; i < count; i++)
{
if (Read())
{
result |= 1 << i;
}
}

return (byte)result;
}
}
}

+ 36
- 0
MQTT.NET.Core/Serializer/ByteWriter.cs 查看文件

@@ -0,0 +1,36 @@
using System;

namespace MQTTnet.Core.Serializer
{
public class ByteWriter
{
private int _index;
private int _byte;

public byte Value => (byte)_byte;

public void Write(byte @byte, int count)
{
for (var i = 0; i < count; i++)
{
var value = ((1 << i) & @byte) > 0;
Write(value);
}
}

public void Write(bool bit)
{
if (_index >= 8)
{
throw new InvalidOperationException("End of the byte reached.");
}

if (bit)
{
_byte |= 1 << _index;
}

_index++;
}
}
}

+ 632
- 0
MQTT.NET.Core/Serializer/DefaultMqttV311PacketSerializer.cs 查看文件

@@ -0,0 +1,632 @@
using System;
using System.Linq;
using System.Net;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using MQTTnet.Core.Channel;
using MQTTnet.Core.Exceptions;
using MQTTnet.Core.Packets;
using MQTTnet.Core.Protocol;

namespace MQTTnet.Core.Serializer
{
public class DefaultMqttV311PacketSerializer : IMqttPacketSerializer
{
public async Task SerializeAsync(MqttBasePacket packet, IMqttTransportChannel destination)
{
if (packet == null) throw new ArgumentNullException(nameof(packet));
if (destination == null) throw new ArgumentNullException(nameof(destination));

var connectPacket = packet as MqttConnectPacket;
if (connectPacket != null)
{
await SerializeAsync(connectPacket, destination);
return;
}

var connAckPacket = packet as MqttConnAckPacket;
if (connAckPacket != null)
{
await SerializeAsync(connAckPacket, destination);
return;
}

var disconnectPacket = packet as MqttDisconnectPacket;
if (disconnectPacket != null)
{
await SerializeAsync(disconnectPacket, destination);
return;
}

var pingReqPacket = packet as MqttPingReqPacket;
if (pingReqPacket != null)
{
await SerializeAsync(pingReqPacket, destination);
return;
}

var pingRespPacket = packet as MqttPingRespPacket;
if (pingRespPacket != null)
{
await SerializeAsync(pingRespPacket, destination);
return;
}

var publishPacket = packet as MqttPublishPacket;
if (publishPacket != null)
{
await SerializeAsync(publishPacket, destination);
return;
}

var pubAckPacket = packet as MqttPubAckPacket;
if (pubAckPacket != null)
{
await SerializeAsync(pubAckPacket, destination);
return;
}

var pubRecPacket = packet as MqttPubRecPacket;
if (pubRecPacket != null)
{
await SerializeAsync(pubRecPacket, destination);
return;
}

var pubRelPacket = packet as MqttPubRelPacket;
if (pubRelPacket != null)
{
await SerializeAsync(pubRelPacket, destination);
return;
}

var pubCompPacket = packet as MqttPubCompPacket;
if (pubCompPacket != null)
{
await SerializeAsync(pubCompPacket, destination);
return;
}

var subscribePacket = packet as MqttSubscribePacket;
if (subscribePacket != null)
{
await SerializeAsync(subscribePacket, destination);
return;
}

var subAckPacket = packet as MqttSubAckPacket;
if (subAckPacket != null)
{
await SerializeAsync(subAckPacket, destination);
return;
}

var unsubscribePacket = packet as MqttUnsubscribePacket;
if (unsubscribePacket != null)
{
await SerializeAsync(unsubscribePacket, destination);
return;
}

var unsubAckPacket = packet as MqttUnsubAckPacket;
if (unsubAckPacket != null)
{
await SerializeAsync(unsubAckPacket, destination);
return;
}

throw new MqttProtocolViolationException("Packet type invalid.");
}

public async Task<MqttBasePacket> DeserializeAsync(IMqttTransportChannel source)
{
using (var mqttPacketReader = new MqttPacketReader(source))
{
await mqttPacketReader.ReadToEndAsync();

switch (mqttPacketReader.ControlPacketType)
{
case MqttControlPacketType.Connect:
{
return await DeserializeConnectAsync(mqttPacketReader);
}

case MqttControlPacketType.ConnAck:
{
return await DeserializeConnAck(mqttPacketReader);
}

case MqttControlPacketType.Disconnect:
{
return new MqttDisconnectPacket();
}

case MqttControlPacketType.Publish:
{
return await DeserializePublishAsync(mqttPacketReader);
}

case MqttControlPacketType.PubAck:
{
return new MqttPubAckPacket
{
PacketIdentifier = await mqttPacketReader.ReadRemainingDataUShortAsync()
};
}

case MqttControlPacketType.PubRec:
{
return new MqttPubRecPacket
{
PacketIdentifier = await mqttPacketReader.ReadRemainingDataUShortAsync()
};
}

case MqttControlPacketType.PubRel:
{
return new MqttPubRelPacket
{
PacketIdentifier = await mqttPacketReader.ReadRemainingDataUShortAsync()
};
}

case MqttControlPacketType.PubComp:
{
return new MqttPubCompPacket
{
PacketIdentifier = await mqttPacketReader.ReadRemainingDataUShortAsync()
};
}

case MqttControlPacketType.PingReq:
{
return new MqttPingReqPacket();
}

case MqttControlPacketType.PingResp:
{
return new MqttPingRespPacket();
}

case MqttControlPacketType.Subscribe:
{
return await DeserializeSubscribeAsync(mqttPacketReader);
}

case MqttControlPacketType.SubAck:
{
return await DeserializeSubAck(mqttPacketReader);
}

case MqttControlPacketType.Unsubscibe:
{
return await DeserializeUnsubscribeAsync(mqttPacketReader);
}

case MqttControlPacketType.UnsubAck:
{
return new MqttUnsubAckPacket
{
PacketIdentifier = await mqttPacketReader.ReadRemainingDataUShortAsync()
};
}
}
}

throw new ProtocolViolationException();
}

private async Task<MqttBasePacket> DeserializeUnsubscribeAsync(MqttPacketReader reader)
{
var packet = new MqttUnsubscribePacket
{
PacketIdentifier = await reader.ReadRemainingDataUShortAsync(),
};

while (!reader.EndOfRemainingData)
{
packet.TopicFilters.Add(await reader.ReadRemainingDataStringWithLengthPrefixAsync());
}

return packet;
}

private async Task<MqttBasePacket> DeserializeSubscribeAsync(MqttPacketReader reader)
{
var packet = new MqttSubscribePacket
{
PacketIdentifier = await reader.ReadRemainingDataUShortAsync(),
};

while (!reader.EndOfRemainingData)
{
packet.TopicFilters.Add(new TopicFilter(
await reader.ReadRemainingDataStringWithLengthPrefixAsync(),
(MqttQualityOfServiceLevel)await reader.ReadRemainingDataByteAsync()));
}

return packet;
}

private async Task<MqttBasePacket> DeserializePublishAsync(MqttPacketReader reader)
{
var fixedHeader = new ByteReader(reader.FixedHeader);
var retain = fixedHeader.Read();
var qualityOfServiceLevel = (MqttQualityOfServiceLevel)fixedHeader.Read(2);
var dup = fixedHeader.Read();

var topic = await reader.ReadRemainingDataStringWithLengthPrefixAsync();

ushort? packetIdentifier = null;
if (qualityOfServiceLevel > 0)
{
packetIdentifier = await reader.ReadRemainingDataUShortAsync();
}

var packet = new MqttPublishPacket
{
Retain = retain,
QualityOfServiceLevel = qualityOfServiceLevel,
Dup = dup,
Topic = topic,
Payload = await reader.ReadRemainingDataAsync(),
PacketIdentifier = packetIdentifier
};

return packet;
}

private async Task<MqttBasePacket> DeserializeConnectAsync(MqttPacketReader reader)
{
var packet = new MqttConnectPacket();

await reader.ReadRemainingDataByteAsync();
await reader.ReadRemainingDataByteAsync();
var protocolName = await reader.ReadRemainingDataAsync(4);

if (Encoding.UTF8.GetString(protocolName, 0, protocolName.Length) != "MQTT")
{
throw new ProtocolViolationException("Protocol name is not 'MQTT'.");
}

var protocolLevel = await reader.ReadRemainingDataByteAsync();
var connectFlags = await reader.ReadRemainingDataByteAsync();

var connectFlagsReader = new ByteReader(connectFlags);
connectFlagsReader.Read(); // Reserved.
packet.CleanSession = connectFlagsReader.Read();
var willFlag = connectFlagsReader.Read();
var willQoS = connectFlagsReader.Read(2);
var willRetain = connectFlagsReader.Read();
var passwordFlag = connectFlagsReader.Read();
var usernameFlag = connectFlagsReader.Read();

packet.KeepAlivePeriod = await reader.ReadRemainingDataUShortAsync();
packet.ClientId = await reader.ReadRemainingDataStringWithLengthPrefixAsync();

if (willFlag)
{
packet.WillMessage = new MqttApplicationMessage(
await reader.ReadRemainingDataStringWithLengthPrefixAsync(),
await reader.ReadRemainingDataWithLengthPrefixAsync(),
(MqttQualityOfServiceLevel)willQoS,
willRetain);
}

if (usernameFlag)
{
packet.Username = await reader.ReadRemainingDataStringWithLengthPrefixAsync();
}

if (passwordFlag)
{
packet.Password = await reader.ReadRemainingDataStringWithLengthPrefixAsync();
}

ValidateConnectPacket(packet);
return packet;
}

private async Task<MqttBasePacket> DeserializeSubAck(MqttPacketReader reader)
{
var packet = new MqttSubAckPacket
{
PacketIdentifier = await reader.ReadRemainingDataUShortAsync()
};

while (!reader.EndOfRemainingData)
{
packet.SubscribeReturnCodes.Add((MqttSubscribeReturnCode)await reader.ReadRemainingDataByteAsync());
}

return packet;
}

private async Task<MqttBasePacket> DeserializeConnAck(MqttPacketReader reader)
{
var variableHeader1 = await reader.ReadRemainingDataByteAsync();
var variableHeader2 = await reader.ReadRemainingDataByteAsync();

var packet = new MqttConnAckPacket
{
IsSessionPresent = new ByteReader(variableHeader1).Read(),
ConnectReturnCode = (MqttConnectReturnCode)variableHeader2
};

return packet;
}

private void ValidateConnectPacket(MqttConnectPacket packet)
{
if (string.IsNullOrEmpty(packet.ClientId) && !packet.CleanSession)
{
throw new ProtocolViolationException("CleanSession must be set if ClientId is empty [MQTT-3.1.3-7].");
}

if (!string.IsNullOrEmpty(packet.ClientId) && !Regex.IsMatch(packet.ClientId, "^[a-zA-Z0-9]*$"))
{
throw new ProtocolViolationException("ClientId contains invalid characters [MQTT-3.1.3-5].");
}
}

private void ValidatePublishPacket(MqttPublishPacket packet)
{
if (packet.QualityOfServiceLevel == 0 && packet.Dup)
{
throw new ProtocolViolationException("Dup flag must be false for QoS 0 packets [MQTT-3.3.1-2].");
}
}

private async Task SerializeAsync(MqttConnectPacket packet, IMqttTransportChannel destination)
{
ValidateConnectPacket(packet);

using (var output = new MqttPacketWriter())
{
// Write variable header
output.Write(0x00); // 3.1.2.1 Protocol Name
output.Write(0x04); // ""
output.Write('M');
output.Write('Q');
output.Write('T');
output.Write('T');
output.Write(0x04); // 3.1.2.2 Protocol Level

var connectFlags = new ByteWriter(); // 3.1.2.3 Connect Flags
connectFlags.Write(false); // Reserved
connectFlags.Write(packet.CleanSession);
connectFlags.Write(packet.WillMessage != null);

if (packet.WillMessage != null)
{
connectFlags.Write((byte)packet.WillMessage.QualityOfServiceLevel, 2);
connectFlags.Write(packet.WillMessage.Retain);
}
else
{
connectFlags.Write(0, 2);
connectFlags.Write(false);
}

connectFlags.Write(packet.Password != null);
connectFlags.Write(packet.Username != null);

output.Write(connectFlags);
output.Write(packet.KeepAlivePeriod);
output.WriteWithLengthPrefix(packet.ClientId);

if (packet.WillMessage != null)
{
output.WriteWithLengthPrefix(packet.WillMessage.Topic);
output.WriteWithLengthPrefix(packet.WillMessage.Payload);
}

if (packet.Username != null)
{
output.WriteWithLengthPrefix(packet.Username);
}

if (packet.Password != null)
{
output.WriteWithLengthPrefix(packet.Password);
}

output.InjectFixedHeader(MqttControlPacketType.Connect);
await output.WriteToAsync(destination);
}
}

private async Task SerializeAsync(MqttConnAckPacket packet, IMqttTransportChannel destination)
{
using (var output = new MqttPacketWriter())
{
var connectAcknowledgeFlags = new ByteWriter();
connectAcknowledgeFlags.Write(packet.IsSessionPresent);

output.Write(connectAcknowledgeFlags);
output.Write((byte)packet.ConnectReturnCode);

output.InjectFixedHeader(MqttControlPacketType.ConnAck);
await output.WriteToAsync(destination);
}
}

private async Task SerializeAsync(MqttDisconnectPacket packet, IMqttTransportChannel destination)
{
await SerializeEmptyPacketAsync(MqttControlPacketType.Disconnect, destination);
}

private async Task SerializeAsync(MqttPingReqPacket packet, IMqttTransportChannel destination)
{
await SerializeEmptyPacketAsync(MqttControlPacketType.PingReq, destination);
}

private async Task SerializeAsync(MqttPingRespPacket packet, IMqttTransportChannel destination)
{
await SerializeEmptyPacketAsync(MqttControlPacketType.PingResp, destination);
}

private async Task SerializeAsync(MqttPublishPacket packet, IMqttTransportChannel destination)
{
ValidatePublishPacket(packet);

using (var output = new MqttPacketWriter())
{
output.WriteWithLengthPrefix(packet.Topic);

if (packet.QualityOfServiceLevel > 0)
{
if (!packet.PacketIdentifier.HasValue)
{
throw new MqttProtocolViolationException("Packet identifier must be set if QoS > 0 [MQTT-2.3.1-1].");
}

output.Write(packet.PacketIdentifier.Value);
}
else
{
if (packet.PacketIdentifier.HasValue)
{
throw new MqttProtocolViolationException("Packet identifier must be empty if QoS == 0 [MQTT-2.3.1-5].");
}
}

if (packet.Payload?.Length > 0)
{
output.Write(packet.Payload);
}

var fixedHeader = new ByteWriter();
fixedHeader.Write(packet.Retain);
fixedHeader.Write((byte)packet.QualityOfServiceLevel, 2);
fixedHeader.Write(packet.Dup);

output.InjectFixedHeader(MqttControlPacketType.Publish, fixedHeader.Value);
await output.WriteToAsync(destination);
}
}

private async Task SerializeAsync(MqttPubAckPacket packet, IMqttTransportChannel destination)
{
using (var output = new MqttPacketWriter())
{
output.Write(packet.PacketIdentifier);

output.InjectFixedHeader(MqttControlPacketType.PubAck);
await output.WriteToAsync(destination);
}
}

private async Task SerializeAsync(MqttPubRecPacket packet, IMqttTransportChannel destination)
{
using (var output = new MqttPacketWriter())
{
output.Write(packet.PacketIdentifier);

output.InjectFixedHeader(MqttControlPacketType.PubRec);
await output.WriteToAsync(destination);
}
}

private async Task SerializeAsync(MqttPubRelPacket packet, IMqttTransportChannel destination)
{
using (var output = new MqttPacketWriter())
{
output.Write(packet.PacketIdentifier);

output.InjectFixedHeader(MqttControlPacketType.PubRel, 0x02);
await output.WriteToAsync(destination);
}
}

private async Task SerializeAsync(MqttPubCompPacket packet, IMqttTransportChannel destination)
{
using (var output = new MqttPacketWriter())
{
output.Write(packet.PacketIdentifier);

output.InjectFixedHeader(MqttControlPacketType.PubComp);
await output.WriteToAsync(destination);
}
}

private async Task SerializeAsync(MqttSubscribePacket packet, IMqttTransportChannel destination)
{
using (var output = new MqttPacketWriter())
{
output.Write(packet.PacketIdentifier);

if (packet.TopicFilters?.Any() == true)
{
foreach (var topicFilter in packet.TopicFilters)
{
output.WriteWithLengthPrefix(topicFilter.Topic);
output.Write((byte)topicFilter.QualityOfServiceLevel);
}
}

output.InjectFixedHeader(MqttControlPacketType.Subscribe, 0x02);
await output.WriteToAsync(destination);
}
}

private async Task SerializeAsync(MqttSubAckPacket packet, IMqttTransportChannel destination)
{
using (var output = new MqttPacketWriter())
{
output.Write(packet.PacketIdentifier);

if (packet.SubscribeReturnCodes?.Any() == true)
{
foreach (var packetSubscribeReturnCode in packet.SubscribeReturnCodes)
{
output.Write((byte)packetSubscribeReturnCode);
}
}

output.InjectFixedHeader(MqttControlPacketType.SubAck);
await output.WriteToAsync(destination);
}
}

private async Task SerializeAsync(MqttUnsubscribePacket packet, IMqttTransportChannel destination)
{
using (var output = new MqttPacketWriter())
{
output.Write(packet.PacketIdentifier);

if (packet.TopicFilters?.Any() == true)
{
foreach (var topicFilter in packet.TopicFilters)
{
output.WriteWithLengthPrefix(topicFilter);
}
}

output.InjectFixedHeader(MqttControlPacketType.Unsubscibe, 0x02);
await output.WriteToAsync(destination);
}
}

private async Task SerializeAsync(MqttUnsubAckPacket packet, IMqttTransportChannel destination)
{
using (var output = new MqttPacketWriter())
{
output.Write(packet.PacketIdentifier);

output.InjectFixedHeader(MqttControlPacketType.UnsubAck);
await output.WriteToAsync(destination);
}
}

private async Task SerializeEmptyPacketAsync(MqttControlPacketType type, IMqttTransportChannel destination)
{
using (var output = new MqttPacketWriter())
{
output.InjectFixedHeader(type);
await output.WriteToAsync(destination);
}
}
}
}

+ 13
- 0
MQTT.NET.Core/Serializer/IMqttPacketSerializer.cs 查看文件

@@ -0,0 +1,13 @@
using System.Threading.Tasks;
using MQTTnet.Core.Channel;
using MQTTnet.Core.Packets;

namespace MQTTnet.Core.Serializer
{
public interface IMqttPacketSerializer
{
Task SerializeAsync(MqttBasePacket mqttPacket, IMqttTransportChannel destination);

Task<MqttBasePacket> DeserializeAsync(IMqttTransportChannel source);
}
}

+ 130
- 0
MQTT.NET.Core/Serializer/MqttPacketReader.cs 查看文件

@@ -0,0 +1,130 @@
using System;
using System.Diagnostics;
using System.IO;
using System.Text;
using System.Threading.Tasks;
using MQTTnet.Core.Channel;
using MQTTnet.Core.Exceptions;
using MQTTnet.Core.Protocol;

namespace MQTTnet.Core.Serializer
{
public sealed class MqttPacketReader : IDisposable
{
private readonly MemoryStream _remainingData = new MemoryStream();
private readonly IMqttTransportChannel _source;

public MqttPacketReader(IMqttTransportChannel source)
{
if (source == null) throw new ArgumentNullException(nameof(source));

_source = source;
}

public MqttControlPacketType ControlPacketType { get; private set; }

public byte FixedHeader { get; private set; }

public int RemainingLength { get; private set; }

public bool EndOfRemainingData => _remainingData.Position == _remainingData.Length;

public async Task ReadToEndAsync()
{
await ReadFixedHeaderAsync();
await ReadRemainingLengthAsync();

if (RemainingLength == 0)
{
return;
}

var buffer = new byte[RemainingLength];
await _source.ReadAsync(buffer);

_remainingData.Write(buffer, 0, buffer.Length);
_remainingData.Position = 0;
}

private async Task ReadFixedHeaderAsync()
{
FixedHeader = await ReadStreamByteAsync();

var byteReader = new ByteReader(FixedHeader);
byteReader.Read(4);
ControlPacketType = (MqttControlPacketType)byteReader.Read(4);
}

private async Task<byte> ReadStreamByteAsync()
{
var buffer = new byte[1];
await _source.ReadAsync(buffer);
return buffer[0];
}

private async Task ReadRemainingLengthAsync()
{
// Alorithm taken from http://docs.oasis-open.org/mqtt/mqtt/v3.1.1/os/mqtt-v3.1.1-os.html.
var multiplier = 1;
var value = 0;
byte encodedByte;
do
{
encodedByte = await ReadStreamByteAsync();
value += (encodedByte & 127) * multiplier;
multiplier *= 128;
if (multiplier > 128 * 128 * 128)
{
throw new MqttProtocolViolationException("Remaining length is ivalid.");
}
} while ((encodedByte & 128) != 0);

RemainingLength = value;
}

public async Task<byte> ReadRemainingDataByteAsync()
{
return (await ReadRemainingDataAsync(1))[0];
}

public async Task<ushort> ReadRemainingDataUShortAsync()
{
var buffer = await ReadRemainingDataAsync(2);

var temp = buffer[0];
buffer[0] = buffer[1];
buffer[1] = temp;

return BitConverter.ToUInt16(buffer, 0);
}

public async Task<string> ReadRemainingDataStringWithLengthPrefixAsync()
{
var buffer = await ReadRemainingDataWithLengthPrefixAsync();
return Encoding.UTF8.GetString(buffer, 0, buffer.Length);
}

public async Task<byte[]> ReadRemainingDataWithLengthPrefixAsync()
{
var length = await ReadRemainingDataUShortAsync();
return await ReadRemainingDataAsync(length);
}

public async Task<byte[]> ReadRemainingDataAsync()
{
return await ReadRemainingDataAsync(RemainingLength - (int)_remainingData.Position);
}

public async Task<byte[]> ReadRemainingDataAsync(int length)
{
var buffer = new byte[length];
await _remainingData.ReadAsync(buffer, 0, buffer.Length);
return buffer;
}

public void Dispose()
{
_remainingData?.Dispose();
}
}
}

+ 107
- 0
MQTT.NET.Core/Serializer/MqttPacketWriter.cs 查看文件

@@ -0,0 +1,107 @@
using System;
using System.IO;
using System.Text;
using System.Threading.Tasks;
using MQTTnet.Core.Channel;
using MQTTnet.Core.Protocol;

namespace MQTTnet.Core.Serializer
{
public sealed class MqttPacketWriter : IDisposable
{
private readonly MemoryStream _buffer = new MemoryStream();

public void InjectFixedHeader(byte fixedHeader)
{
if (_buffer.Length == 0)
{
Write(fixedHeader);
Write(0);
return;
}

var remainingLength = (int)_buffer.Length;
using (var buffer = new MemoryStream())
{
_buffer.WriteTo(buffer);
_buffer.SetLength(0);

_buffer.WriteByte(fixedHeader);

// Alorithm taken from http://docs.oasis-open.org/mqtt/mqtt/v3.1.1/os/mqtt-v3.1.1-os.html.
var x = remainingLength;
do
{
var encodedByte = (byte)(x % 128);
x = x / 128;
if (x > 0)
{
encodedByte = (byte)(encodedByte | 128);
}

_buffer.WriteByte(encodedByte);
} while (x > 0);

buffer.Position = 0;
buffer.WriteTo(_buffer);
}
}

public void InjectFixedHeader(MqttControlPacketType packetType, byte flags = 0)
{
var fixedHeader = (byte)((byte)packetType << 4);
fixedHeader |= flags;
InjectFixedHeader(fixedHeader);
}

public void Write(byte value)
{
_buffer.WriteByte(value);
}

public void Write(char value)
{
_buffer.WriteByte((byte)value);
}

public void Write(ushort value)
{
var buffer = BitConverter.GetBytes(value);
_buffer.WriteByte(buffer[1]);
_buffer.WriteByte(buffer[0]);
}

public void Write(ByteWriter value)
{
_buffer.WriteByte(value.Value);
}

public void Write(byte[] value)
{
_buffer.Write(value, 0, value.Length);
}

public void WriteWithLengthPrefix(string value)
{
WriteWithLengthPrefix(Encoding.UTF8.GetBytes(value ?? string.Empty));
}

public void WriteWithLengthPrefix(byte[] value)
{
var length = (ushort)value.Length;

Write(length);
Write(value);
}

public void Dispose()
{
_buffer?.Dispose();
}

public async Task WriteToAsync(IMqttTransportChannel destination)
{
await destination.WriteAsync(_buffer.ToArray());
}
}
}

+ 11
- 0
MQTT.NET.Core/TaskExtensions.cs 查看文件

@@ -0,0 +1,11 @@
using System.Threading.Tasks;

namespace MQTTnet.Core
{
public static class TaskExtensions
{
public static void Forget(this Task task)
{
}
}
}

+ 6
- 0
MQTT.NET.TestConsole/App.config 查看文件

@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.6.1" />
</startup>
</configuration>

+ 71
- 0
MQTT.NET.TestConsole/MQTTnet.TestConsole.csproj 查看文件

@@ -0,0 +1,71 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{7B19B139-2E9D-4F1D-88B4-6180B4CF872A}</ProjectGuid>
<OutputType>Exe</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>MQTTnet.TestConsole</RootNamespace>
<AssemblyName>MQTTnet.TestConsole</AssemblyName>
<TargetFrameworkVersion>v4.6.1</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.ServiceModel.Activities" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Data" />
<Reference Include="System.Net.Http" />
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="Program.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
<ItemGroup>
<None Include="App.config" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\MQTT.NET.Core\MQTTnet.Core.csproj">
<Project>{99c884f3-b4b9-417d-aa92-dc7dd1c4cfee}</Project>
<Name>MQTTnet.Core</Name>
</ProjectReference>
<ProjectReference Include="..\MQTTnet.NET\MQTTnet.NETFramework.csproj">
<Project>{A480EF90-0EAA-4D9A-B271-47A9C47F6F7D}</Project>
<Name>MQTTnet.NETFramework</Name>
</ProjectReference>
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
</Project>

+ 109
- 0
MQTT.NET.TestConsole/Program.cs 查看文件

@@ -0,0 +1,109 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading.Tasks;
using MQTTnet.Core;
using MQTTnet.Core.Adapter;
using MQTTnet.Core.Client;
using MQTTnet.Core.Diagnostics;
using MQTTnet.Core.Packets;
using MQTTnet.Core.Protocol;
using MQTTnet.NETFramework;

namespace MQTTnet.TestConsole
{
public static class Program
{
public static void Main(string[] arguments)
{
Task.Run(() => Run(arguments)).Wait();
}

private static async Task Run(string[] arguments)
{
MqttTrace.TraceMessagePublished += (s, e) =>
{
Console.WriteLine($">> [{e.ThreadId}] [{e.Source}] [{e.Level}]: {e.Message}");
if (e.Exception != null)
{
// Console.WriteLine(e.Exception);
}
};

try
{
var options = new MqttClientOptions
{
Server = "localhost"
};

var client = new MqttClientFactory().CreateMqttClient(options);
client.ApplicationMessageReceived += (s, e) =>
{
Console.WriteLine("### RECEIVED APPLICATION MESSAGE ###");
Console.WriteLine($"+ Topic = {e.ApplicationMessage.Topic}");
Console.WriteLine($"+ Payload = {Encoding.UTF8.GetString(e.ApplicationMessage.Payload)}");
Console.WriteLine($"+ QoS = {e.ApplicationMessage.QualityOfServiceLevel}");
Console.WriteLine($"+ Retain = {e.ApplicationMessage.Retain}");
Console.WriteLine();
};

client.Connected += async (s, e) =>
{
Console.WriteLine("### CONNECTED WITH SERVER ###");

await client.SubscribeAsync(new List<TopicFilter>
{
new TopicFilter("#", MqttQualityOfServiceLevel.AtMostOnce)
});

Console.WriteLine("### SUBSCRIBED ###");
};

client.Disconnected += async (s, e) =>
{
Console.WriteLine("### DISCONNECTED FROM SERVER ###");
await Task.Delay(TimeSpan.FromSeconds(5));

try
{
await client.ConnectAsync();
}
catch
{
Console.WriteLine("### RECONNECTING FAILED ###");
}
};

try
{
await client.ConnectAsync();
}
catch
{
Console.WriteLine("### CONNECTING FAILED ###");
}

Console.WriteLine("### WAITING FOR APPLICATION MESSAGES ###");

while (true)
{
Console.ReadLine();

var applicationMessage = new MqttApplicationMessage(
"A/B/C",
Encoding.UTF8.GetBytes("Hello World"),
MqttQualityOfServiceLevel.AtLeastOnce,
false
);

await client.PublishAsync(applicationMessage);
}
}
catch (Exception exception)
{
Console.WriteLine(exception);
}
}
}
}

+ 15
- 0
MQTT.NET.TestConsole/Properties/AssemblyInfo.cs 查看文件

@@ -0,0 +1,15 @@
using System.Reflection;
using System.Runtime.InteropServices;

[assembly: AssemblyTitle("MQTTnet.TestConsole")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("Christian Kratky")]
[assembly: AssemblyProduct("MQTTnet")]
[assembly: AssemblyCopyright("Copyright © Christian Kratky 2016-2017")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
[assembly: ComVisible(false)]
[assembly: Guid("7b19b139-2e9d-4f1d-88b4-6180b4cf872a")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]

+ 56
- 0
MQTTnet.NET/MQTTnet.NETFramework.csproj 查看文件

@@ -0,0 +1,56 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{A480EF90-0EAA-4D9A-B271-47A9C47F6F7D}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>MQTTnet.NETFramework</RootNamespace>
<AssemblyName>MQTTnet.NETFramework</AssemblyName>
<TargetFrameworkVersion>v4.6.1</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="MqttClientFactory.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="MqttTcpChannel.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\MQTT.NET.Core\MQTTnet.Core.csproj">
<Project>{99C884F3-B4B9-417D-AA92-DC7DD1C4CFEE}</Project>
<Name>MQTTnet.Core</Name>
</ProjectReference>
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
</Project>

+ 17
- 0
MQTTnet.NET/MqttClientFactory.cs 查看文件

@@ -0,0 +1,17 @@
using System;
using MQTTnet.Core.Adapter;
using MQTTnet.Core.Client;
using MQTTnet.Core.Serializer;

namespace MQTTnet.NETFramework
{
public class MqttClientFactory
{
public MqttClient CreateMqttClient(MqttClientOptions options)
{
if (options == null) throw new ArgumentNullException(nameof(options));

return new MqttClient(options, new MqttChannelAdapter(new MqttTcpChannel(), new DefaultMqttV311PacketSerializer()));
}
}
}

+ 46
- 0
MQTTnet.NET/MqttTcpChannel.cs 查看文件

@@ -0,0 +1,46 @@
using System;
using System.Net.Sockets;
using System.Threading.Tasks;
using MQTTnet.Core.Channel;
using MQTTnet.Core.Client;

namespace MQTTnet.NETFramework
{
public class MqttTcpChannel : IMqttTransportChannel, IDisposable
{
private readonly Socket _socket = new Socket(SocketType.Stream, ProtocolType.Tcp);

public async Task ConnectAsync(MqttClientOptions options)
{
await Task.Factory.FromAsync(_socket.BeginConnect, _socket.EndConnect, options.Server, options.Port, null);
}

public async Task DisconnectAsync()
{
await Task.Factory.FromAsync(_socket.BeginDisconnect, _socket.EndDisconnect, true, null);
}

public async Task WriteAsync(byte[] buffer)
{
if (buffer == null) throw new ArgumentNullException(nameof(buffer));

await Task.Factory.FromAsync(
// ReSharper disable once AssignNullToNotNullAttribute
_socket.BeginSend(buffer, 0, buffer.Length, SocketFlags.None, null, null),
_socket.EndSend);
}

public async Task ReadAsync(byte[] buffer)
{
await Task.Factory.FromAsync(
// ReSharper disable once AssignNullToNotNullAttribute
_socket.BeginReceive(buffer, 0, buffer.Length, SocketFlags.None, null, null),
_socket.EndReceive);
}

public void Dispose()
{
_socket?.Dispose();
}
}
}

+ 15
- 0
MQTTnet.NET/Properties/AssemblyInfo.cs 查看文件

@@ -0,0 +1,15 @@
using System.Reflection;
using System.Runtime.InteropServices;

[assembly: AssemblyTitle("MQTTnet.NETFramework")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("Christian Kratky")]
[assembly: AssemblyProduct("MQTTnet")]
[assembly: AssemblyCopyright("Copyright © Christian Kratky 2016-2017")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
[assembly: ComVisible(false)]
[assembly: Guid("a480ef90-0eaa-4d9a-b271-47a9c47f6f7d")]
[assembly: AssemblyVersion("2.1.0.4")]
[assembly: AssemblyFileVersion("2.1.0.4")]

+ 132
- 0
MQTTnet.Universal/MQTTnet.Universal.csproj 查看文件

@@ -0,0 +1,132 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{BD60C727-D8E8-40C3-B8E3-C95A864AE611}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>MQTTnet.Universal</RootNamespace>
<AssemblyName>MQTTnet.Universal</AssemblyName>
<DefaultLanguage>en-US</DefaultLanguage>
<TargetPlatformIdentifier>UAP</TargetPlatformIdentifier>
<TargetPlatformVersion>10.0.14393.0</TargetPlatformVersion>
<TargetPlatformMinVersion>10.0.10586.0</TargetPlatformMinVersion>
<MinimumVisualStudioVersion>14</MinimumVisualStudioVersion>
<FileAlignment>512</FileAlignment>
<ProjectTypeGuids>{A5A43C5B-DE2A-4C0C-9213-0A381AF9435A};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE;NETFX_CORE;WINDOWS_UWP</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x86'">
<PlatformTarget>x86</PlatformTarget>
<DebugSymbols>true</DebugSymbols>
<OutputPath>bin\x86\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP</DefineConstants>
<NoWarn>;2008</NoWarn>
<DebugType>full</DebugType>
<PlatformTarget>x86</PlatformTarget>
<UseVSHostingProcess>false</UseVSHostingProcess>
<ErrorReport>prompt</ErrorReport>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x86'">
<PlatformTarget>x86</PlatformTarget>
<OutputPath>bin\x86\Release\</OutputPath>
<DefineConstants>TRACE;NETFX_CORE;WINDOWS_UWP</DefineConstants>
<Optimize>true</Optimize>
<NoWarn>;2008</NoWarn>
<DebugType>pdbonly</DebugType>
<PlatformTarget>x86</PlatformTarget>
<UseVSHostingProcess>false</UseVSHostingProcess>
<ErrorReport>prompt</ErrorReport>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|ARM'">
<PlatformTarget>ARM</PlatformTarget>
<DebugSymbols>true</DebugSymbols>
<OutputPath>bin\ARM\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP</DefineConstants>
<NoWarn>;2008</NoWarn>
<DebugType>full</DebugType>
<PlatformTarget>ARM</PlatformTarget>
<UseVSHostingProcess>false</UseVSHostingProcess>
<ErrorReport>prompt</ErrorReport>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|ARM'">
<PlatformTarget>ARM</PlatformTarget>
<OutputPath>bin\ARM\Release\</OutputPath>
<DefineConstants>TRACE;NETFX_CORE;WINDOWS_UWP</DefineConstants>
<Optimize>true</Optimize>
<NoWarn>;2008</NoWarn>
<DebugType>pdbonly</DebugType>
<PlatformTarget>ARM</PlatformTarget>
<UseVSHostingProcess>false</UseVSHostingProcess>
<ErrorReport>prompt</ErrorReport>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'">
<PlatformTarget>x64</PlatformTarget>
<DebugSymbols>true</DebugSymbols>
<OutputPath>bin\x64\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP</DefineConstants>
<NoWarn>;2008</NoWarn>
<DebugType>full</DebugType>
<PlatformTarget>x64</PlatformTarget>
<UseVSHostingProcess>false</UseVSHostingProcess>
<ErrorReport>prompt</ErrorReport>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'">
<PlatformTarget>x64</PlatformTarget>
<OutputPath>bin\x64\Release\</OutputPath>
<DefineConstants>TRACE;NETFX_CORE;WINDOWS_UWP</DefineConstants>
<Optimize>true</Optimize>
<NoWarn>;2008</NoWarn>
<DebugType>pdbonly</DebugType>
<PlatformTarget>x64</PlatformTarget>
<UseVSHostingProcess>false</UseVSHostingProcess>
<ErrorReport>prompt</ErrorReport>
</PropertyGroup>
<ItemGroup>
<!-- A reference to the entire .Net Framework and Windows SDK are automatically included -->
<None Include="project.json" />
</ItemGroup>
<ItemGroup>
<Compile Include="MqttClientFactory.cs" />
<Compile Include="MqttTcpChannel.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<EmbeddedResource Include="Properties\MQTTnet.Universal.rd.xml" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\MQTT.NET.Core\MQTTnet.Core.csproj">
<Project>{99C884F3-B4B9-417D-AA92-DC7DD1C4CFEE}</Project>
<Name>MQTTnet.Core</Name>
</ProjectReference>
</ItemGroup>
<PropertyGroup Condition=" '$(VisualStudioVersion)' == '' or '$(VisualStudioVersion)' &lt; '14.0' ">
<VisualStudioVersion>14.0</VisualStudioVersion>
</PropertyGroup>
<Import Project="$(MSBuildExtensionsPath)\Microsoft\WindowsXaml\v$(VisualStudioVersion)\Microsoft.Windows.UI.Xaml.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
</Project>

+ 17
- 0
MQTTnet.Universal/MqttClientFactory.cs 查看文件

@@ -0,0 +1,17 @@
using System;
using MQTTnet.Core.Adapter;
using MQTTnet.Core.Client;
using MQTTnet.Core.Serializer;

namespace MQTTnet.Universal
{
public class MqttClientFactory
{
public MqttClient CreateMqttClient(MqttClientOptions options)
{
if (options == null) throw new ArgumentNullException(nameof(options));

return new MqttClient(options, new MqttChannelAdapter(new MqttTcpChannel(), new DefaultMqttV311PacketSerializer()));
}
}
}

+ 52
- 0
MQTTnet.Universal/MqttTcpChannel.cs 查看文件

@@ -0,0 +1,52 @@
using System;
using System.Runtime.InteropServices.WindowsRuntime;
using System.Threading.Tasks;
using Windows.Networking;
using Windows.Networking.Sockets;
using Windows.Storage.Streams;
using MQTTnet.Core.Channel;
using MQTTnet.Core.Client;
using Buffer = Windows.Storage.Streams.Buffer;

namespace MQTTnet.Universal
{
public sealed class MqttTcpChannel : IMqttTransportChannel, IDisposable
{
private readonly StreamSocket _socket = new StreamSocket();

public async Task ConnectAsync(MqttClientOptions options)
{
if (options == null) throw new ArgumentNullException(nameof(options));

await _socket.ConnectAsync(new HostName(options.Server), options.Port.ToString());
}

public async Task DisconnectAsync()
{
await _socket.CancelIOAsync();
_socket.Dispose();
}

public async Task WriteAsync(byte[] buffer)
{
if (buffer == null) throw new ArgumentNullException(nameof(buffer));

await _socket.OutputStream.WriteAsync(buffer.AsBuffer());
await _socket.OutputStream.FlushAsync();
}

public async Task ReadAsync(byte[] buffer)
{
var buffer2 = new Buffer((uint)buffer.Length);
await _socket.InputStream.ReadAsync(buffer2, (uint)buffer.Length, InputStreamOptions.None);

var array2 = buffer2.ToArray();
Array.Copy(array2, buffer, array2.Length);
}

public void Dispose()
{
_socket?.Dispose();
}
}
}

+ 14
- 0
MQTTnet.Universal/Properties/AssemblyInfo.cs 查看文件

@@ -0,0 +1,14 @@
using System.Reflection;
using System.Runtime.InteropServices;

[assembly: AssemblyTitle("MQTTnet.Universal")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("Christian Kratky")]
[assembly: AssemblyProduct("MQTTnet")]
[assembly: AssemblyCopyright("Copyright © Christian Kratky 2016-2017")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
[assembly: ComVisible(false)]
[assembly: AssemblyVersion("2.1.0.4")]
[assembly: AssemblyFileVersion("2.1.0.4")]

+ 33
- 0
MQTTnet.Universal/Properties/MQTTnet.Universal.rd.xml 查看文件

@@ -0,0 +1,33 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
This file contains Runtime Directives, specifications about types your application accesses
through reflection and other dynamic code patterns. Runtime Directives are used to control the
.NET Native optimizer and ensure that it does not remove code accessed by your library. If your
library does not do any reflection, then you generally do not need to edit this file. However,
if your library reflects over types, especially types passed to it or derived from its types,
then you should write Runtime Directives.

The most common use of reflection in libraries is to discover information about types passed
to the library. Runtime Directives have three ways to express requirements on types passed to
your library.

1. Parameter, GenericParameter, TypeParameter, TypeEnumerableParameter
Use these directives to reflect over types passed as a parameter.

2. SubTypes
Use a SubTypes directive to reflect over types derived from another type.

3. AttributeImplies
Use an AttributeImplies directive to indicate that your library needs to reflect over
types or methods decorated with an attribute.

For more information on writing Runtime Directives for libraries, please visit
http://go.microsoft.com/fwlink/?LinkID=391919
-->
<Directives xmlns="http://schemas.microsoft.com/netfx/2013/01/metadata">
<Library Name="MQTTnet.Universal">

<!-- add directives for your library here -->

</Library>
</Directives>

+ 16
- 0
MQTTnet.Universal/project.json 查看文件

@@ -0,0 +1,16 @@
{
"dependencies": {
"Microsoft.NETCore.UniversalWindowsPlatform": "5.1.0"
},
"frameworks": {
"uap10.0": {}
},
"runtimes": {
"win10-arm": {},
"win10-arm-aot": {},
"win10-x86": {},
"win10-x86-aot": {},
"win10-x64": {},
"win10-x64-aot": {}
}
}

+ 112
- 0
MQTTnet.sln 查看文件

@@ -0,0 +1,112 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 14
VisualStudioVersion = 14.0.25420.1
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MQTTnet.Core", "MQTT.NET.Core\MQTTnet.Core.csproj", "{99C884F3-B4B9-417D-AA92-DC7DD1C4CFEE}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MQTTnet.TestConsole", "MQTT.NET.TestConsole\MQTTnet.TestConsole.csproj", "{7B19B139-2E9D-4F1D-88B4-6180B4CF872A}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MQTTnet.Core.Tests", "MQTT.NET.Core.Tests\MQTTnet.Core.Tests.csproj", "{A7FF0C91-25DE-4BA6-B39E-F54E8DADF1CC}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MQTTnet.NETFramework", "MQTTnet.NET\MQTTnet.NETFramework.csproj", "{A480EF90-0EAA-4D9A-B271-47A9C47F6F7D}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MQTTnet.Universal", "MQTTnet.Universal\MQTTnet.Universal.csproj", "{BD60C727-D8E8-40C3-B8E3-C95A864AE611}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Debug|ARM = Debug|ARM
Debug|x64 = Debug|x64
Debug|x86 = Debug|x86
Release|Any CPU = Release|Any CPU
Release|ARM = Release|ARM
Release|x64 = Release|x64
Release|x86 = Release|x86
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{99C884F3-B4B9-417D-AA92-DC7DD1C4CFEE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{99C884F3-B4B9-417D-AA92-DC7DD1C4CFEE}.Debug|Any CPU.Build.0 = Debug|Any CPU
{99C884F3-B4B9-417D-AA92-DC7DD1C4CFEE}.Debug|ARM.ActiveCfg = Debug|Any CPU
{99C884F3-B4B9-417D-AA92-DC7DD1C4CFEE}.Debug|ARM.Build.0 = Debug|Any CPU
{99C884F3-B4B9-417D-AA92-DC7DD1C4CFEE}.Debug|x64.ActiveCfg = Debug|Any CPU
{99C884F3-B4B9-417D-AA92-DC7DD1C4CFEE}.Debug|x64.Build.0 = Debug|Any CPU
{99C884F3-B4B9-417D-AA92-DC7DD1C4CFEE}.Debug|x86.ActiveCfg = Debug|Any CPU
{99C884F3-B4B9-417D-AA92-DC7DD1C4CFEE}.Debug|x86.Build.0 = Debug|Any CPU
{99C884F3-B4B9-417D-AA92-DC7DD1C4CFEE}.Release|Any CPU.ActiveCfg = Release|Any CPU
{99C884F3-B4B9-417D-AA92-DC7DD1C4CFEE}.Release|Any CPU.Build.0 = Release|Any CPU
{99C884F3-B4B9-417D-AA92-DC7DD1C4CFEE}.Release|ARM.ActiveCfg = Release|Any CPU
{99C884F3-B4B9-417D-AA92-DC7DD1C4CFEE}.Release|ARM.Build.0 = Release|Any CPU
{99C884F3-B4B9-417D-AA92-DC7DD1C4CFEE}.Release|x64.ActiveCfg = Release|Any CPU
{99C884F3-B4B9-417D-AA92-DC7DD1C4CFEE}.Release|x64.Build.0 = Release|Any CPU
{99C884F3-B4B9-417D-AA92-DC7DD1C4CFEE}.Release|x86.ActiveCfg = Release|Any CPU
{99C884F3-B4B9-417D-AA92-DC7DD1C4CFEE}.Release|x86.Build.0 = Release|Any CPU
{7B19B139-2E9D-4F1D-88B4-6180B4CF872A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{7B19B139-2E9D-4F1D-88B4-6180B4CF872A}.Debug|Any CPU.Build.0 = Debug|Any CPU
{7B19B139-2E9D-4F1D-88B4-6180B4CF872A}.Debug|ARM.ActiveCfg = Debug|Any CPU
{7B19B139-2E9D-4F1D-88B4-6180B4CF872A}.Debug|ARM.Build.0 = Debug|Any CPU
{7B19B139-2E9D-4F1D-88B4-6180B4CF872A}.Debug|x64.ActiveCfg = Debug|Any CPU
{7B19B139-2E9D-4F1D-88B4-6180B4CF872A}.Debug|x64.Build.0 = Debug|Any CPU
{7B19B139-2E9D-4F1D-88B4-6180B4CF872A}.Debug|x86.ActiveCfg = Debug|Any CPU
{7B19B139-2E9D-4F1D-88B4-6180B4CF872A}.Debug|x86.Build.0 = Debug|Any CPU
{7B19B139-2E9D-4F1D-88B4-6180B4CF872A}.Release|Any CPU.ActiveCfg = Release|Any CPU
{7B19B139-2E9D-4F1D-88B4-6180B4CF872A}.Release|Any CPU.Build.0 = Release|Any CPU
{7B19B139-2E9D-4F1D-88B4-6180B4CF872A}.Release|ARM.ActiveCfg = Release|Any CPU
{7B19B139-2E9D-4F1D-88B4-6180B4CF872A}.Release|ARM.Build.0 = Release|Any CPU
{7B19B139-2E9D-4F1D-88B4-6180B4CF872A}.Release|x64.ActiveCfg = Release|Any CPU
{7B19B139-2E9D-4F1D-88B4-6180B4CF872A}.Release|x64.Build.0 = Release|Any CPU
{7B19B139-2E9D-4F1D-88B4-6180B4CF872A}.Release|x86.ActiveCfg = Release|Any CPU
{7B19B139-2E9D-4F1D-88B4-6180B4CF872A}.Release|x86.Build.0 = Release|Any CPU
{A7FF0C91-25DE-4BA6-B39E-F54E8DADF1CC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{A7FF0C91-25DE-4BA6-B39E-F54E8DADF1CC}.Debug|Any CPU.Build.0 = Debug|Any CPU
{A7FF0C91-25DE-4BA6-B39E-F54E8DADF1CC}.Debug|ARM.ActiveCfg = Debug|Any CPU
{A7FF0C91-25DE-4BA6-B39E-F54E8DADF1CC}.Debug|ARM.Build.0 = Debug|Any CPU
{A7FF0C91-25DE-4BA6-B39E-F54E8DADF1CC}.Debug|x64.ActiveCfg = Debug|Any CPU
{A7FF0C91-25DE-4BA6-B39E-F54E8DADF1CC}.Debug|x64.Build.0 = Debug|Any CPU
{A7FF0C91-25DE-4BA6-B39E-F54E8DADF1CC}.Debug|x86.ActiveCfg = Debug|Any CPU
{A7FF0C91-25DE-4BA6-B39E-F54E8DADF1CC}.Debug|x86.Build.0 = Debug|Any CPU
{A7FF0C91-25DE-4BA6-B39E-F54E8DADF1CC}.Release|Any CPU.ActiveCfg = Release|Any CPU
{A7FF0C91-25DE-4BA6-B39E-F54E8DADF1CC}.Release|Any CPU.Build.0 = Release|Any CPU
{A7FF0C91-25DE-4BA6-B39E-F54E8DADF1CC}.Release|ARM.ActiveCfg = Release|Any CPU
{A7FF0C91-25DE-4BA6-B39E-F54E8DADF1CC}.Release|ARM.Build.0 = Release|Any CPU
{A7FF0C91-25DE-4BA6-B39E-F54E8DADF1CC}.Release|x64.ActiveCfg = Release|Any CPU
{A7FF0C91-25DE-4BA6-B39E-F54E8DADF1CC}.Release|x64.Build.0 = Release|Any CPU
{A7FF0C91-25DE-4BA6-B39E-F54E8DADF1CC}.Release|x86.ActiveCfg = Release|Any CPU
{A7FF0C91-25DE-4BA6-B39E-F54E8DADF1CC}.Release|x86.Build.0 = Release|Any CPU
{A480EF90-0EAA-4D9A-B271-47A9C47F6F7D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{A480EF90-0EAA-4D9A-B271-47A9C47F6F7D}.Debug|Any CPU.Build.0 = Debug|Any CPU
{A480EF90-0EAA-4D9A-B271-47A9C47F6F7D}.Debug|ARM.ActiveCfg = Debug|Any CPU
{A480EF90-0EAA-4D9A-B271-47A9C47F6F7D}.Debug|ARM.Build.0 = Debug|Any CPU
{A480EF90-0EAA-4D9A-B271-47A9C47F6F7D}.Debug|x64.ActiveCfg = Debug|Any CPU
{A480EF90-0EAA-4D9A-B271-47A9C47F6F7D}.Debug|x64.Build.0 = Debug|Any CPU
{A480EF90-0EAA-4D9A-B271-47A9C47F6F7D}.Debug|x86.ActiveCfg = Debug|Any CPU
{A480EF90-0EAA-4D9A-B271-47A9C47F6F7D}.Debug|x86.Build.0 = Debug|Any CPU
{A480EF90-0EAA-4D9A-B271-47A9C47F6F7D}.Release|Any CPU.ActiveCfg = Release|Any CPU
{A480EF90-0EAA-4D9A-B271-47A9C47F6F7D}.Release|Any CPU.Build.0 = Release|Any CPU
{A480EF90-0EAA-4D9A-B271-47A9C47F6F7D}.Release|ARM.ActiveCfg = Release|Any CPU
{A480EF90-0EAA-4D9A-B271-47A9C47F6F7D}.Release|ARM.Build.0 = Release|Any CPU
{A480EF90-0EAA-4D9A-B271-47A9C47F6F7D}.Release|x64.ActiveCfg = Release|Any CPU
{A480EF90-0EAA-4D9A-B271-47A9C47F6F7D}.Release|x64.Build.0 = Release|Any CPU
{A480EF90-0EAA-4D9A-B271-47A9C47F6F7D}.Release|x86.ActiveCfg = Release|Any CPU
{A480EF90-0EAA-4D9A-B271-47A9C47F6F7D}.Release|x86.Build.0 = Release|Any CPU
{BD60C727-D8E8-40C3-B8E3-C95A864AE611}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{BD60C727-D8E8-40C3-B8E3-C95A864AE611}.Debug|Any CPU.Build.0 = Debug|Any CPU
{BD60C727-D8E8-40C3-B8E3-C95A864AE611}.Debug|ARM.ActiveCfg = Debug|ARM
{BD60C727-D8E8-40C3-B8E3-C95A864AE611}.Debug|ARM.Build.0 = Debug|ARM
{BD60C727-D8E8-40C3-B8E3-C95A864AE611}.Debug|x64.ActiveCfg = Debug|x64
{BD60C727-D8E8-40C3-B8E3-C95A864AE611}.Debug|x64.Build.0 = Debug|x64
{BD60C727-D8E8-40C3-B8E3-C95A864AE611}.Debug|x86.ActiveCfg = Debug|x86
{BD60C727-D8E8-40C3-B8E3-C95A864AE611}.Debug|x86.Build.0 = Debug|x86
{BD60C727-D8E8-40C3-B8E3-C95A864AE611}.Release|Any CPU.ActiveCfg = Release|Any CPU
{BD60C727-D8E8-40C3-B8E3-C95A864AE611}.Release|Any CPU.Build.0 = Release|Any CPU
{BD60C727-D8E8-40C3-B8E3-C95A864AE611}.Release|ARM.ActiveCfg = Release|ARM
{BD60C727-D8E8-40C3-B8E3-C95A864AE611}.Release|ARM.Build.0 = Release|ARM
{BD60C727-D8E8-40C3-B8E3-C95A864AE611}.Release|x64.ActiveCfg = Release|x64
{BD60C727-D8E8-40C3-B8E3-C95A864AE611}.Release|x64.Build.0 = Release|x64
{BD60C727-D8E8-40C3-B8E3-C95A864AE611}.Release|x86.ActiveCfg = Release|x86
{BD60C727-D8E8-40C3-B8E3-C95A864AE611}.Release|x86.Build.0 = Release|x86
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
EndGlobal

Loading…
取消
儲存