mirror of
https://github.com/dotnet/MQTTnet.git
synced 2026-10-27 16:52:40 +08:00
v4.0.0 (#1357)
This commit is contained in:
+8
-4
@@ -1,9 +1,13 @@
|
||||
using System;
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System;
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using MQTTnet.Server;
|
||||
|
||||
namespace MQTTnet.AspNetCore.Extensions
|
||||
namespace MQTTnet.AspNetCore
|
||||
{
|
||||
public static class ApplicationBuilderExtensions
|
||||
{
|
||||
@@ -36,9 +40,9 @@ namespace MQTTnet.AspNetCore.Extensions
|
||||
return app;
|
||||
}
|
||||
|
||||
public static IApplicationBuilder UseMqttServer(this IApplicationBuilder app, Action<IMqttServer> configure)
|
||||
public static IApplicationBuilder UseMqttServer(this IApplicationBuilder app, Action<MqttServer> configure)
|
||||
{
|
||||
var server = app.ApplicationServices.GetRequiredService<IMqttServer>();
|
||||
var server = app.ApplicationServices.GetRequiredService<MqttServer>();
|
||||
|
||||
configure(server);
|
||||
|
||||
@@ -1,13 +1,17 @@
|
||||
using MQTTnet.Server;
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using MQTTnet.Server;
|
||||
using System;
|
||||
|
||||
namespace MQTTnet.AspNetCore
|
||||
{
|
||||
public class AspNetMqttServerOptionsBuilder : MqttServerOptionsBuilder
|
||||
public sealed class AspNetMqttServerOptionsBuilder : MqttServerOptionsBuilder
|
||||
{
|
||||
public AspNetMqttServerOptionsBuilder(IServiceProvider serviceProvider)
|
||||
{
|
||||
ServiceProvider = serviceProvider;
|
||||
ServiceProvider = serviceProvider ?? throw new ArgumentNullException(nameof(serviceProvider));
|
||||
}
|
||||
|
||||
public IServiceProvider ServiceProvider { get; }
|
||||
|
||||
@@ -1,15 +1,20 @@
|
||||
using MQTTnet.Adapter;
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using MQTTnet.Adapter;
|
||||
using MQTTnet.AspNetCore.Client.Tcp;
|
||||
using MQTTnet.Client.Options;
|
||||
using MQTTnet.Formatter;
|
||||
using System;
|
||||
using System.Net;
|
||||
using MQTTnet.Client;
|
||||
using MQTTnet.Diagnostics;
|
||||
|
||||
namespace MQTTnet.AspNetCore.Client
|
||||
{
|
||||
public class MqttClientConnectionContextFactory : IMqttClientAdapterFactory
|
||||
public sealed class MqttClientConnectionContextFactory : IMqttClientAdapterFactory
|
||||
{
|
||||
public IMqttChannelAdapter CreateClientAdapter(IMqttClientOptions options)
|
||||
public IMqttChannelAdapter CreateClientAdapter(MqttClientOptions options, MqttPacketInspector packetInspector, IMqttNetLogger logger)
|
||||
{
|
||||
if (options == null) throw new ArgumentNullException(nameof(options));
|
||||
|
||||
@@ -19,9 +24,8 @@ namespace MQTTnet.AspNetCore.Client
|
||||
{
|
||||
var endpoint = new DnsEndPoint(tcpOptions.Server, tcpOptions.GetPort());
|
||||
var tcpConnection = new TcpConnection(endpoint);
|
||||
|
||||
var writer = new SpanBasedMqttPacketWriter();
|
||||
var formatter = new MqttPacketFormatterAdapter(options.ProtocolVersion, writer);
|
||||
|
||||
var formatter = new MqttPacketFormatterAdapter(options.ProtocolVersion, new MqttBufferWriter(4096, 65535));
|
||||
return new MqttConnectionContext(formatter, tcpConnection);
|
||||
}
|
||||
default:
|
||||
|
||||
@@ -1,4 +1,8 @@
|
||||
using System;
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace MQTTnet.AspNetCore.Client.Tcp
|
||||
|
||||
@@ -1,4 +1,8 @@
|
||||
using System.IO.Pipelines;
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System.IO.Pipelines;
|
||||
|
||||
namespace MQTTnet.AspNetCore.Client.Tcp
|
||||
{
|
||||
|
||||
@@ -1,4 +1,8 @@
|
||||
using System;
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.IO.Pipelines;
|
||||
using System.Net.Sockets;
|
||||
|
||||
@@ -1,4 +1,8 @@
|
||||
using System;
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System;
|
||||
using System.IO.Pipelines;
|
||||
using System.Net.Sockets;
|
||||
|
||||
|
||||
@@ -1,4 +1,8 @@
|
||||
using System;
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System;
|
||||
using System.Buffers;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
|
||||
@@ -1,4 +1,8 @@
|
||||
using Microsoft.AspNetCore.Connections;
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using Microsoft.AspNetCore.Connections;
|
||||
using Microsoft.AspNetCore.Http.Features;
|
||||
using MQTTnet.Exceptions;
|
||||
using System;
|
||||
@@ -40,7 +44,7 @@ namespace MQTTnet.AspNetCore.Client.Tcp
|
||||
_sender = new SocketSender(_socket, PipeScheduler.ThreadPool);
|
||||
_receiver = new SocketReceiver(_socket, PipeScheduler.ThreadPool);
|
||||
}
|
||||
#if NETCOREAPP3_1 || NET5_0
|
||||
#if NETCOREAPP3_1 || NET5_0_OR_GREATER
|
||||
public override ValueTask DisposeAsync()
|
||||
#else
|
||||
public Task DisposeAsync()
|
||||
@@ -53,7 +57,7 @@ namespace MQTTnet.AspNetCore.Client.Tcp
|
||||
|
||||
_socket?.Dispose();
|
||||
|
||||
#if NETCOREAPP3_1 || NET5_0
|
||||
#if NETCOREAPP3_1 || NET5_0_OR_GREATER
|
||||
|
||||
return base.DisposeAsync();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using Microsoft.AspNetCore.Connections;
|
||||
|
||||
namespace MQTTnet.AspNetCore
|
||||
{
|
||||
public static class ConnectionBuilderExtensions
|
||||
{
|
||||
public static IConnectionBuilder UseMqtt(this IConnectionBuilder builder)
|
||||
{
|
||||
return builder.UseConnectionHandler<MqttConnectionHandler>();
|
||||
}
|
||||
}
|
||||
}
|
||||
+6
-2
@@ -1,11 +1,15 @@
|
||||
using Microsoft.AspNetCore.Http;
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Http.Connections;
|
||||
|
||||
#if NETCOREAPP3_1
|
||||
using System;
|
||||
#endif
|
||||
|
||||
namespace MQTTnet.AspNetCore.Extensions
|
||||
namespace MQTTnet.AspNetCore
|
||||
{
|
||||
public static class ConnectionRouteBuilderExtensions
|
||||
{
|
||||
+6
-2
@@ -1,5 +1,9 @@
|
||||
|
||||
#if NETCOREAPP3_1 || NET5_0
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
|
||||
#if NETCOREAPP3_1 || NET5_0_OR_GREATER
|
||||
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
using Microsoft.AspNetCore.Routing;
|
||||
@@ -1,12 +0,0 @@
|
||||
using Microsoft.AspNetCore.Connections;
|
||||
|
||||
namespace MQTTnet.AspNetCore.Extensions
|
||||
{
|
||||
public static class ConnectionBuilderExtensions
|
||||
{
|
||||
public static IConnectionBuilder UseMqtt(this IConnectionBuilder builder)
|
||||
{
|
||||
return builder.UseConnectionHandler<MqttConnectionHandler>();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,36 +1,71 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFrameworks>netstandard2.0;netcoreapp2.1;netcoreapp3.1;net5.0</TargetFrameworks>
|
||||
<Product />
|
||||
<Company />
|
||||
<Authors />
|
||||
<PackageId />
|
||||
<LangVersion>7.2</LangVersion>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
<PublishRepositoryUrl>true</PublishRepositoryUrl>
|
||||
<IncludeSymbols>true</IncludeSymbols>
|
||||
<SymbolPackageFormat>snupkg</SymbolPackageFormat>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<TargetFrameworks>netstandard2.0;netcoreapp2.1;netcoreapp3.1;net5.0;net6.0</TargetFrameworks>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="1.0.0" PrivateAssets="All" />
|
||||
</ItemGroup>
|
||||
<AssemblyName>MQTTnet.AspNetCore</AssemblyName>
|
||||
<RootNamespace>MQTTnet.AspNetCore</RootNamespace>
|
||||
<GeneratePackageOnBuild>True</GeneratePackageOnBuild>
|
||||
<Company>The contributors of MQTTnet</Company>
|
||||
<Product>MQTTnet</Product>
|
||||
<Description>MQTTnet is a high performance .NET library for MQTT based communication. It provides a MQTT client and a MQTT server (broker) and supports v3.1.0, v3.1.1 and v5.0.0 of the MQTT protocol.</Description>
|
||||
<Authors>The contributors of MQTTnet</Authors>
|
||||
<PackageId>MQTTnet.AspNetCore</PackageId>
|
||||
<SignAssembly>false</SignAssembly>
|
||||
<DelaySign>false</DelaySign>
|
||||
<PublishRepositoryUrl>true</PublishRepositoryUrl>
|
||||
<IncludeSymbols>true</IncludeSymbols>
|
||||
<SymbolPackageFormat>snupkg</SymbolPackageFormat>
|
||||
<Copyright>Christian Kratky 2016-2022</Copyright>
|
||||
<PackageProjectUrl>https://github.com/dotnet/MQTTnet</PackageProjectUrl>
|
||||
<RepositoryUrl>https://github.com/dotnet/MQTTnet.git</RepositoryUrl>
|
||||
<RepositoryType>git</RepositoryType>
|
||||
<PackageTags>MQTT Message Queue Telemetry Transport MQTTClient MQTTServer Server MQTTBroker Broker NETStandard IoT InternetOfThings Messaging Hardware Arduino Sensor Actuator M2M ESP Smart Home Cities Automation Xamarin Blazor</PackageTags>
|
||||
<NeutralLanguage>en-US</NeutralLanguage>
|
||||
<EnableNETAnalyzers>false</EnableNETAnalyzers>
|
||||
<EnforceCodeStyleInBuild>false</EnforceCodeStyleInBuild>
|
||||
<PackageIcon>nuget.png</PackageIcon>
|
||||
<EmbedUntrackedSources>true</EmbedUntrackedSources>
|
||||
<ContinuousIntegrationBuild>true</ContinuousIntegrationBuild>
|
||||
<PackageLicenseFile>LICENSE</PackageLicenseFile>
|
||||
<PackageReleaseNotes>For release notes please go to MQTTnet release notes (https://www.nuget.org/packages/MQTTnet/).</PackageReleaseNotes>
|
||||
<DisableImplicitAspNetCoreAnalyzers>true</DisableImplicitAspNetCoreAnalyzers>
|
||||
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
|
||||
<DefineConstants>RELEASE;NETSTANDARD2_0</DefineConstants>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<None Include="..\..\Images\nuget.png">
|
||||
<Pack>True</Pack>
|
||||
<PackagePath>\</PackagePath>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup Condition="'$(TargetFramework)' == 'netcoreapp3.1' or '$(TargetFramework)' == 'net5.0' ">
|
||||
<FrameworkReference Include="Microsoft.AspNetCore.App" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup Condition="'$(TargetFramework)' != 'netcoreapp3.1' and '$(TargetFramework)' != 'net5.0' ">
|
||||
<PackageReference Include="Microsoft.AspNetCore.Http.Connections" Version="1.1.0" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="..\..\LICENSE">
|
||||
<Pack>True</Pack>
|
||||
<PackagePath>\</PackagePath>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\MQTTnet\MQTTnet.csproj" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="1.0.0" PrivateAssets="All" />
|
||||
</ItemGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
|
||||
<DefineConstants>RELEASE;NETSTANDARD2_0</DefineConstants>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup Condition="'$(TargetFramework)' == 'netcoreapp3.1' or '$(TargetFramework)' == 'net5.0' or '$(TargetFramework)' == 'net6.0' ">
|
||||
<FrameworkReference Include="Microsoft.AspNetCore.App" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup Condition="'$(TargetFramework)' != 'netcoreapp3.1' and '$(TargetFramework)' != 'net5.0' and '$(TargetFramework)' != 'net6.0' ">
|
||||
<PackageReference Include="Microsoft.AspNetCore.Http.Connections" Version="1.1.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\MQTTnet\MQTTnet.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
||||
@@ -1,4 +1,8 @@
|
||||
using Microsoft.AspNetCore.Connections;
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using Microsoft.AspNetCore.Connections;
|
||||
using Microsoft.AspNetCore.Http.Connections.Features;
|
||||
using MQTTnet.Adapter;
|
||||
using MQTTnet.AspNetCore.Client.Tcp;
|
||||
@@ -10,7 +14,6 @@ using System.IO.Pipelines;
|
||||
using System.Security.Cryptography.X509Certificates;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using MQTTnet.AspNetCore.Extensions;
|
||||
using MQTTnet.Internal;
|
||||
|
||||
namespace MQTTnet.AspNetCore
|
||||
@@ -18,7 +21,6 @@ namespace MQTTnet.AspNetCore
|
||||
public sealed class MqttConnectionContext : IMqttChannelAdapter
|
||||
{
|
||||
readonly AsyncLock _writerLock = new AsyncLock();
|
||||
readonly SpanBasedMqttPacketBodyReader _reader;
|
||||
|
||||
PipeReader _input;
|
||||
PipeWriter _output;
|
||||
@@ -33,8 +35,6 @@ namespace MQTTnet.AspNetCore
|
||||
_input = Connection.Transport.Input;
|
||||
_output = Connection.Transport.Output;
|
||||
}
|
||||
|
||||
_reader = new SpanBasedMqttPacketBodyReader();
|
||||
}
|
||||
|
||||
public string Endpoint
|
||||
@@ -73,7 +73,7 @@ namespace MQTTnet.AspNetCore
|
||||
|
||||
IHttpContextFeature Http => Connection.Features.Get<IHttpContextFeature>();
|
||||
|
||||
public async Task ConnectAsync(TimeSpan timeout, CancellationToken cancellationToken)
|
||||
public async Task ConnectAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
if (Connection is TcpConnection tcp && !tcp.IsConnected)
|
||||
{
|
||||
@@ -84,7 +84,7 @@ namespace MQTTnet.AspNetCore
|
||||
_output = Connection.Transport.Output;
|
||||
}
|
||||
|
||||
public Task DisconnectAsync(TimeSpan timeout, CancellationToken cancellationToken)
|
||||
public Task DisconnectAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
_input?.Complete();
|
||||
_output?.Complete();
|
||||
@@ -92,7 +92,7 @@ namespace MQTTnet.AspNetCore
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
public async Task<MqttBasePacket> ReceivePacketAsync(CancellationToken cancellationToken)
|
||||
public async Task<MqttPacket> ReceivePacketAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
var input = Connection.Transport.Input;
|
||||
|
||||
@@ -120,7 +120,7 @@ namespace MQTTnet.AspNetCore
|
||||
{
|
||||
if (!buffer.IsEmpty)
|
||||
{
|
||||
if (PacketFormatterAdapter.TryDecode(_reader, buffer, out var packet, out consumed, out observed, out var received))
|
||||
if (PacketFormatterAdapter.TryDecode(buffer, out var packet, out consumed, out observed, out var received))
|
||||
{
|
||||
BytesReceived += received;
|
||||
return packet;
|
||||
@@ -167,13 +167,14 @@ namespace MQTTnet.AspNetCore
|
||||
BytesSent = 0;
|
||||
}
|
||||
|
||||
public async Task SendPacketAsync(MqttBasePacket packet, CancellationToken cancellationToken)
|
||||
public async Task SendPacketAsync(MqttPacket packet, CancellationToken cancellationToken)
|
||||
{
|
||||
var formatter = PacketFormatterAdapter;
|
||||
|
||||
using (await _writerLock.WaitAsync(cancellationToken).ConfigureAwait(false))
|
||||
{
|
||||
var buffer = formatter.Encode(packet);
|
||||
var msg = buffer.AsMemory();
|
||||
var msg = buffer.Join().AsMemory();
|
||||
var output = _output;
|
||||
var result = await output.WriteAsync(msg, cancellationToken).ConfigureAwait(false);
|
||||
if (result.IsCompleted)
|
||||
@@ -181,7 +182,7 @@ namespace MQTTnet.AspNetCore
|
||||
BytesSent += msg.Length;
|
||||
}
|
||||
|
||||
PacketFormatterAdapter.FreeBuffer();
|
||||
PacketFormatterAdapter.Cleanup();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,15 +1,22 @@
|
||||
using Microsoft.AspNetCore.Connections;
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using Microsoft.AspNetCore.Connections;
|
||||
using Microsoft.AspNetCore.Connections.Features;
|
||||
using MQTTnet.Adapter;
|
||||
using MQTTnet.Server;
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using MQTTnet.Diagnostics;
|
||||
using MQTTnet.Formatter;
|
||||
|
||||
namespace MQTTnet.AspNetCore
|
||||
{
|
||||
public class MqttConnectionHandler : ConnectionHandler, IMqttServerAdapter
|
||||
public sealed class MqttConnectionHandler : ConnectionHandler, IMqttServerAdapter
|
||||
{
|
||||
MqttServerOptions _serverOptions;
|
||||
|
||||
public Func<IMqttChannelAdapter, Task> ClientHandler { get; set; }
|
||||
|
||||
public override async Task OnConnectedAsync(ConnectionContext connection)
|
||||
@@ -20,9 +27,8 @@ namespace MQTTnet.AspNetCore
|
||||
{
|
||||
transferFormatFeature.ActiveFormat = TransferFormat.Binary;
|
||||
}
|
||||
|
||||
var writer = new SpanBasedMqttPacketWriter();
|
||||
var formatter = new MqttPacketFormatterAdapter(writer);
|
||||
|
||||
var formatter = new MqttPacketFormatterAdapter(new MqttBufferWriter(_serverOptions.WriterBufferSize, _serverOptions.WriterBufferSizeMax));
|
||||
using (var adapter = new MqttConnectionContext(formatter, connection))
|
||||
{
|
||||
var clientHandler = ClientHandler;
|
||||
@@ -33,8 +39,10 @@ namespace MQTTnet.AspNetCore
|
||||
}
|
||||
}
|
||||
|
||||
public Task StartAsync(IMqttServerOptions options)
|
||||
public Task StartAsync(MqttServerOptions options, IMqttNetLogger logger)
|
||||
{
|
||||
_serverOptions = options;
|
||||
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,27 +1,27 @@
|
||||
using System;
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
using MQTTnet.Adapter;
|
||||
using MQTTnet.Diagnostics.Logger;
|
||||
using MQTTnet.Diagnostics;
|
||||
using MQTTnet.Server;
|
||||
|
||||
namespace MQTTnet.AspNetCore
|
||||
{
|
||||
public sealed class MqttHostedServer : MqttServer, IHostedService
|
||||
{
|
||||
readonly IMqttServerOptions _options;
|
||||
|
||||
public MqttHostedServer(IMqttServerOptions options, IEnumerable<IMqttServerAdapter> adapters, IMqttNetLogger logger)
|
||||
: base(adapters, logger)
|
||||
public MqttHostedServer(MqttServerOptions options, IEnumerable<IMqttServerAdapter> adapters, IMqttNetLogger logger)
|
||||
: base(options, adapters, logger)
|
||||
{
|
||||
_options = options ?? throw new ArgumentNullException(nameof(options));
|
||||
}
|
||||
|
||||
public Task StartAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
_ = StartAsync(_options);
|
||||
_ = StartAsync();
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
@@ -30,4 +30,4 @@ namespace MQTTnet.AspNetCore
|
||||
return StopAsync();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,8 @@
|
||||
using System;
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
|
||||
@@ -1,4 +1,8 @@
|
||||
using Microsoft.AspNetCore.Http;
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using MQTTnet.Adapter;
|
||||
using MQTTnet.Formatter;
|
||||
using MQTTnet.Implementations;
|
||||
@@ -6,23 +10,19 @@ using MQTTnet.Server;
|
||||
using System;
|
||||
using System.Net.WebSockets;
|
||||
using System.Threading.Tasks;
|
||||
using MQTTnet.Diagnostics.Logger;
|
||||
using MQTTnet.Diagnostics;
|
||||
|
||||
namespace MQTTnet.AspNetCore
|
||||
{
|
||||
public sealed class MqttWebSocketServerAdapter : IMqttServerAdapter
|
||||
{
|
||||
readonly IMqttNetLogger _rootLogger;
|
||||
|
||||
public MqttWebSocketServerAdapter(IMqttNetLogger logger)
|
||||
{
|
||||
_rootLogger = logger ?? throw new ArgumentNullException(nameof(logger));
|
||||
}
|
||||
|
||||
IMqttNetLogger _logger = new MqttNetNullLogger();
|
||||
|
||||
public Func<IMqttChannelAdapter, Task> ClientHandler { get; set; }
|
||||
|
||||
public Task StartAsync(IMqttServerOptions options)
|
||||
public Task StartAsync(MqttServerOptions options, IMqttNetLogger logger)
|
||||
{
|
||||
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
@@ -45,11 +45,10 @@ namespace MQTTnet.AspNetCore
|
||||
var clientHandler = ClientHandler;
|
||||
if (clientHandler != null)
|
||||
{
|
||||
var writer = new SpanBasedMqttPacketWriter();
|
||||
var formatter = new MqttPacketFormatterAdapter(writer);
|
||||
var formatter = new MqttPacketFormatterAdapter(new MqttBufferWriter(4096, 65535));
|
||||
var channel = new MqttWebSocketChannel(webSocket, endpoint, isSecureConnection, clientCertificate);
|
||||
|
||||
using (var channelAdapter = new MqttChannelAdapter(channel, formatter, null, _rootLogger))
|
||||
using (var channelAdapter = new MqttChannelAdapter(channel, formatter, null, _logger))
|
||||
{
|
||||
await clientHandler(channelAdapter).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
+14
-11
@@ -1,18 +1,21 @@
|
||||
using System;
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System;
|
||||
using System.Buffers;
|
||||
using MQTTnet.Adapter;
|
||||
using MQTTnet.Exceptions;
|
||||
using MQTTnet.Formatter;
|
||||
using MQTTnet.Packets;
|
||||
|
||||
namespace MQTTnet.AspNetCore.Extensions
|
||||
namespace MQTTnet.AspNetCore
|
||||
{
|
||||
public static class ReaderExtensions
|
||||
{
|
||||
public static bool TryDecode(this MqttPacketFormatterAdapter formatter,
|
||||
SpanBasedMqttPacketBodyReader reader,
|
||||
in ReadOnlySequence<byte> input,
|
||||
out MqttBasePacket packet,
|
||||
out MqttPacket packet,
|
||||
out SequencePosition consumed,
|
||||
out SequencePosition observed,
|
||||
out int bytesRead)
|
||||
@@ -30,7 +33,7 @@ namespace MQTTnet.AspNetCore.Extensions
|
||||
return false;
|
||||
}
|
||||
|
||||
var fixedheader = copy.First.Span[0];
|
||||
var fixedHeader = copy.First.Span[0];
|
||||
if (!TryReadBodyLength(ref copy, out int headerLength, out var bodyLength))
|
||||
{
|
||||
return false;
|
||||
@@ -42,10 +45,9 @@ namespace MQTTnet.AspNetCore.Extensions
|
||||
}
|
||||
|
||||
var bodySlice = copy.Slice(0, bodyLength);
|
||||
var buffer = bodySlice.GetMemory();
|
||||
reader.SetBuffer(buffer);
|
||||
|
||||
var receivedMqttPacket = new ReceivedMqttPacket(fixedheader, reader, buffer.Length + 2);
|
||||
var buffer = bodySlice.GetMemory().ToArray();
|
||||
|
||||
var receivedMqttPacket = new ReceivedMqttPacket(fixedHeader, new ArraySegment<byte>(buffer, 0, buffer.Length), buffer.Length + 2);
|
||||
|
||||
if (formatter.ProtocolVersion == MqttProtocolVersion.Unknown)
|
||||
{
|
||||
@@ -59,7 +61,7 @@ namespace MQTTnet.AspNetCore.Extensions
|
||||
return true;
|
||||
}
|
||||
|
||||
private static ReadOnlyMemory<byte> GetMemory(this in ReadOnlySequence<byte> input)
|
||||
static ReadOnlyMemory<byte> GetMemory(this in ReadOnlySequence<byte> input)
|
||||
{
|
||||
if (input.IsSingleSegment)
|
||||
{
|
||||
@@ -70,7 +72,7 @@ namespace MQTTnet.AspNetCore.Extensions
|
||||
return input.ToArray();
|
||||
}
|
||||
|
||||
private static bool TryReadBodyLength(ref ReadOnlySequence<byte> input, out int headerLength, out int bodyLength)
|
||||
static bool TryReadBodyLength(ref ReadOnlySequence<byte> input, out int headerLength, out int bodyLength)
|
||||
{
|
||||
// Alorithm taken from https://docs.oasis-open.org/mqtt/mqtt/v3.1.1/errata01/os/mqtt-v3.1.1-errata01-os-complete.html.
|
||||
var multiplier = 1;
|
||||
@@ -88,6 +90,7 @@ namespace MQTTnet.AspNetCore.Extensions
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
encodedByte = temp[index];
|
||||
index++;
|
||||
|
||||
+28
-22
@@ -1,17 +1,33 @@
|
||||
using System;
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
using MQTTnet.Adapter;
|
||||
using MQTTnet.Diagnostics;
|
||||
using MQTTnet.Diagnostics.Logger;
|
||||
using MQTTnet.Implementations;
|
||||
using MQTTnet.Server;
|
||||
|
||||
namespace MQTTnet.AspNetCore.Extensions
|
||||
namespace MQTTnet.AspNetCore
|
||||
{
|
||||
public static class ServiceCollectionExtensions
|
||||
{
|
||||
public static IServiceCollection AddHostedMqttServer(this IServiceCollection services, IMqttServerOptions options)
|
||||
public static IServiceCollection AddMqttServer(this IServiceCollection serviceCollection, Action<MqttServerOptionsBuilder> configure = null)
|
||||
{
|
||||
if (serviceCollection is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(serviceCollection));
|
||||
}
|
||||
|
||||
serviceCollection.AddMqttConnectionHandler();
|
||||
serviceCollection.AddHostedMqttServer(configure);
|
||||
|
||||
return serviceCollection;
|
||||
}
|
||||
|
||||
public static IServiceCollection AddHostedMqttServer(this IServiceCollection services, MqttServerOptions options)
|
||||
{
|
||||
if (options == null) throw new ArgumentNullException(nameof(options));
|
||||
|
||||
@@ -22,13 +38,13 @@ namespace MQTTnet.AspNetCore.Extensions
|
||||
return services;
|
||||
}
|
||||
|
||||
public static IServiceCollection AddHostedMqttServer(this IServiceCollection services, Action<MqttServerOptionsBuilder> configure)
|
||||
public static IServiceCollection AddHostedMqttServer(this IServiceCollection services, Action<MqttServerOptionsBuilder> configure = null)
|
||||
{
|
||||
services.AddSingleton<IMqttServerOptions>(s =>
|
||||
services.AddSingleton<MqttServerOptions>(s =>
|
||||
{
|
||||
var builder = new MqttServerOptionsBuilder();
|
||||
configure(builder);
|
||||
return builder.Build();
|
||||
var serverOptionsBuilder = new MqttServerOptionsBuilder();
|
||||
configure?.Invoke(serverOptionsBuilder);
|
||||
return serverOptionsBuilder.Build();
|
||||
});
|
||||
|
||||
services.AddHostedMqttServer();
|
||||
@@ -38,7 +54,7 @@ namespace MQTTnet.AspNetCore.Extensions
|
||||
|
||||
public static IServiceCollection AddHostedMqttServerWithServices(this IServiceCollection services, Action<AspNetMqttServerOptionsBuilder> configure)
|
||||
{
|
||||
services.AddSingleton<IMqttServerOptions>(s =>
|
||||
services.AddSingleton<MqttServerOptions>(s =>
|
||||
{
|
||||
var builder = new AspNetMqttServerOptionsBuilder(s);
|
||||
configure(builder);
|
||||
@@ -50,24 +66,14 @@ namespace MQTTnet.AspNetCore.Extensions
|
||||
return services;
|
||||
}
|
||||
|
||||
public static IServiceCollection AddHostedMqttServer<TOptions>(this IServiceCollection services)
|
||||
where TOptions : class, IMqttServerOptions
|
||||
{
|
||||
services.AddSingleton<IMqttServerOptions, TOptions>();
|
||||
|
||||
services.AddHostedMqttServer();
|
||||
|
||||
return services;
|
||||
}
|
||||
|
||||
private static IServiceCollection AddHostedMqttServer(this IServiceCollection services)
|
||||
static IServiceCollection AddHostedMqttServer(this IServiceCollection services)
|
||||
{
|
||||
var logger = new MqttNetEventLogger();
|
||||
|
||||
services.AddSingleton<IMqttNetLogger>(logger);
|
||||
services.AddSingleton<MqttHostedServer>();
|
||||
services.AddSingleton<IHostedService>(s => s.GetService<MqttHostedServer>());
|
||||
services.AddSingleton<IMqttServer>(s => s.GetService<MqttHostedServer>());
|
||||
services.AddSingleton<MqttServer>(s => s.GetService<MqttHostedServer>());
|
||||
|
||||
return services;
|
||||
}
|
||||
@@ -1,129 +0,0 @@
|
||||
using MQTTnet.Exceptions;
|
||||
using MQTTnet.Formatter;
|
||||
using System;
|
||||
using System.Buffers.Binary;
|
||||
using System.Text;
|
||||
|
||||
namespace MQTTnet.AspNetCore
|
||||
{
|
||||
public class SpanBasedMqttPacketBodyReader : IMqttPacketBodyReader
|
||||
{
|
||||
ReadOnlyMemory<byte> _buffer;
|
||||
|
||||
int _offset;
|
||||
|
||||
public void SetBuffer(ReadOnlyMemory<byte> buffer)
|
||||
{
|
||||
_buffer = buffer;
|
||||
_offset = 0;
|
||||
}
|
||||
|
||||
public int Length => _buffer.Length;
|
||||
|
||||
public bool EndOfStream => _buffer.Length.Equals(_offset);
|
||||
|
||||
public int Offset => _offset;
|
||||
|
||||
public byte ReadByte()
|
||||
{
|
||||
return _buffer.Span[_offset++];
|
||||
}
|
||||
|
||||
public byte[] ReadRemainingData()
|
||||
{
|
||||
return _buffer.Slice(_offset).ToArray();
|
||||
}
|
||||
|
||||
public byte[] ReadWithLengthPrefix()
|
||||
{
|
||||
return ReadSegmentWithLengthPrefix().ToArray();
|
||||
}
|
||||
|
||||
public unsafe string ReadStringWithLengthPrefix()
|
||||
{
|
||||
var buffer = ReadSegmentWithLengthPrefix();
|
||||
if (buffer.Length == 0)
|
||||
{
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
fixed (byte* bytes = &buffer.GetPinnableReference())
|
||||
{
|
||||
var result = Encoding.UTF8.GetString(bytes, buffer.Length);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
public ushort ReadTwoByteInteger()
|
||||
{
|
||||
var result = BinaryPrimitives.ReadUInt16BigEndian(_buffer.Span.Slice(_offset));
|
||||
_offset += 2;
|
||||
return result;
|
||||
}
|
||||
|
||||
public uint ReadFourByteInteger()
|
||||
{
|
||||
var result = BinaryPrimitives.ReadUInt32BigEndian(_buffer.Span.Slice(_offset));
|
||||
_offset += 4;
|
||||
return result;
|
||||
}
|
||||
|
||||
public uint ReadVariableLengthInteger()
|
||||
{
|
||||
var multiplier = 1;
|
||||
var value = 0U;
|
||||
byte encodedByte;
|
||||
|
||||
do
|
||||
{
|
||||
encodedByte = ReadByte();
|
||||
value += (uint)((encodedByte & 127) * multiplier);
|
||||
|
||||
if (multiplier > 2097152)
|
||||
{
|
||||
throw new MqttProtocolViolationException("Variable length integer is invalid.");
|
||||
}
|
||||
|
||||
multiplier *= 128;
|
||||
} while ((encodedByte & 128) != 0);
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
public bool ReadBoolean()
|
||||
{
|
||||
var buffer = ReadByte();
|
||||
|
||||
if (buffer == 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (buffer == 1)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
throw new MqttProtocolViolationException("Boolean values can be 0 or 1 only.");
|
||||
}
|
||||
|
||||
public void Seek(int position)
|
||||
{
|
||||
_offset = position;
|
||||
}
|
||||
|
||||
ReadOnlySpan<byte> ReadSegmentWithLengthPrefix()
|
||||
{
|
||||
var span = _buffer.Span;
|
||||
var length = BinaryPrimitives.ReadUInt16BigEndian(span.Slice(_offset));
|
||||
|
||||
if (Length < _offset + length)
|
||||
{
|
||||
throw new MqttProtocolViolationException($"Expected at least {_offset + 2 + length} bytes but there are only {Length} bytes");
|
||||
}
|
||||
var result = span.Slice(_offset + 2, length);
|
||||
_offset += 2 + length;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,144 +0,0 @@
|
||||
using MQTTnet.Formatter;
|
||||
using System;
|
||||
using System.Buffers;
|
||||
using System.Buffers.Binary;
|
||||
using System.Text;
|
||||
|
||||
namespace MQTTnet.AspNetCore
|
||||
{
|
||||
public class SpanBasedMqttPacketWriter : IMqttPacketWriter
|
||||
{
|
||||
readonly ArrayPool<byte> _pool = ArrayPool<byte>.Create();
|
||||
|
||||
public SpanBasedMqttPacketWriter()
|
||||
{
|
||||
Reset(0);
|
||||
}
|
||||
|
||||
byte[] _buffer;
|
||||
int _position;
|
||||
|
||||
public int Length { get; set; }
|
||||
|
||||
public void FreeBuffer()
|
||||
{
|
||||
_pool.Return(_buffer);
|
||||
}
|
||||
|
||||
public byte[] GetBuffer()
|
||||
{
|
||||
return _buffer;
|
||||
}
|
||||
|
||||
public void Reset(int v)
|
||||
{
|
||||
_buffer = _pool.Rent(1500);
|
||||
Length = v;
|
||||
_position = v;
|
||||
}
|
||||
|
||||
public void Seek(int v)
|
||||
{
|
||||
_position = v;
|
||||
}
|
||||
|
||||
public void Write(byte value)
|
||||
{
|
||||
GrowIfNeeded(1);
|
||||
_buffer[_position] = value;
|
||||
Commit(1);
|
||||
}
|
||||
|
||||
public void Write(ushort value)
|
||||
{
|
||||
GrowIfNeeded(2);
|
||||
|
||||
BinaryPrimitives.WriteUInt16BigEndian(_buffer.AsSpan(_position), value);
|
||||
Commit(2);
|
||||
}
|
||||
|
||||
public void Write(IMqttPacketWriter propertyWriter)
|
||||
{
|
||||
if (propertyWriter == null) throw new ArgumentNullException(nameof(propertyWriter));
|
||||
|
||||
GrowIfNeeded(propertyWriter.Length);
|
||||
Write(propertyWriter.GetBuffer(), 0, propertyWriter.Length);
|
||||
}
|
||||
|
||||
public void Write(byte[] payload, int start, int length)
|
||||
{
|
||||
GrowIfNeeded(length);
|
||||
|
||||
payload.AsSpan(start, length).CopyTo(_buffer.AsSpan(_position));
|
||||
Commit(length);
|
||||
}
|
||||
|
||||
public void WriteVariableLengthInteger(uint value)
|
||||
{
|
||||
GrowIfNeeded(4);
|
||||
|
||||
var x = value;
|
||||
do
|
||||
{
|
||||
var encodedByte = x % 128;
|
||||
x = x / 128;
|
||||
if (x > 0)
|
||||
{
|
||||
encodedByte = encodedByte | 128;
|
||||
}
|
||||
|
||||
_buffer[_position] = (byte)encodedByte;
|
||||
Commit(1);
|
||||
} while (x > 0);
|
||||
}
|
||||
|
||||
public void WriteWithLengthPrefix(string value)
|
||||
{
|
||||
var bytesLength = Encoding.UTF8.GetByteCount(value ?? string.Empty);
|
||||
GrowIfNeeded(bytesLength + 2);
|
||||
|
||||
Write((ushort)bytesLength);
|
||||
Encoding.UTF8.GetBytes(value ?? string.Empty, 0, value?.Length ?? 0, _buffer, _position);
|
||||
Commit(bytesLength);
|
||||
}
|
||||
|
||||
public void WriteWithLengthPrefix(byte[] payload)
|
||||
{
|
||||
GrowIfNeeded(payload.Length + 2);
|
||||
|
||||
Write((ushort)payload.Length);
|
||||
payload.CopyTo(_buffer, _position);
|
||||
Commit(payload.Length);
|
||||
}
|
||||
|
||||
void Commit(int count)
|
||||
{
|
||||
if (_position == Length)
|
||||
{
|
||||
Length += count;
|
||||
}
|
||||
|
||||
_position += count;
|
||||
}
|
||||
|
||||
void GrowIfNeeded(int requiredAdditional)
|
||||
{
|
||||
var requiredTotal = _position + requiredAdditional;
|
||||
if (_buffer.Length >= requiredTotal)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var newBufferLength = _buffer.Length;
|
||||
while (newBufferLength < requiredTotal)
|
||||
{
|
||||
newBufferLength *= 2;
|
||||
}
|
||||
|
||||
var newBuffer = _pool.Rent(newBufferLength);
|
||||
Array.Copy(_buffer, newBuffer, _buffer.Length);
|
||||
_pool.Return(_buffer);
|
||||
_buffer = newBuffer;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user