Merge branch 'feature/server-project-bootstrap' into develop

This commit is contained in:
Christian Kratky
2019-03-10 19:57:32 +01:00
127 changed files with 2952 additions and 490 deletions
@@ -30,8 +30,7 @@ namespace MQTTnet.AspNetCore
var adapter = app.ApplicationServices.GetRequiredService<MqttWebSocketServerAdapter>();
using (var webSocket = await context.WebSockets.AcceptWebSocketAsync(subProtocol))
{
var endpoint = $"{context.Connection.RemoteIpAddress}:{context.Connection.RemotePort}";
await adapter.RunWebSocketConnectionAsync(webSocket, endpoint);
await adapter.RunWebSocketConnectionAsync(webSocket, context);
}
});
@@ -20,6 +20,7 @@ namespace MQTTnet.AspNetCore
}
public string Endpoint => Connection.ConnectionId;
public bool IsSecureConnection => false; // TODO: Fix detection.
public ConnectionContext Connection { get; }
public MqttPacketFormatterAdapter PacketFormatterAdapter { get; }
public event EventHandler ReadingPacketStarted;
@@ -10,7 +10,7 @@ namespace MQTTnet.AspNetCore
{
public class MqttConnectionHandler : ConnectionHandler, IMqttServerAdapter
{
public event EventHandler<MqttServerAdapterClientAcceptedEventArgs> ClientAccepted;
public Action<MqttServerAdapterClientAcceptedEventArgs> ClientAcceptedHandler { get; set; }
public override async Task OnConnectedAsync(ConnectionContext connection)
{
@@ -24,9 +24,9 @@ namespace MQTTnet.AspNetCore
using (var adapter = new MqttConnectionContext(new MqttPacketFormatterAdapter(), connection))
{
var args = new MqttServerAdapterClientAcceptedEventArgs(adapter);
ClientAccepted?.Invoke(this, args);
ClientAcceptedHandler?.Invoke(args);
await args.SessionTask;
await args.SessionTask.ConfigureAwait(false);
}
}
@@ -1,6 +1,7 @@
using System;
using System.Net.WebSockets;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using MQTTnet.Adapter;
using MQTTnet.Diagnostics;
using MQTTnet.Formatter;
@@ -11,7 +12,16 @@ namespace MQTTnet.AspNetCore
{
public class MqttWebSocketServerAdapter : IMqttServerAdapter
{
public event EventHandler<MqttServerAdapterClientAcceptedEventArgs> ClientAccepted;
private readonly IMqttNetChildLogger _logger;
public MqttWebSocketServerAdapter(IMqttNetChildLogger logger)
{
if (logger == null) throw new ArgumentNullException(nameof(logger));
_logger = logger.CreateChildLogger(nameof(MqttTcpServerAdapter));
}
public Action<MqttServerAdapterClientAcceptedEventArgs> ClientAcceptedHandler { get; set; }
public Task StartAsync(IMqttServerOptions options)
{
@@ -23,14 +33,21 @@ namespace MQTTnet.AspNetCore
return Task.CompletedTask;
}
public async Task RunWebSocketConnectionAsync(WebSocket webSocket, string endpoint)
public async Task RunWebSocketConnectionAsync(WebSocket webSocket, HttpContext httpContext)
{
if (webSocket == null) throw new ArgumentNullException(nameof(webSocket));
var clientAdapter = new MqttChannelAdapter(new MqttWebSocketChannel(webSocket, endpoint), new MqttPacketFormatterAdapter(), new MqttNetLogger().CreateChildLogger(nameof(MqttWebSocketServerAdapter)));
var endpoint = $"{httpContext.Connection.RemoteIpAddress}:{httpContext.Connection.RemotePort}";
var clientCertificate = await httpContext.Connection.GetClientCertificateAsync().ConfigureAwait(false);
var isSecureConnection = clientCertificate != null;
clientCertificate?.Dispose();
var channel = new MqttWebSocketChannel(webSocket, endpoint, isSecureConnection);
var clientAdapter = new MqttChannelAdapter(channel, new MqttPacketFormatterAdapter(), _logger.CreateChildLogger(nameof(MqttWebSocketServerAdapter)));
var eventArgs = new MqttServerAdapterClientAcceptedEventArgs(clientAdapter);
ClientAccepted?.Invoke(this, eventArgs);
ClientAcceptedHandler?.Invoke(eventArgs);
if (eventArgs.SessionTask != null)
{
@@ -40,7 +57,6 @@ namespace MQTTnet.AspNetCore
public void Dispose()
{
StopAsync().GetAwaiter().GetResult();
}
}
}
@@ -0,0 +1,31 @@
using System;
using System.Threading.Tasks;
namespace MQTTnet.Extensions.ManagedClient
{
public class ApplicationMessageProcessedHandlerDelegate : IApplicationMessageProcessedHandler
{
private readonly Func<ApplicationMessageProcessedEventArgs, Task> _handler;
public ApplicationMessageProcessedHandlerDelegate(Action<ApplicationMessageProcessedEventArgs> handler)
{
if (handler == null) throw new ArgumentNullException(nameof(handler));
_handler = context =>
{
handler(context);
return Task.FromResult(0);
};
}
public ApplicationMessageProcessedHandlerDelegate(Func<ApplicationMessageProcessedEventArgs, Task> handler)
{
_handler = handler ?? throw new ArgumentNullException(nameof(handler));
}
public Task HandleApplicationMessageProcessedAsync(ApplicationMessageProcessedEventArgs eventArgs)
{
return _handler(eventArgs);
}
}
}
@@ -0,0 +1,31 @@
using System;
using System.Threading.Tasks;
namespace MQTTnet.Extensions.ManagedClient
{
public class ApplicationMessageSkippedHandlerDelegate : IApplicationMessageSkippedHandler
{
private readonly Func<ApplicationMessageSkippedEventArgs, Task> _handler;
public ApplicationMessageSkippedHandlerDelegate(Action<ApplicationMessageSkippedEventArgs> handler)
{
if (handler == null) throw new ArgumentNullException(nameof(handler));
_handler = eventArgs =>
{
handler(eventArgs);
return Task.FromResult(0);
};
}
public ApplicationMessageSkippedHandlerDelegate(Func<ApplicationMessageSkippedEventArgs, Task> handler)
{
_handler = handler ?? throw new ArgumentNullException(nameof(handler));
}
public Task HandleApplicationMessageSkippedAsync(ApplicationMessageSkippedEventArgs eventArgs)
{
return _handler(eventArgs);
}
}
}
@@ -0,0 +1,31 @@
using System;
using System.Threading.Tasks;
namespace MQTTnet.Extensions.ManagedClient
{
public class ConnectingFailedHandlerDelegate : IConnectingFailedHandler
{
private readonly Func<ManagedProcessFailedEventArgs, Task> _handler;
public ConnectingFailedHandlerDelegate(Action<ManagedProcessFailedEventArgs> handler)
{
if (handler == null) throw new ArgumentNullException(nameof(handler));
_handler = eventArgs =>
{
handler(eventArgs);
return Task.FromResult(0);
};
}
public ConnectingFailedHandlerDelegate(Func<ManagedProcessFailedEventArgs, Task> handler)
{
_handler = handler ?? throw new ArgumentNullException(nameof(handler));
}
public Task HandleConnectingFailedAsync(ManagedProcessFailedEventArgs eventArgs)
{
return _handler(eventArgs);
}
}
}
@@ -0,0 +1,9 @@
using System.Threading.Tasks;
namespace MQTTnet.Extensions.ManagedClient
{
public interface IApplicationMessageProcessedHandler
{
Task HandleApplicationMessageProcessedAsync(ApplicationMessageProcessedEventArgs eventArgs);
}
}
@@ -0,0 +1,9 @@
using System.Threading.Tasks;
namespace MQTTnet.Extensions.ManagedClient
{
public interface IApplicationMessageSkippedHandler
{
Task HandleApplicationMessageSkippedAsync(ApplicationMessageSkippedEventArgs eventArgs);
}
}
@@ -0,0 +1,9 @@
using System.Threading.Tasks;
namespace MQTTnet.Extensions.ManagedClient
{
public interface IConnectingFailedHandler
{
Task HandleConnectingFailedAsync(ManagedProcessFailedEventArgs eventArgs);
}
}
@@ -14,19 +14,14 @@ namespace MQTTnet.Extensions.ManagedClient
IManagedMqttClientOptions Options { get; }
IMqttClientConnectedHandler ConnectedHandler { get; set; }
[Obsolete("Use ConnectedHandler instead.")]
event EventHandler<MqttClientConnectedEventArgs> Connected;
IMqttClientDisconnectedHandler DisconnectedHandler { get; set; }
[Obsolete("Use DisconnectedHandler instead.")]
event EventHandler<MqttClientDisconnectedEventArgs> Disconnected;
event EventHandler<ApplicationMessageProcessedEventArgs> ApplicationMessageProcessed;
event EventHandler<ApplicationMessageSkippedEventArgs> ApplicationMessageSkipped;
event EventHandler<MqttManagedProcessFailedEventArgs> ConnectingFailed;
event EventHandler<MqttManagedProcessFailedEventArgs> SynchronizingSubscriptionsFailed;
IApplicationMessageProcessedHandler ApplicationMessageProcessedHandler { get; set; }
IApplicationMessageSkippedHandler ApplicationMessageSkippedHandler { get; set; }
IConnectingFailedHandler ConnectingFailedHandler { get; set; }
ISynchronizingSubscriptionsFailedHandler SynchronizingSubscriptionsFailedHandler { get; set; }
Task StartAsync(IManagedMqttClientOptions options);
Task StopAsync();
@@ -1,5 +1,4 @@
using System;
using MQTTnet.Client;
using MQTTnet.Client.Options;
using MQTTnet.Server;
@@ -0,0 +1,9 @@
using System.Threading.Tasks;
namespace MQTTnet.Extensions.ManagedClient
{
public interface ISynchronizingSubscriptionsFailedHandler
{
Task HandleSynchronizingSubscriptionsFailedAsync(ManagedProcessFailedEventArgs eventArgs);
}
}
@@ -13,8 +13,6 @@ using MQTTnet.Exceptions;
using MQTTnet.Internal;
using MQTTnet.Protocol;
using MQTTnet.Server;
using MqttClientConnectedEventArgs = MQTTnet.Client.Connecting.MqttClientConnectedEventArgs;
using MqttClientDisconnectedEventArgs = MQTTnet.Client.Disconnecting.MqttClientDisconnectedEventArgs;
namespace MQTTnet.Extensions.ManagedClient
{
@@ -36,14 +34,9 @@ namespace MQTTnet.Extensions.ManagedClient
public ManagedMqttClient(IMqttClient mqttClient, IMqttNetChildLogger logger)
{
if (logger == null) throw new ArgumentNullException(nameof(logger));
_mqttClient = mqttClient ?? throw new ArgumentNullException(nameof(mqttClient));
_mqttClient.UseConnectedHandler(OnConnected);
_mqttClient.UseDisconnectedHandler(OnDisconnected);
_mqttClient.UseReceivedApplicationMessageHandler(OnApplicationMessageReceived);
if (logger == null) throw new ArgumentNullException(nameof(logger));
_logger = logger.CreateChildLogger(nameof(ManagedMqttClient));
}
@@ -52,25 +45,31 @@ namespace MQTTnet.Extensions.ManagedClient
public int PendingApplicationMessagesCount => _messageQueue.Count;
public IManagedMqttClientOptions Options { get; private set; }
public IMqttClientConnectedHandler ConnectedHandler { get; set; }
public event EventHandler<MqttClientConnectedEventArgs> Connected;
public IMqttClientDisconnectedHandler DisconnectedHandler { get; set; }
public event EventHandler<MqttClientDisconnectedEventArgs> Disconnected;
public IMqttApplicationMessageHandler ReceivedApplicationMessageHandler
public IMqttClientConnectedHandler ConnectedHandler
{
get => _mqttClient.ReceivedApplicationMessageHandler;
set => _mqttClient.ReceivedApplicationMessageHandler = value;
get => _mqttClient.ConnectedHandler;
set => _mqttClient.ConnectedHandler = value;
}
public event EventHandler<MqttApplicationMessageReceivedEventArgs> ApplicationMessageReceived;
public event EventHandler<ApplicationMessageProcessedEventArgs> ApplicationMessageProcessed;
public event EventHandler<ApplicationMessageSkippedEventArgs> ApplicationMessageSkipped;
public IMqttClientDisconnectedHandler DisconnectedHandler
{
get => _mqttClient.DisconnectedHandler;
set => _mqttClient.DisconnectedHandler = value;
}
public event EventHandler<MqttManagedProcessFailedEventArgs> ConnectingFailed;
public event EventHandler<MqttManagedProcessFailedEventArgs> SynchronizingSubscriptionsFailed;
public IMqttApplicationMessageReceivedHandler ApplicationMessageReceivedHandler
{
get => _mqttClient.ApplicationMessageReceivedHandler;
set => _mqttClient.ApplicationMessageReceivedHandler = value;
}
public IApplicationMessageProcessedHandler ApplicationMessageProcessedHandler { get; set; }
public IApplicationMessageSkippedHandler ApplicationMessageSkippedHandler { get; set; }
public IConnectingFailedHandler ConnectingFailedHandler { get; set; }
public ISynchronizingSubscriptionsFailedHandler SynchronizingSubscriptionsFailedHandler { get; set; }
public async Task StartAsync(IManagedMqttClientOptions options)
{
@@ -129,28 +128,45 @@ namespace MQTTnet.Extensions.ManagedClient
if (applicationMessage == null) throw new ArgumentNullException(nameof(applicationMessage));
ManagedMqttApplicationMessage removedMessage = null;
lock (_messageQueue)
ApplicationMessageSkippedEventArgs applicationMessageSkippedEventArgs = null;
try
{
if (_messageQueue.Count >= Options.MaxPendingMessages)
lock (_messageQueue)
{
if (Options.PendingMessagesOverflowStrategy == MqttPendingMessagesOverflowStrategy.DropNewMessage)
if (_messageQueue.Count >= Options.MaxPendingMessages)
{
_logger.Verbose("Skipping publish of new application message because internal queue is full.");
ApplicationMessageSkipped?.Invoke(this, new ApplicationMessageSkippedEventArgs(applicationMessage));
return;
if (Options.PendingMessagesOverflowStrategy == MqttPendingMessagesOverflowStrategy.DropNewMessage)
{
_logger.Verbose("Skipping publish of new application message because internal queue is full.");
applicationMessageSkippedEventArgs = new ApplicationMessageSkippedEventArgs(applicationMessage);
return;
}
if (Options.PendingMessagesOverflowStrategy == MqttPendingMessagesOverflowStrategy.DropOldestQueuedMessage)
{
removedMessage = _messageQueue.RemoveFirst();
_logger.Verbose("Removed oldest application message from internal queue because it is full.");
applicationMessageSkippedEventArgs = new ApplicationMessageSkippedEventArgs(removedMessage);
}
}
if (Options.PendingMessagesOverflowStrategy == MqttPendingMessagesOverflowStrategy.DropOldestQueuedMessage)
_messageQueue.Enqueue(applicationMessage);
}
}
finally
{
if (applicationMessageSkippedEventArgs != null)
{
var applicationMessageSkippedHandler = ApplicationMessageSkippedHandler;
if (applicationMessageSkippedHandler != null)
{
removedMessage = _messageQueue.RemoveFirst();
_logger.Verbose("Removed oldest application message from internal queue because it is full.");
ApplicationMessageSkipped?.Invoke(this, new ApplicationMessageSkippedEventArgs(removedMessage));
await applicationMessageSkippedHandler.HandleApplicationMessageSkippedAsync(applicationMessageSkippedEventArgs).ConfigureAwait(false);
}
}
_messageQueue.Enqueue(applicationMessage);
}
if (_storageManager != null)
{
if (removedMessage != null)
@@ -355,7 +371,7 @@ namespace MQTTnet.Extensions.ManagedClient
}
finally
{
ApplicationMessageProcessed?.Invoke(this, new ApplicationMessageProcessedEventArgs(message, transmitException));
ApplicationMessageProcessedHandler?.HandleApplicationMessageProcessedAsync(new ApplicationMessageProcessedEventArgs(message, transmitException)).GetAwaiter().GetResult();
}
}
@@ -398,7 +414,11 @@ namespace MQTTnet.Extensions.ManagedClient
_logger.Warning(exception, "Synchronizing subscriptions failed.");
_subscriptionsNotPushed = true;
SynchronizingSubscriptionsFailed?.Invoke(this, new MqttManagedProcessFailedEventArgs(exception));
var synchronizingSubscriptionsFailedHandler = SynchronizingSubscriptionsFailedHandler;
if (SynchronizingSubscriptionsFailedHandler != null)
{
await synchronizingSubscriptionsFailedHandler.HandleSynchronizingSubscriptionsFailedAsync(new ManagedProcessFailedEventArgs(exception)).ConfigureAwait(false);
}
}
}
@@ -416,29 +436,16 @@ namespace MQTTnet.Extensions.ManagedClient
}
catch (Exception exception)
{
ConnectingFailed?.Invoke(this, new MqttManagedProcessFailedEventArgs(exception));
var connectingFailedHandler = ConnectingFailedHandler;
if (connectingFailedHandler != null)
{
await connectingFailedHandler.HandleConnectingFailedAsync(new ManagedProcessFailedEventArgs(exception)).ConfigureAwait(false);
}
return ReconnectionResult.NotConnected;
}
}
private Task OnApplicationMessageReceived(MqttApplicationMessageHandlerContext context)
{
ApplicationMessageReceived?.Invoke(this, new MqttApplicationMessageReceivedEventArgs(context.SenderClientId, context.ApplicationMessage));
return Task.FromResult(0);
}
private Task OnDisconnected(MqttClientDisconnectedEventArgs eventArgs)
{
Disconnected?.Invoke(this, eventArgs);
return DisconnectedHandler?.HandleDisconnectedAsync(eventArgs);
}
private Task OnConnected(MqttClientConnectedEventArgs eventArgs)
{
Connected?.Invoke(this, eventArgs);
return ConnectedHandler?.HandleConnectedAsync(eventArgs);
}
private void StartPublishing()
{
if (_publishingCancellationToken != null)
@@ -60,28 +60,28 @@ namespace MQTTnet.Extensions.ManagedClient
return client;
}
public static IManagedMqttClient UseReceivedApplicationMessageHandler(this IManagedMqttClient client, Func<MqttApplicationMessageHandlerContext, Task> handler)
public static IManagedMqttClient UseApplicationMessageReceivedHandler(this IManagedMqttClient client, Func<MqttApplicationMessageReceivedEventArgs, Task> handler)
{
if (handler == null)
{
client.ReceivedApplicationMessageHandler = null;
client.ApplicationMessageReceivedHandler = null;
return client;
}
client.ReceivedApplicationMessageHandler = new MqttApplicationMessageHandlerDelegate(handler);
client.ApplicationMessageReceivedHandler = new MqttApplicationMessageReceivedHandlerDelegate(handler);
return client;
}
public static IManagedMqttClient UseReceivedApplicationMessageHandler(this IManagedMqttClient client, Action<MqttApplicationMessageHandlerContext> handler)
public static IManagedMqttClient UseApplicationMessageReceivedHandler(this IManagedMqttClient client, Action<MqttApplicationMessageReceivedEventArgs> handler)
{
if (handler == null)
{
client.ReceivedApplicationMessageHandler = null;
client.ApplicationMessageReceivedHandler = null;
return client;
}
client.ReceivedApplicationMessageHandler = new MqttApplicationMessageHandlerDelegate(handler);
client.ApplicationMessageReceivedHandler = new MqttApplicationMessageReceivedHandlerDelegate(handler);
return client;
}
@@ -2,9 +2,9 @@
namespace MQTTnet.Extensions.ManagedClient
{
public class MqttManagedProcessFailedEventArgs : EventArgs
public class ManagedProcessFailedEventArgs : EventArgs
{
public MqttManagedProcessFailedEventArgs(Exception exception)
public ManagedProcessFailedEventArgs(Exception exception)
{
Exception = exception;
}
@@ -1,19 +1,18 @@
using System;
using MQTTnet.Client;
using MQTTnet.Diagnostics;
namespace MQTTnet.Extensions.ManagedClient
{
public static class MqttFactoryExtensions
{
public static IManagedMqttClient CreateManagedMqttClient(this IMqttClientFactory factory)
public static IManagedMqttClient CreateManagedMqttClient(this IMqttFactory factory)
{
if (factory == null) throw new ArgumentNullException(nameof(factory));
return new ManagedMqttClient(factory.CreateMqttClient(), new MqttNetLogger().CreateChildLogger());
return new ManagedMqttClient(factory.CreateMqttClient(), factory.DefaultLogger.CreateChildLogger());
}
public static IManagedMqttClient CreateManagedMqttClient(this IMqttClientFactory factory, IMqttNetLogger logger)
public static IManagedMqttClient CreateManagedMqttClient(this IMqttFactory factory, IMqttNetLogger logger)
{
if (factory == null) throw new ArgumentNullException(nameof(factory));
if (logger == null) throw new ArgumentNullException(nameof(logger));
@@ -0,0 +1,31 @@
using System;
using System.Threading.Tasks;
namespace MQTTnet.Extensions.ManagedClient
{
public class SynchronizingSubscriptionsFailedHandlerDelegate : ISynchronizingSubscriptionsFailedHandler
{
private readonly Func<ManagedProcessFailedEventArgs, Task> _handler;
public SynchronizingSubscriptionsFailedHandlerDelegate(Action<ManagedProcessFailedEventArgs> handler)
{
if (handler == null) throw new ArgumentNullException(nameof(handler));
_handler = context =>
{
handler(context);
return Task.FromResult(0);
};
}
public SynchronizingSubscriptionsFailedHandlerDelegate(Func<ManagedProcessFailedEventArgs, Task> handler)
{
_handler = handler ?? throw new ArgumentNullException(nameof(handler));
}
public Task HandleSynchronizingSubscriptionsFailedAsync(ManagedProcessFailedEventArgs eventArgs)
{
return _handler(eventArgs);
}
}
}
+19 -5
View File
@@ -13,12 +13,17 @@ namespace MQTTnet.Extensions.Rpc
{
private readonly ConcurrentDictionary<string, TaskCompletionSource<byte[]>> _waitingCalls = new ConcurrentDictionary<string, TaskCompletionSource<byte[]>>();
private readonly IMqttClient _mqttClient;
private readonly RpcAwareApplicationMessageReceivedHandler _applicationMessageReceivedHandler;
public MqttRpcClient(IMqttClient mqttClient)
{
_mqttClient = mqttClient ?? throw new ArgumentNullException(nameof(mqttClient));
_mqttClient.ApplicationMessageReceived += OnApplicationMessageReceived;
_applicationMessageReceivedHandler = new RpcAwareApplicationMessageReceivedHandler(
mqttClient.ApplicationMessageReceivedHandler,
HandleApplicationMessageReceivedAsync);
_mqttClient.ApplicationMessageReceivedHandler = _applicationMessageReceivedHandler;
}
public Task<byte[]> ExecuteAsync(TimeSpan timeout, string methodName, string payload, MqttQualityOfServiceLevel qualityOfServiceLevel)
@@ -45,6 +50,11 @@ namespace MQTTnet.Extensions.Rpc
throw new ArgumentException("The method name cannot contain /, + or #.");
}
if (!(_mqttClient.ApplicationMessageReceivedHandler is RpcAwareApplicationMessageReceivedHandler))
{
throw new InvalidOperationException("The application message received handler was modified.");
}
var requestTopic = $"MQTTnet.RPC/{Guid.NewGuid():N}/{methodName}";
var responseTopic = requestTopic + "/response";
@@ -102,26 +112,30 @@ namespace MQTTnet.Extensions.Rpc
}
}
private void OnApplicationMessageReceived(object sender, MqttApplicationMessageReceivedEventArgs eventArgs)
private Task HandleApplicationMessageReceivedAsync(MqttApplicationMessageReceivedEventArgs eventArgs)
{
if (!_waitingCalls.TryRemove(eventArgs.ApplicationMessage.Topic, out var tcs))
{
return;
return Task.FromResult(0);
}
if (tcs.Task.IsCompleted || tcs.Task.IsCanceled)
{
return;
return Task.FromResult(0);
}
tcs.TrySetResult(eventArgs.ApplicationMessage.Payload);
return Task.FromResult(0);
}
public void Dispose()
{
_mqttClient.ApplicationMessageReceivedHandler = _applicationMessageReceivedHandler.OriginalHandler;
foreach (var tcs in _waitingCalls)
{
tcs.Value.SetCanceled();
tcs.Value.TrySetCanceled();
}
_waitingCalls.Clear();
@@ -0,0 +1,31 @@
using System;
using System.Threading.Tasks;
using MQTTnet.Client.Receiving;
namespace MQTTnet.Extensions.Rpc
{
public class RpcAwareApplicationMessageReceivedHandler : IMqttApplicationMessageReceivedHandler
{
private readonly Func<MqttApplicationMessageReceivedEventArgs, Task> _handleReceivedApplicationMessageAsync;
public RpcAwareApplicationMessageReceivedHandler(
IMqttApplicationMessageReceivedHandler originalHandler,
Func<MqttApplicationMessageReceivedEventArgs, Task> handleReceivedApplicationMessageAsync)
{
OriginalHandler = originalHandler;
_handleReceivedApplicationMessageAsync = handleReceivedApplicationMessageAsync ?? throw new ArgumentNullException(nameof(handleReceivedApplicationMessageAsync));
}
public IMqttApplicationMessageReceivedHandler OriginalHandler { get; }
public async Task HandleApplicationMessageReceivedAsync(MqttApplicationMessageReceivedEventArgs eventArgs)
{
if (OriginalHandler != null)
{
await OriginalHandler.HandleApplicationMessageReceivedAsync(eventArgs).ConfigureAwait(false);
}
await _handleReceivedApplicationMessageAsync(eventArgs).ConfigureAwait(false);
}
}
}
@@ -0,0 +1,132 @@
using System.IO;
using System.Net;
namespace MQTTnet.Server.Configuration
{
/// <summary>
/// Listen Entry Settings Model
/// </summary>
public class ListenModel
{
/// <summary>
/// Constructor
/// </summary>
public ListenModel()
{
}
/// <summary>
/// Path to Certificate
/// </summary>
public string CertificatePath { get; set; }
/// <summary>
/// Enabled / Disable
/// </summary>
public bool Enabled { get; set; } = true;
/// <summary>
/// Listen Address
/// </summary>
public string IPv4 { get; set; }
/// <summary>
/// Listen Address
/// </summary>
public string IPv6 { get; set; }
/// <summary>
/// Listen Port
/// </summary>
public int Port { get; set; } = 1883;
/// <summary>
/// Read Certificate file
/// </summary>
/// <returns></returns>
public byte[] ReadCertificate()
{
if (string.IsNullOrEmpty(CertificatePath) || string.IsNullOrWhiteSpace(CertificatePath))
{
throw new FileNotFoundException("No path set");
}
if (!File.Exists(CertificatePath))
{
throw new FileNotFoundException($"Could not find Certificate in path: {CertificatePath}");
}
return File.ReadAllBytes(CertificatePath);
}
/// <summary>
/// Read IPv4
/// </summary>
/// <returns></returns>
public bool TryReadIPv4(out IPAddress address)
{
if (IPv4 == "*")
{
address = IPAddress.Parse("0.0.0.0");
return true;
}
if (IPv4 == "localhost")
{
address = IPAddress.Parse("127.0.0.1");
return true;
}
if (IPv4 == "disable")
{
address = IPAddress.None;
return true;
}
if (IPAddress.TryParse(IPv4, out var ip))
{
address = ip;
return true;
}
else
{
throw new System.Exception($"Could not parse IPv4 address: {IPv4}");
}
}
/// <summary>
/// Read IPv6
/// </summary>
/// <returns></returns>
public bool TryReadIPv6(out IPAddress address)
{
if (IPv6 == "*")
{
address = IPAddress.Parse("::");
return true;
}
if (IPv6 == "localhost")
{
address = IPAddress.Parse("::1");
return true;
}
if (IPv6 == "disable")
{
address = IPAddress.None;
return true;
}
if (IPAddress.TryParse(IPv6, out var ip))
{
address = ip;
return true;
}
else
{
throw new System.Exception($"Could not parse IPv6 address: {IPv6}");
}
}
}
}
@@ -0,0 +1,42 @@
namespace MQTTnet.Server.Configuration
{
/// <summary>
/// Main Settings Model
/// </summary>
public class SettingsModel
{
public SettingsModel()
{
}
/// <summary>
/// Set default connection timeout in seconds
/// </summary>
public int CommunicationTimeout { get; set; } = 15;
/// <summary>
/// Set 0 to disable connection backlogging
/// </summary>
public int ConnectionBacklog { get; set; }
/// <summary>
/// Enable support for persistent sessions
/// </summary>
public bool EnablePersistentSessions { get; set; } = false;
/// <summary>
/// Listen Settings
/// </summary>
public ListenModel EndPoint { get; set; } = new ListenModel();
/// <summary>
/// Encryption Listen Settings
/// </summary>
public ListenModel EndPointEncryption { get; set; } = new ListenModel();
/// <summary>
/// Set limit for max pending messages per client
/// </summary>
public int MaxPendingMessagesPerClient { get; set; } = 250;
}
}
@@ -0,0 +1,42 @@
using System.Collections.Generic;
using Microsoft.AspNetCore.Mvc;
namespace MQTTnet.Server.Controllers
{
[Route("api/[controller]")]
[ApiController]
public class ValuesController : ControllerBase
{
// GET api/values
[HttpGet]
public ActionResult<IEnumerable<string>> Get()
{
return new string[] { "value1", "value2" };
}
// GET api/values/5
[HttpGet("{id}")]
public ActionResult<string> Get(int id)
{
return "value";
}
// POST api/values
[HttpPost]
public void Post([FromBody] string value)
{
}
// PUT api/values/5
[HttpPut("{id}")]
public void Put(int id, [FromBody] string value)
{
}
// DELETE api/values/5
[HttpDelete("{id}")]
public void Delete(int id)
{
}
}
}
+21
View File
@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2017 Christian Kratky
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
@@ -0,0 +1,43 @@
using System;
using MQTTnet.Diagnostics;
namespace MQTTnet.Server.Logging
{
public class MqttNetChildLoggerWrapper : IMqttNetChildLogger
{
private readonly MqttNetLoggerWrapper _logger;
private readonly string _source;
public MqttNetChildLoggerWrapper(string source, MqttNetLoggerWrapper logger)
{
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
_source = source;
}
public IMqttNetChildLogger CreateChildLogger(string source = null)
{
return _logger.CreateChildLogger(source);
}
public void Verbose(string message, params object[] parameters)
{
_logger.Publish(MqttNetLogLevel.Verbose, _source, message, parameters, null);
}
public void Info(string message, params object[] parameters)
{
_logger.Publish(MqttNetLogLevel.Info, _source, message, parameters, null);
}
public void Warning(Exception exception, string message, params object[] parameters)
{
_logger.Publish(MqttNetLogLevel.Warning, _source, message, parameters, exception);
}
public void Error(Exception exception, string message, params object[] parameters)
{
_logger.Publish(MqttNetLogLevel.Error, _source, message, parameters, exception);
}
}
}
@@ -0,0 +1,48 @@
using System;
using Microsoft.Extensions.Logging;
using MQTTnet.Diagnostics;
namespace MQTTnet.Server.Logging
{
public class MqttNetLoggerWrapper : IMqttNetLogger
{
private readonly ILogger<MqttServer> _logger;
public MqttNetLoggerWrapper(ILogger<MqttServer> logger)
{
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
}
public event EventHandler<MqttNetLogMessagePublishedEventArgs> LogMessagePublished;
public IMqttNetChildLogger CreateChildLogger(string source = null)
{
return new MqttNetChildLoggerWrapper(source, this);
}
public void Publish(MqttNetLogLevel logLevel, string source, string message, object[] parameters, Exception exception)
{
var convertedLogLevel = ConvertLogLevel(logLevel);
if (!_logger.IsEnabled(convertedLogLevel))
{
return;
}
_logger.Log(convertedLogLevel, exception, message, parameters);
}
private static LogLevel ConvertLogLevel(MqttNetLogLevel logLevel)
{
switch (logLevel)
{
case MqttNetLogLevel.Error: return LogLevel.Error;
case MqttNetLogLevel.Warning: return LogLevel.Warning;
case MqttNetLogLevel.Info: return LogLevel.Information;
case MqttNetLogLevel.Verbose: return LogLevel.Trace;
}
return LogLevel.Debug;
}
}
}
@@ -0,0 +1,83 @@
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>netcoreapp2.2</TargetFramework>
<AspNetCoreHostingModel>InProcess</AspNetCoreHostingModel>
<AssemblyName>MQTTnet.Server</AssemblyName>
<RootNamespace>MQTTnet.Server</RootNamespace>
<GeneratePackageOnBuild>False</GeneratePackageOnBuild>
<Company />
<Product>MQTTnet</Product>
<Description />
<Authors />
<PackageId />
<SignAssembly>false</SignAssembly>
<DelaySign>false</DelaySign>
<LangVersion>latest</LangVersion>
<TypeScriptToolsVersion>3.3</TypeScriptToolsVersion>
</PropertyGroup>
<PropertyGroup>
<StartupObject></StartupObject>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
<DocumentationFile></DocumentationFile>
<WarningsAsErrors>NU1605</WarningsAsErrors>
<NoWarn>1701;1702</NoWarn>
</PropertyGroup>
<ItemGroup>
<Content Remove="wwwroot\app\app.ts" />
</ItemGroup>
<ItemGroup>
<Content Update="appsettings.json">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content>
<Content Update="wwwroot\app\app.js">
<CopyToOutputDirectory>Never</CopyToOutputDirectory>
</Content>
<Content Update="wwwroot\app\app.js.map">
<CopyToOutputDirectory>Never</CopyToOutputDirectory>
</Content>
<Content Update="wwwroot\Index.html">
<CopyToOutputDirectory>Never</CopyToOutputDirectory>
</Content>
</ItemGroup>
<ItemGroup>
<PackageReference Include="IronPython" Version="2.7.9" />
<PackageReference Include="IronPython.StdLib" Version="2.7.9" />
<PackageReference Include="Microsoft.AspNetCore.App" />
<PackageReference Include="Microsoft.AspNetCore.Razor.Design" Version="2.2.0" PrivateAssets="All" />
<PackageReference Include="Microsoft.AspNetCore.StaticFiles" Version="2.2.0" />
<PackageReference Include="Microsoft.AspNetCore.WebSockets" Version="2.2.1" />
<PackageReference Include="Swashbuckle.AspNetCore.SwaggerGen" Version="4.0.1" />
<PackageReference Include="Swashbuckle.AspNetCore.SwaggerUI" Version="4.0.1" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\MQTTnet.AspnetCore\MQTTnet.AspNetCore.csproj" />
<ProjectReference Include="..\MQTTnet\MQTTnet.csproj" />
</ItemGroup>
<ItemGroup>
<None Update="LICENSE">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Update="Scripts\readme.md">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Update="Scripts\00_sample.py">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
</ItemGroup>
<ItemGroup>
<TypeScriptCompile Include="wwwroot\app\app.ts">
<CopyToOutputDirectory>Never</CopyToOutputDirectory>
</TypeScriptCompile>
</ItemGroup>
</Project>
@@ -0,0 +1,32 @@
using System;
using System.Collections.Generic;
using Microsoft.Extensions.Logging;
using MQTTnet.Adapter;
using MQTTnet.Diagnostics;
using MQTTnet.Server.Logging;
namespace MQTTnet.Server.Mqtt
{
public class CustomMqttFactory
{
private readonly MqttFactory _mqttFactory;
public CustomMqttFactory(ILogger<MqttServer> logger)
{
if (logger == null) throw new ArgumentNullException(nameof(logger));
Logger = new MqttNetLoggerWrapper(logger);
_mqttFactory = new MqttFactory(Logger);
}
public IMqttNetLogger Logger { get; }
public IMqttServer CreateMqttServer(List<IMqttServerAdapter> adapters)
{
if (adapters == null) throw new ArgumentNullException(nameof(adapters));
return _mqttFactory.CreateMqttServer(adapters);
}
}
}
@@ -0,0 +1,66 @@
using System;
using System.Threading.Tasks;
using IronPython.Runtime;
using Microsoft.Extensions.Logging;
using MQTTnet.Protocol;
using MQTTnet.Server.Scripting;
namespace MQTTnet.Server.Mqtt
{
public class MqttApplicationMessageInterceptor : IMqttServerApplicationMessageInterceptor
{
private readonly PythonScriptHostService _pythonScriptHostService;
private readonly ILogger _logger;
public MqttApplicationMessageInterceptor(PythonScriptHostService pythonScriptHostService, ILogger<MqttApplicationMessageInterceptor> logger)
{
_pythonScriptHostService = pythonScriptHostService ?? throw new ArgumentNullException(nameof(pythonScriptHostService));
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
}
public Task InterceptApplicationMessagePublishAsync(MqttApplicationMessageInterceptorContext context)
{
try
{
var pythonContext = new PythonDictionary
{
{ "accept_publish", context.AcceptPublish },
{ "close_connection", context.CloseConnection },
{ "client_id", context.ClientId },
{ "topic", context.ApplicationMessage.Topic },
{ "qos", (int)context.ApplicationMessage.QualityOfServiceLevel },
{ "retain", context.ApplicationMessage.Retain }
};
_pythonScriptHostService.InvokeOptionalFunction("on_intercept_application_message", pythonContext);
context.AcceptPublish = (bool)pythonContext.get("accept_publish", context.AcceptPublish);
context.CloseConnection = (bool)pythonContext.get("close_connection", context.CloseConnection);
context.ApplicationMessage.Topic = (string)pythonContext.get("topic", context.ApplicationMessage.Topic);
context.ApplicationMessage.QualityOfServiceLevel = (MqttQualityOfServiceLevel)(int)pythonContext.get("qos", (int)context.ApplicationMessage.QualityOfServiceLevel);
}
catch (Exception exception)
{
_logger.LogError(exception, "Error while intercepting application message.");
}
return Task.CompletedTask;
}
// TODO: Create dump(object) method in wrapper (creates JSON and prints it).
public class PythonMqttApplicationMessageInterceptorContext
{
public bool accept_connection;
public bool accept_publish;
public string client_id;
public string topic;
public int qos;
public bool retain;
}
}
}
@@ -0,0 +1,39 @@
using System;
using System.Threading.Tasks;
using IronPython.Runtime;
using Microsoft.Extensions.Logging;
using MQTTnet.Server.Scripting;
namespace MQTTnet.Server.Mqtt
{
public class MqttClientConnectedHandler : IMqttServerClientConnectedHandler
{
private readonly PythonScriptHostService _pythonScriptHostService;
private readonly ILogger _logger;
public MqttClientConnectedHandler(PythonScriptHostService pythonScriptHostService, ILogger<MqttClientConnectedHandler> logger)
{
_pythonScriptHostService = pythonScriptHostService ?? throw new ArgumentNullException(nameof(pythonScriptHostService));
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
}
public Task HandleClientConnectedAsync(MqttServerClientConnectedEventArgs eventArgs)
{
try
{
var pythonEventArgs = new PythonDictionary
{
{ "client_id", eventArgs.ClientId }
};
_pythonScriptHostService.InvokeOptionalFunction("on_client_connected", pythonEventArgs);
}
catch (Exception exception)
{
_logger.LogError(exception, "Error while handling client connected event.");
}
return Task.CompletedTask;
}
}
}
@@ -0,0 +1,40 @@
using System;
using System.Threading.Tasks;
using IronPython.Runtime;
using Microsoft.Extensions.Logging;
using MQTTnet.Server.Scripting;
namespace MQTTnet.Server.Mqtt
{
public class MqttClientDisconnectedHandler : IMqttServerClientDisconnectedHandler
{
private readonly PythonScriptHostService _pythonScriptHostService;
private readonly ILogger _logger;
public MqttClientDisconnectedHandler(PythonScriptHostService pythonScriptHostService, ILogger<MqttClientDisconnectedHandler> logger)
{
_pythonScriptHostService = pythonScriptHostService ?? throw new ArgumentNullException(nameof(pythonScriptHostService));
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
}
public Task HandleClientDisconnectedAsync(MqttServerClientDisconnectedEventArgs eventArgs)
{
try
{
var pythonEventArgs = new PythonDictionary
{
{ "client_id", eventArgs.ClientId },
{ "type", PythonConvert.Pythonfy(eventArgs.DisconnectType) }
};
_pythonScriptHostService.InvokeOptionalFunction("on_client_disconnected", pythonEventArgs);
}
catch (Exception exception)
{
_logger.LogError(exception, "Error while handling client disconnected event.");
}
return Task.CompletedTask;
}
}
}
@@ -0,0 +1,41 @@
using System;
using System.Threading.Tasks;
using IronPython.Runtime;
using Microsoft.Extensions.Logging;
using MQTTnet.Server.Scripting;
namespace MQTTnet.Server.Mqtt
{
public class MqttClientSubscribedTopicHandler : IMqttServerClientSubscribedTopicHandler
{
private readonly PythonScriptHostService _pythonScriptHostService;
private readonly ILogger _logger;
public MqttClientSubscribedTopicHandler(PythonScriptHostService pythonScriptHostService, ILogger<MqttClientSubscribedTopicHandler> logger)
{
_pythonScriptHostService = pythonScriptHostService ?? throw new ArgumentNullException(nameof(pythonScriptHostService));
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
}
public Task HandleClientSubscribedTopicAsync(MqttServerClientSubscribedTopicEventArgs eventArgs)
{
try
{
var pythonEventArgs = new PythonDictionary
{
{ "client_id", eventArgs.ClientId },
{ "topic", eventArgs.TopicFilter.Topic },
{ "qos", (int)eventArgs.TopicFilter.QualityOfServiceLevel }
};
_pythonScriptHostService.InvokeOptionalFunction("on_client_subscribed_topic", pythonEventArgs);
}
catch (Exception exception)
{
_logger.LogError(exception, "Error while handling client subscribed topic event.");
}
return Task.CompletedTask;
}
}
}
@@ -0,0 +1,40 @@
using System;
using System.Threading.Tasks;
using IronPython.Runtime;
using Microsoft.Extensions.Logging;
using MQTTnet.Server.Scripting;
namespace MQTTnet.Server.Mqtt
{
public class MqttClientUnsubscribedTopicHandler : IMqttServerClientUnsubscribedTopicHandler
{
private readonly PythonScriptHostService _pythonScriptHostService;
private readonly ILogger _logger;
public MqttClientUnsubscribedTopicHandler(PythonScriptHostService pythonScriptHostService, ILogger<MqttClientUnsubscribedTopicHandler> logger)
{
_pythonScriptHostService = pythonScriptHostService ?? throw new ArgumentNullException(nameof(pythonScriptHostService));
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
}
public Task HandleClientUnsubscribedTopicAsync(MqttServerClientUnsubscribedTopicEventArgs eventArgs)
{
try
{
var pythonEventArgs = new PythonDictionary
{
{ "client_id", eventArgs.ClientId },
{ "topic", eventArgs.TopicFilter }
};
_pythonScriptHostService.InvokeOptionalFunction("on_client_unsubscribed_topic", pythonEventArgs);
}
catch (Exception exception)
{
_logger.LogError(exception, "Error while handling client unsubscribed topic event.");
}
return Task.CompletedTask;
}
}
}
@@ -0,0 +1,47 @@
using System;
using System.Threading.Tasks;
using IronPython.Runtime;
using Microsoft.Extensions.Logging;
using MQTTnet.Protocol;
using MQTTnet.Server.Scripting;
namespace MQTTnet.Server.Mqtt
{
public class MqttConnectionValidator : IMqttServerConnectionValidator
{
private readonly PythonScriptHostService _pythonScriptHostService;
private readonly ILogger _logger;
public MqttConnectionValidator(PythonScriptHostService pythonScriptHostService, ILogger<MqttConnectionValidator> logger)
{
_pythonScriptHostService = pythonScriptHostService ?? throw new ArgumentNullException(nameof(pythonScriptHostService));
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
}
public Task ValidateConnectionAsync(MqttConnectionValidatorContext context)
{
try
{
var pythonContext = new PythonDictionary
{
{ "client_id", context.ClientId },
{ "endpoint", context.Endpoint },
{ "is_secure_connection", context.IsSecureConnection },
{ "username", context.Username },
{ "password", context.Password },
{ "result", PythonConvert.Pythonfy(context.ReturnCode) }
};
_pythonScriptHostService.InvokeOptionalFunction("on_validate_client_connection", pythonContext);
context.ReturnCode = PythonConvert.ParseEnum<MqttConnectReturnCode>((string)pythonContext["result"]);
}
catch (Exception exception)
{
_logger.LogError(exception, "Error while validating client connection.");
}
return Task.CompletedTask;
}
}
}
@@ -0,0 +1,191 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using IronPython.Runtime;
using Microsoft.Extensions.Logging;
using MQTTnet.Adapter;
using MQTTnet.AspNetCore;
using MQTTnet.Implementations;
using MQTTnet.Protocol;
using MQTTnet.Server.Scripting;
namespace MQTTnet.Server.Mqtt
{
public class MqttServerService
{
private readonly ILogger<MqttServerService> _logger;
private readonly Configuration.SettingsModel _settings;
private readonly MqttApplicationMessageInterceptor _mqttApplicationMessageInterceptor;
private readonly MqttClientConnectedHandler _mqttClientConnectedHandler;
private readonly MqttClientDisconnectedHandler _mqttClientDisconnectedHandler;
private readonly MqttClientSubscribedTopicHandler _mqttClientSubscribedTopicHandler;
private readonly MqttClientUnsubscribedTopicHandler _mqttClientUnsubscribedTopicHandler;
private readonly MqttConnectionValidator _mqttConnectionValidator;
private readonly IMqttServer _mqttServer;
private readonly MqttSubscriptionInterceptor _mqttSubscriptionInterceptor;
private readonly PythonScriptHostService _pythonScriptHostService;
public MqttServerService(
Configuration.SettingsModel settings,
CustomMqttFactory mqttFactory,
MqttClientConnectedHandler mqttClientConnectedHandler,
MqttClientDisconnectedHandler mqttClientDisconnectedHandler,
MqttClientSubscribedTopicHandler mqttClientSubscribedTopicHandler,
MqttClientUnsubscribedTopicHandler mqttClientUnsubscribedTopicHandler,
MqttConnectionValidator mqttConnectionValidator,
MqttSubscriptionInterceptor mqttSubscriptionInterceptor,
MqttApplicationMessageInterceptor mqttApplicationMessageInterceptor,
PythonScriptHostService pythonScriptHostService,
ILogger<MqttServerService> logger)
{
_settings = settings;
_mqttClientConnectedHandler = mqttClientConnectedHandler ?? throw new ArgumentNullException(nameof(mqttClientConnectedHandler));
_mqttClientDisconnectedHandler = mqttClientDisconnectedHandler ?? throw new ArgumentNullException(nameof(mqttClientDisconnectedHandler));
_mqttClientSubscribedTopicHandler = mqttClientSubscribedTopicHandler ?? throw new ArgumentNullException(nameof(mqttClientSubscribedTopicHandler));
_mqttClientUnsubscribedTopicHandler = mqttClientUnsubscribedTopicHandler ?? throw new ArgumentNullException(nameof(mqttClientUnsubscribedTopicHandler));
_mqttConnectionValidator = mqttConnectionValidator ?? throw new ArgumentNullException(nameof(mqttConnectionValidator));
_mqttSubscriptionInterceptor = mqttSubscriptionInterceptor ?? throw new ArgumentNullException(nameof(mqttSubscriptionInterceptor));
_mqttApplicationMessageInterceptor = mqttApplicationMessageInterceptor ?? throw new ArgumentNullException(nameof(mqttApplicationMessageInterceptor));
_pythonScriptHostService = pythonScriptHostService ?? throw new ArgumentNullException(nameof(pythonScriptHostService));
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
WebSocketServerAdapter = new MqttWebSocketServerAdapter(mqttFactory.Logger.CreateChildLogger());
var adapters = new List<IMqttServerAdapter>
{
new MqttTcpServerAdapter(mqttFactory.Logger.CreateChildLogger()),
WebSocketServerAdapter
};
_mqttServer = mqttFactory.CreateMqttServer(adapters);
}
public MqttWebSocketServerAdapter WebSocketServerAdapter { get; }
public void Configure()
{
_pythonScriptHostService.RegisterProxyObject("publish", new Action<PythonDictionary>(Publish));
var options = new MqttServerOptionsBuilder()
.WithMaxPendingMessagesPerClient(_settings.MaxPendingMessagesPerClient)
.WithDefaultCommunicationTimeout(TimeSpan.FromSeconds(_settings.CommunicationTimeout))
.WithConnectionValidator(_mqttConnectionValidator)
.WithApplicationMessageInterceptor(_mqttApplicationMessageInterceptor)
.WithSubscriptionInterceptor(_mqttSubscriptionInterceptor);
// Configure unencrypted connections
if (_settings.EndPoint.Enabled)
{
options.WithDefaultEndpoint();
if (_settings.EndPoint.TryReadIPv4(out var address4))
{
options.WithDefaultEndpointBoundIPAddress(address4);
}
if (_settings.EndPoint.TryReadIPv6(out var address6))
{
options.WithDefaultEndpointBoundIPV6Address(address6);
}
if (_settings.EndPoint.Port > 0)
{
options.WithDefaultEndpointPort(_settings.EndPoint.Port);
}
}
else
{
options.WithoutDefaultEndpoint();
}
// Configure encrypted connections
if (_settings.EndPointEncryption.Enabled)
{
options
.WithEncryptedEndpoint()
.WithEncryptionSslProtocol(System.Security.Authentication.SslProtocols.Tls12)
.WithEncryptionCertificate(_settings.EndPointEncryption.ReadCertificate());
if (_settings.EndPointEncryption.TryReadIPv4(out var address4))
{
options.WithEncryptedEndpointBoundIPAddress(address4);
}
if (_settings.EndPointEncryption.TryReadIPv6(out var address6))
{
options.WithEncryptedEndpointBoundIPV6Address(address6);
}
if (_settings.EndPoint.Port > 0)
{
options.WithEncryptedEndpointPort(_settings.EndPointEncryption.Port);
}
}
else
{
options.WithoutEncryptedEndpoint();
}
if (_settings.ConnectionBacklog > 0)
{
options.WithConnectionBacklog(_settings.ConnectionBacklog);
}
_mqttServer.ClientConnectedHandler = _mqttClientConnectedHandler;
_mqttServer.ClientDisconnectedHandler = _mqttClientDisconnectedHandler;
_mqttServer.ClientSubscribedTopicHandler = _mqttClientSubscribedTopicHandler;
_mqttServer.ClientUnsubscribedTopicHandler = _mqttClientUnsubscribedTopicHandler;
_mqttServer.StartAsync(options.Build()).GetAwaiter().GetResult();
_logger.LogInformation("MQTT server started.");
}
private void Publish(PythonDictionary parameters)
{
try
{
var applicationMessageBuilder = new MqttApplicationMessageBuilder()
.WithTopic((string)parameters.get("topic", null))
.WithRetainFlag((bool)parameters.get("retain", false))
.WithQualityOfServiceLevel((MqttQualityOfServiceLevel)(int)parameters.get("qos", 0));
var payload = parameters.get("payload", null);
byte[] binaryPayload;
if (payload == null)
{
binaryPayload = new byte[0];
}
else if (payload is string stringPayload)
{
binaryPayload = Encoding.UTF8.GetBytes(stringPayload);
}
else if (payload is ByteArray byteArray)
{
binaryPayload = byteArray.ToArray();
}
else if (payload is IEnumerable<int> intArray)
{
binaryPayload = intArray.Select(Convert.ToByte).ToArray();
}
else
{
throw new NotSupportedException("Payload type not supported.");
}
applicationMessageBuilder = applicationMessageBuilder
.WithPayload(binaryPayload);
var applicationMessage = applicationMessageBuilder.Build();
_mqttServer.PublishAsync(applicationMessage).GetAwaiter().GetResult();
}
catch (Exception exception)
{
_logger.LogError(exception, "Error while publishing application message from server.");
}
}
}
}
@@ -0,0 +1,47 @@
using System;
using System.Threading.Tasks;
using IronPython.Runtime;
using Microsoft.Extensions.Logging;
using MQTTnet.Server.Scripting;
namespace MQTTnet.Server.Mqtt
{
public class MqttSubscriptionInterceptor : IMqttServerSubscriptionInterceptor
{
private readonly PythonScriptHostService _pythonScriptHostService;
private readonly ILogger _logger;
public MqttSubscriptionInterceptor(PythonScriptHostService pythonScriptHostService, ILogger<MqttSubscriptionInterceptor> logger)
{
_pythonScriptHostService = pythonScriptHostService ?? throw new ArgumentNullException(nameof(pythonScriptHostService));
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
}
public Task InterceptSubscriptionAsync(MqttSubscriptionInterceptorContext context)
{
try
{
var pythonContext = new PythonDictionary
{
{ "accept_subscription", context.AcceptSubscription },
{ "close_connection", context.CloseConnection },
{ "client_id", context.ClientId },
{ "topic", context.TopicFilter.Topic },
{ "qos", (int)context.TopicFilter.QualityOfServiceLevel }
};
_pythonScriptHostService.InvokeOptionalFunction("on_intercept_subscription", pythonContext);
context.AcceptSubscription = (bool)pythonContext["accept_subscription"];
context.CloseConnection = (bool)pythonContext["close_connection"];
}
catch (Exception exception)
{
_logger.LogError(exception, "Error while intercepting subscription.");
}
return Task.CompletedTask;
}
}
}
+67
View File
@@ -0,0 +1,67 @@
using System;
using Microsoft.AspNetCore;
using Microsoft.AspNetCore.Hosting;
namespace MQTTnet.Server
{
public static class Program
{
public static int Main(string[] args)
{
try
{
PrintLogo();
CreateWebHostBuilder(args).Build().Run();
return 0;
}
catch (Exception exception)
{
Console.WriteLine(exception);
return -1;
}
}
private static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
WebHost.CreateDefaultBuilder(args)
.UseKestrel()
.UseStartup<Startup>();
private static void PrintLogo()
{
Console.ResetColor();
Console.ForegroundColor = ConsoleColor.Red;
Console.WriteLine(@"
__ __ ____ _______ _______ _ _____
| \/ |/ __ \__ __|__ __| | | / ____|
| \ / | | | | | | | |_ __ ___| |_ | (___ ___ _ ____ _____ _ __
| |\/| | | | | | | | | '_ \ / _ \ __| \___ \ / _ \ '__\ \ / / _ \ '__|
| | | | |__| | | | | | | | | __/ |_ ____) | __/ | \ V / __/ |
|_| |_|\___\_\ |_| |_|_| |_|\___|\__| |_____/ \___|_| \_/ \___|_|");
Console.ForegroundColor = ConsoleColor.White;
Console.WriteLine(@"
-- The official MQTT server implementation of MQTTnet --
Copyright (c) 2017-2019 The MQTTnet Team");
Console.ForegroundColor = ConsoleColor.Blue;
Console.WriteLine(@"
https://github.com/chkr1011/MQTTnet");
Console.ForegroundColor = ConsoleColor.White;
Console.WriteLine(@"
Version: 1.0.0-alpha1
License: MIT (read LICENSE file)
Sponsoring: https://opencollective.com/mqttnet
Support: https://github.com/chkr1011/MQTTnet/issues
Docs: https://github.com/chkr1011/MQTTnet/wiki/MQTTnetServer
");
Console.BackgroundColor = ConsoleColor.White;
Console.ForegroundColor = ConsoleColor.Red;
Console.WriteLine(" ! THIS IS AN ALPHA VERSION! IT IS NOT RECOMMENDED TO USE IT FOR ANY DIFFERENT PURPOSE THAN TESTING OR EVALUATING!");
Console.WriteLine();
Console.ResetColor();
}
}
}
@@ -0,0 +1,47 @@
using System;
using System.Collections.Generic;
using Microsoft.Extensions.Logging;
namespace MQTTnet.Server.Scripting.DataSharing
{
public class DataSharingService
{
private readonly Dictionary<string, object> _storage = new Dictionary<string, object>();
private readonly PythonScriptHostService _pythonScriptHostService;
private readonly ILogger<DataSharingService> _logger;
public DataSharingService(PythonScriptHostService pythonScriptHostService, ILogger<DataSharingService> logger)
{
_pythonScriptHostService = pythonScriptHostService ?? throw new ArgumentNullException(nameof(pythonScriptHostService));
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
}
public void Configure()
{
_pythonScriptHostService.RegisterProxyObject("write_shared_data", new Action<string, object>(Write));
_pythonScriptHostService.RegisterProxyObject("read_shared_data", new Func<string, object, object>(Read));
}
public void Write(string key, object value)
{
lock (_storage)
{
_storage[key] = value;
_logger.LogInformation($"Shared data with key '{key}' updated.");
}
}
public object Read(string key, object defaultValue)
{
lock (_storage)
{
if (!_storage.TryGetValue(key, out var value))
{
return defaultValue;
}
return value;
}
}
}
}
@@ -0,0 +1,88 @@
using System;
using System.Collections;
using System.Text;
using IronPython.Runtime;
namespace MQTTnet.Server.Scripting
{
public static class PythonConvert
{
public static object ToPython(object value)
{
if (value is PythonDictionary)
{
return value;
}
if (value is string)
{
return value;
}
if (value is int)
{
return value;
}
if (value is float)
{
return value;
}
if (value is bool)
{
return value;
}
if (value is IDictionary dictionary)
{
var pythonDictionary = new PythonDictionary();
foreach (DictionaryEntry dictionaryEntry in dictionary)
{
pythonDictionary.Add(dictionaryEntry.Key, ToPython(dictionaryEntry.Value));
}
return pythonDictionary;
}
if (value is IEnumerable enumerable)
{
var pythonList = new List();
foreach (var item in enumerable)
{
pythonList.Add(ToPython(item));
}
return pythonList;
}
return value;
}
public static string Pythonfy(Enum value)
{
return Pythonfy(value.ToString());
}
public static string Pythonfy(string value)
{
var result = new StringBuilder();
foreach (var @char in value)
{
if (char.IsUpper(@char) && result.Length > 0)
{
result.Append('_');
}
result.Append(char.ToLowerInvariant(@char));
}
return result.ToString();
}
public static TEnum ParseEnum<TEnum>(string value) where TEnum : Enum
{
return (TEnum)Enum.Parse(typeof(TEnum), value.Replace("_", string.Empty), true);
}
}
}
@@ -0,0 +1,66 @@
using System;
using System.IO;
using System.Text;
using Microsoft.Extensions.Logging;
namespace MQTTnet.Server.Scripting
{
public class PythonIOStream : Stream
{
private readonly ILogger _logger;
private readonly Encoding _encoder = Encoding.UTF8;
public PythonIOStream(ILogger<PythonIOStream> logger)
{
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
}
public override void Flush()
{
}
public override int Read(byte[] buffer, int offset, int count)
{
throw new NotSupportedException();
}
public override long Seek(long offset, SeekOrigin origin)
{
throw new NotSupportedException();
}
public override void SetLength(long value)
{
throw new NotSupportedException();
}
public override void Write(byte[] buffer, int offset, int count)
{
if (buffer == null) throw new ArgumentNullException(nameof(buffer));
if (count == 0)
{
return;
}
var text = _encoder.GetString(buffer, offset, count);
if (text.Equals(Environment.NewLine))
{
return;
}
_logger.LogDebug(text);
}
public override bool CanRead { get; } = false;
public override bool CanSeek { get; } = false;
public override bool CanWrite { get; } = true;
public override long Length { get; } = 0L;
public override long Position
{
get => throw new NotSupportedException();
set => throw new NotSupportedException();
}
}
}
@@ -0,0 +1,130 @@
using System;
using System.Collections.Generic;
using System.Dynamic;
using System.IO;
using System.Linq;
using System.Text;
using Microsoft.Extensions.Logging;
using Microsoft.Scripting;
using Microsoft.Scripting.Hosting;
namespace MQTTnet.Server.Scripting
{
public class PythonScriptHostService
{
private readonly IDictionary<string, object> _proxyObjects = new ExpandoObject();
private readonly List<PythonScriptInstance> _scriptInstances = new List<PythonScriptInstance>();
private readonly ILogger<PythonScriptHostService> _logger;
private readonly ScriptEngine _scriptEngine;
public PythonScriptHostService(PythonIOStream pythonIOStream, ILogger<PythonScriptHostService> logger)
{
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
_scriptEngine = IronPython.Hosting.Python.CreateEngine();
_scriptEngine.Runtime.IO.SetOutput(pythonIOStream, Encoding.UTF8);
}
public void Configure()
{
AddSearchPaths(_scriptEngine);
var scriptsDirectory = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Scripts");
foreach (var filename in Directory.GetFiles(scriptsDirectory, "*.py", SearchOption.AllDirectories).OrderBy(file => file))
{
TryInitializeScript(filename);
}
}
public void RegisterProxyObject(string name, object @object)
{
if (name == null) throw new ArgumentNullException(nameof(name));
if (@object == null) throw new ArgumentNullException(nameof(@object));
_proxyObjects.Add(name, @object);
}
public void InvokeOptionalFunction(string name, object parameters)
{
if (name == null) throw new ArgumentNullException(nameof(name));
lock (_scriptInstances)
{
foreach (var pythonScriptInstance in _scriptInstances)
{
try
{
pythonScriptInstance.InvokeOptionalFunction(name, parameters);
}
catch (Exception exception)
{
_logger.LogError(exception, $"Error while invoking function '{name}' at script '{pythonScriptInstance.Name}'.");
}
}
}
}
private void TryInitializeScript(string filename)
{
try
{
var scriptName = new FileInfo(filename).Name;
_logger.LogTrace($"Initializing Python script '{scriptName}'...");
var code = File.ReadAllText(filename);
var scriptInstance = CreateScriptInstance(scriptName, code);
scriptInstance.InvokeOptionalFunction("initialize");
_scriptInstances.Add(scriptInstance);
_logger.LogInformation($"Initialized script '{scriptName}'.");
}
catch (Exception exception)
{
_logger.LogError(exception, $"Error while initializing script '{new FileInfo(filename).Name}'.");
}
}
private PythonScriptInstance CreateScriptInstance(string name, string code)
{
var scriptScope = _scriptEngine.CreateScope();
var source = scriptScope.Engine.CreateScriptSourceFromString(code, SourceCodeKind.File);
var compiledCode = source.Compile();
scriptScope.SetVariable("mqtt_net_server", _proxyObjects);
compiledCode.Execute(scriptScope);
return new PythonScriptInstance(name, scriptScope);
}
private void AddSearchPaths(ScriptEngine scriptEngine)
{
var paths = new List<string>
{
Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Lib"),
"/usr/lib/python2.7",
@"C:\Python27\Lib"
};
AddSearchPaths(scriptEngine, paths);
}
private void AddSearchPaths(ScriptEngine scriptEngine, IEnumerable<string> paths)
{
var searchPaths = scriptEngine.GetSearchPaths();
foreach (var path in paths)
{
if (Directory.Exists(path))
{
searchPaths.Add(path);
_logger.LogInformation($"Added Python lib path: {path}");
}
}
scriptEngine.SetSearchPaths(searchPaths);
}
}
}
@@ -0,0 +1,57 @@
using System;
using IronPython.Runtime;
using Microsoft.Scripting.Hosting;
namespace MQTTnet.Server.Scripting
{
public class PythonScriptInstance
{
private readonly ScriptScope _scriptScope;
public PythonScriptInstance(string name, ScriptScope scriptScope)
{
_scriptScope = scriptScope;
Name = name;
}
public string Name { get; }
public bool InvokeOptionalFunction(string name, params object[] parameters)
{
return InvokeOptionalFunction(name, parameters, out _);
}
public bool InvokeOptionalFunction(string name, object[] parameters, out object result)
{
if (name == null) throw new ArgumentNullException(nameof(name));
lock (_scriptScope)
{
if (!_scriptScope.Engine.Operations.TryGetMember(_scriptScope, name, out var member))
{
result = null;
return false;
}
if (!(member is PythonFunction function))
{
throw new Exception($"Member '{name}' is no Python function.");
}
try
{
result = _scriptScope.Engine.Operations.Invoke(function, parameters);
return true;
}
catch (Exception exception)
{
var details = _scriptScope.Engine.GetService<ExceptionOperations>().FormatException(exception);
var message = $"Error while invoking function '{name}'. " + Environment.NewLine + details;
throw new Exception(message, exception);
}
}
}
}
}
+107
View File
@@ -0,0 +1,107 @@
import json
def initialize():
"""
This function is invoked after the script file has been loaded.
It will be executed only one time.
"""
print("Hello World from Sample script.")
def on_validate_client_connection(context):
"""
This function is invoked whenever a client wants to connect. It can be used to validate the connection.
"""
print(context)
mqtt_net_server.write_shared_data(context["client_id"], {"custom_value_1": 1, "custom_value_2": True})
return
if context["client_id"] != "test_client":
context["result"] = "connection_refused_not_authorized"
return
if context["username"] != "bud spencer":
context["result"] = "connection_refused_not_authorized"
return
if context["password"] != "secret":
context["result"] = "connection_refused_not_authorized"
print(context)
def on_intercept_subscription(context):
"""
This function is invoked whenever a client wants to subscribe to a topic.
"""
print("Client '{client_id}' want's to subscribe to topic '{topic}'.".format(client_id=context["client_id"], topic=context["topic"]))
def on_intercept_application_message(context):
"""
This function is invoked for every processed application message. It also allows modifying
the message or cancel processing at all.
"""
client_id = context["client_id"]
if client_id != None:
shared_data = mqtt_net_server.read_shared_data(context["client_id"], {})
print(shared_data)
if context["topic"] == "topic_with_response":
json_payload = {
"hello": "world",
"x": 1,
"y": True,
"z": None
}
application_message = {
"retain": False,
"topic": "reply",
"payload": json.dumps(json_payload)
}
mqtt_net_server.publish(application_message)
print("Client '{client_id}' published topic '{topic}'.".format(client_id=context["client_id"], topic=context["topic"]))
def on_client_connected(event_args):
"""
This function is called whenever a client has passed the validation is connected.
"""
print("Client '{client_id}' is now connected.".format(client_id=event_args["client_id"]))
def on_client_disconnected(event_args):
"""
This function is called whenever a client has disconnected.
"""
print("Client '{client_id}' is now disconnected (type = {type}).".format(client_id=event_args["client_id"], type=event_args["type"]))
def on_client_subscribed_topic(event_args):
"""
This function is called whenever a client has subscribed to a topic (when allowed).
"""
print("Client '{client_id}' has subscribed to '{topic}'.".format(client_id=event_args["client_id"], topic=event_args["topic"]))
def on_client_unsubscribed_topic(event_args):
"""
This function is called whenever a client has unsubscribed from a topic.
"""
print("Client '{client_id}' has unsubscribed from '{topic}'.".format(client_id=event_args["client_id"], topic=event_args["topic"]))
+19
View File
@@ -0,0 +1,19 @@
This directory contains scripts which are loaded by the server and can be used to perform the following tasks.
1. Validation of client connections via credentials, client IDs etc.
2. Manipulation of every processed message.
3. Validation of subscription attempts.
4. Publishing of custom application messages.
All scripts are loaded and _MQTTnet Server_ will invoke functions according to predefined naming conventions.
If a function is implemented in multiple scripts the context will be moved throug all instances. This allows overriding of results or passing data to other (following) scripts.
The Python starndard library ships with _MQTTnet Server_. But it is possible to add custom paths with Python libraries.
```
import sys
sys.path.append(PATH_TO_LIBRARY)
```
* All scripts must have the file extension _.py_.
* All scripts are sorted alphabetically (A to Z) before being loaded and parsed.
+110
View File
@@ -0,0 +1,110 @@
using System;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using MQTTnet.Server.Logging;
using MQTTnet.Server.Mqtt;
using MQTTnet.Server.Scripting;
using MQTTnet.Server.Scripting.DataSharing;
namespace MQTTnet.Server
{
public class Startup
{
public Startup(IConfiguration configuration)
{
var builder = new ConfigurationBuilder()
.AddJsonFile("appsettings.json")
.AddEnvironmentVariables();
Configuration = builder.Build();
}
public IConfigurationRoot Configuration { get; }
public void Configure(
IApplicationBuilder application,
IHostingEnvironment environment,
MqttServerService mqttServerService,
PythonScriptHostService pythonScriptHostService,
DataSharingService dataSharingService)
{
if (environment.IsDevelopment())
{
application.UseDeveloperExceptionPage();
}
else
{
application.UseHsts();
}
application.UseStaticFiles();
var webSocketOptions = new WebSocketOptions
{
KeepAliveInterval = TimeSpan.FromSeconds(120),
ReceiveBufferSize = 4 * 1024
};
application.UseWebSockets(webSocketOptions);
application.UseHttpsRedirection();
application.UseMvc();
application.Use(async (context, next) =>
{
if (context.Request.Path == "/mqtt") // TODO: Full path to config.
{
if (context.WebSockets.IsWebSocketRequest)
{
using (var webSocket = await context.WebSockets.AcceptWebSocketAsync().ConfigureAwait(false))
{
await mqttServerService.WebSocketServerAdapter.RunWebSocketConnectionAsync(webSocket, context).ConfigureAwait(false);
}
}
else
{
context.Response.StatusCode = 400;
}
}
else
{
await next().ConfigureAwait(false);
}
});
dataSharingService.Configure();
pythonScriptHostService.Configure();
mqttServerService.Configure();
}
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
// Read settings
var settings = new Configuration.SettingsModel();
Configuration.Bind("MQTT", settings);
services.AddSingleton(settings);
// Wire up dependencies
services.AddSingleton<PythonIOStream>();
services.AddSingleton<PythonScriptHostService>();
services.AddSingleton<DataSharingService>();
services.AddSingleton<MqttNetLoggerWrapper>();
services.AddSingleton<CustomMqttFactory>();
services.AddSingleton<MqttServerService>();
services.AddSingleton<MqttClientConnectedHandler>();
services.AddSingleton<MqttClientDisconnectedHandler>();
services.AddSingleton<MqttClientSubscribedTopicHandler>();
services.AddSingleton<MqttClientUnsubscribedTopicHandler>();
services.AddSingleton<MqttConnectionValidator>();
services.AddSingleton<MqttSubscriptionInterceptor>();
services.AddSingleton<MqttApplicationMessageInterceptor>();
}
}
}
@@ -0,0 +1,9 @@
{
"Logging": {
"LogLevel": {
"Default": "Debug",
"System": "Information",
"Microsoft": "Information"
}
}
}
+43
View File
@@ -0,0 +1,43 @@
{
"Kestrel": {
"EndPoints": {
"Http": {
"Url": "http://localhost:80"
},
"Https": {
"Url": "http://localhost:443"
}
}
},
"MQTT": {
/*
Wildcard Addresses:
* - All local IP addresses
localhost - Localhost only
disable - Skip address assignment
*/
"EndPoint": {
"Enabled": true,
"IPv4": "localhost",
"IPv6": "localhost",
"Port": 1883
},
"EndPointEncryption": {
"Enabled": false,
"IPv4": "localhost",
"IPv6": "localhost",
"Port": 8883,
"CertificatePath": "/absolute/path/to/pfx"
},
"CommunicationTimeout": 15, /* In seconds */
"ConnectionBacklog": 0, /* Set 0 to disable */
"EnablePersistentSessions": false,
"MaxPendingMessagesPerClient": 250
},
"Logging": {
"LogLevel": {
"Default": "Warning"
}
},
"AllowedHosts": "*"
}
+12
View File
@@ -0,0 +1,12 @@
{
"version": "1.0.0",
"name": "mqtt.test",
"private": true,
"devDependencies": {},
"dependencies": {
"@types/node": "^8.0.46",
"mqtt": "^2.15.1",
"systemjs": "^0.20.19",
"typescript": "^2.3.4"
}
}
+12
View File
@@ -0,0 +1,12 @@
{
"compilerOptions": {
"noImplicitAny": false,
"noEmitOnError": true,
"removeComments": false,
"sourceMap": true,
"target": "es5"
},
"exclude": [
"node_modules"
]
}
+35
View File
@@ -0,0 +1,35 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>MQTTnet Server test</title>
</head>
<body>
<script src="node_modules/systemjs/dist/system.js"></script>
<script>
System.config({
packages: {
'': {
defaultExtension: 'js'
}
},
map: {
mqtt: 'node_modules/mqtt/dist/mqtt.min'
}
});
System.import('app/app');
</script>
<div>
<p id="state"></p>
<input id="topic" placeholder="topic" />
<input id="msg" placeholder="msg" />
<button id="publish">send</button>
</div>
<div>
<ul id="msgs" ></ul>
</div>
</body>
</html>
+58
View File
@@ -0,0 +1,58 @@
import { connect } from "mqtt";
var client = connect('ws://' + location.host + '/mqtt',
{
clientId: "client" + Math.floor(Math.random() * 6) + 1
});
window.onbeforeunload = () => {
client.end();
};
var publishButton = document.getElementById("publish");
var topicInput = <HTMLInputElement>document.getElementById("topic");
var msgInput = <HTMLInputElement>document.getElementById("msg");
var stateParagraph = document.getElementById("state");
var msgsList = <HTMLUListElement>document.getElementById("msgs");
publishButton.onclick = click => {
var topic = topicInput.value;
var msg = msgInput.value;
client.publish(topic, msg);
};
client.on('connect', () => {
client.subscribe('#', { qos: 0 }, (err, granted) => {
console.log(err);
});
client.publish('presence', 'Hello mqtt');
stateParagraph.innerText = "connected";
showMsg("[connect]");
});
client.on("error", e => {
showMsg("error: " + e.message);
});
client.on("reconnect", () => {
stateParagraph.innerText = "reconnecting";
showMsg("[reconnect]");
});
client.on('message', (topic, message) => {
showMsg(topic + ": " + message.toString());
});
function showMsg(msg: string) {
//console.log(msg);
var node = document.createElement("LI");
node.appendChild(document.createTextNode(msg));
msgsList.appendChild(node);
if (msgsList.childElementCount > 50) {
msgsList.removeChild(msgsList.childNodes[0]);
}
}
@@ -10,6 +10,8 @@ namespace MQTTnet.Adapter
{
string Endpoint { get; }
bool IsSecureConnection { get; }
MqttPacketFormatterAdapter PacketFormatterAdapter { get; }
event EventHandler ReadingPacketStarted;
+1 -1
View File
@@ -6,7 +6,7 @@ namespace MQTTnet.Adapter
{
public interface IMqttServerAdapter : IDisposable
{
event EventHandler<MqttServerAdapterClientAcceptedEventArgs> ClientAccepted;
Action<MqttServerAdapterClientAcceptedEventArgs> ClientAcceptedHandler { get; set; }
Task StartAsync(IMqttServerOptions options);
Task StopAsync();
@@ -42,6 +42,8 @@ namespace MQTTnet.Adapter
public string Endpoint => _channel.Endpoint;
public bool IsSecureConnection => _channel.IsSecureConnection;
public MqttPacketFormatterAdapter PacketFormatterAdapter { get; }
public event EventHandler ReadingPacketStarted;
+1
View File
@@ -7,6 +7,7 @@ namespace MQTTnet.Channel
public interface IMqttChannel : IDisposable
{
string Endpoint { get; }
bool IsSecureConnection { get; }
Task ConnectAsync(CancellationToken cancellationToken);
Task DisconnectAsync(CancellationToken cancellationToken);
+2 -6
View File
@@ -15,13 +15,9 @@ namespace MQTTnet.Client
IMqttClientOptions Options { get; }
IMqttClientConnectedHandler ConnectedHandler { get; set; }
[Obsolete("Use ConnectedHandler instead.")]
event EventHandler<MqttClientConnectedEventArgs> Connected;
IMqttClientDisconnectedHandler DisconnectedHandler { get; set; }
[Obsolete("Use DisconnectedHandler instead.")]
event EventHandler<MqttClientDisconnectedEventArgs> Disconnected;
Task<MqttClientAuthenticateResult> ConnectAsync(IMqttClientOptions options, CancellationToken cancellationToken);
Task DisconnectAsync(MqttClientDisconnectOptions options, CancellationToken cancellationToken);
+22 -32
View File
@@ -46,15 +46,9 @@ namespace MQTTnet.Client
public IMqttClientConnectedHandler ConnectedHandler { get; set; }
public event EventHandler<MqttClientConnectedEventArgs> Connected;
public IMqttClientDisconnectedHandler DisconnectedHandler { get; set; }
public event EventHandler<MqttClientDisconnectedEventArgs> Disconnected;
public IMqttApplicationMessageHandler ReceivedApplicationMessageHandler { get; set; }
public event EventHandler<MqttApplicationMessageReceivedEventArgs> ApplicationMessageReceived;
public IMqttApplicationMessageReceivedHandler ApplicationMessageReceivedHandler { get; set; }
public bool IsConnected { get; private set; }
@@ -106,9 +100,6 @@ namespace MQTTnet.Client
await connectedHandler.HandleConnectedAsync(new MqttClientConnectedEventArgs(authenticateResult)).ConfigureAwait(false);
}
// TODO: Remove!
Connected?.Invoke(this, new MqttClientConnectedEventArgs(authenticateResult));
return authenticateResult;
}
catch (Exception exception)
@@ -276,8 +267,6 @@ namespace MQTTnet.Client
{
await disconnectedHandler.HandleDisconnectedAsync(new MqttClientDisconnectedEventArgs(clientWasConnected, exception)).ConfigureAwait(false);
}
Disconnected?.Invoke(this, new MqttClientDisconnectedEventArgs(clientWasConnected, exception));
}
}
@@ -521,25 +510,27 @@ namespace MQTTnet.Client
}
else if (publishPacket.QualityOfServiceLevel == MqttQualityOfServiceLevel.AtLeastOnce)
{
await HandleReceivedApplicationMessageAsync(publishPacket).ConfigureAwait(false);
await SendAsync(new MqttPubAckPacket
if (await HandleReceivedApplicationMessageAsync(publishPacket).ConfigureAwait(false))
{
PacketIdentifier = publishPacket.PacketIdentifier,
ReasonCode = MqttPubAckReasonCode.Success
}, cancellationToken).ConfigureAwait(false);
await SendAsync(new MqttPubAckPacket
{
PacketIdentifier = publishPacket.PacketIdentifier,
ReasonCode = MqttPubAckReasonCode.Success
}, cancellationToken).ConfigureAwait(false);
}
}
else if (publishPacket.QualityOfServiceLevel == MqttQualityOfServiceLevel.ExactlyOnce)
{
await HandleReceivedApplicationMessageAsync(publishPacket).ConfigureAwait(false);
var pubRecPacket = new MqttPubRecPacket
if (await HandleReceivedApplicationMessageAsync(publishPacket).ConfigureAwait(false))
{
PacketIdentifier = publishPacket.PacketIdentifier,
ReasonCode = MqttPubRecReasonCode.Success
};
var pubRecPacket = new MqttPubRecPacket
{
PacketIdentifier = publishPacket.PacketIdentifier,
ReasonCode = MqttPubRecReasonCode.Success
};
await SendAsync(pubRecPacket, cancellationToken).ConfigureAwait(false);
await SendAsync(pubRecPacket, cancellationToken).ConfigureAwait(false);
}
}
else
{
@@ -583,20 +574,19 @@ namespace MQTTnet.Client
return _adapter.PacketFormatterAdapter.DataConverter.CreatePublishResult(pubRecPacket, pubCompPacket);
}
private Task HandleReceivedApplicationMessageAsync(MqttPublishPacket publishPacket)
private async Task<bool> HandleReceivedApplicationMessageAsync(MqttPublishPacket publishPacket)
{
var applicationMessage = _adapter.PacketFormatterAdapter.DataConverter.CreateApplicationMessage(publishPacket);
ApplicationMessageReceived?.Invoke(this, new MqttApplicationMessageReceivedEventArgs(Options.ClientId, applicationMessage));
var handler = ReceivedApplicationMessageHandler;
var handler = ApplicationMessageReceivedHandler;
if (handler != null)
{
return handler.HandleApplicationMessageAsync(
new MqttApplicationMessageHandlerContext(Options.ClientId, applicationMessage));
var eventArgs = new MqttApplicationMessageReceivedEventArgs(Options.ClientId, applicationMessage);
await handler.HandleApplicationMessageReceivedAsync(eventArgs).ConfigureAwait(false);
return !eventArgs.ProcessingFailed;
}
return Task.FromResult(0);
return true;
}
private static async Task WaitForTaskAsync(Task task, Task sender)
@@ -63,35 +63,35 @@ namespace MQTTnet.Client
return client;
}
public static IMqttClient UseReceivedApplicationMessageHandler(this IMqttClient client, Func<MqttApplicationMessageHandlerContext, Task> handler)
public static IMqttClient UseApplicationMessageReceivedHandler(this IMqttClient client, Func<MqttApplicationMessageReceivedEventArgs, Task> handler)
{
if (handler == null)
{
client.ReceivedApplicationMessageHandler = null;
client.ApplicationMessageReceivedHandler = null;
return client;
}
client.ReceivedApplicationMessageHandler = new MqttApplicationMessageHandlerDelegate(handler);
client.ApplicationMessageReceivedHandler = new MqttApplicationMessageReceivedHandlerDelegate(handler);
return client;
}
public static IMqttClient UseReceivedApplicationMessageHandler(this IMqttClient client, Action<MqttApplicationMessageHandlerContext> handler)
public static IMqttClient UseApplicationMessageReceivedHandler(this IMqttClient client, Action<MqttApplicationMessageReceivedEventArgs> handler)
{
if (handler == null)
{
client.ReceivedApplicationMessageHandler = null;
client.ApplicationMessageReceivedHandler = null;
return client;
}
client.ReceivedApplicationMessageHandler = new MqttApplicationMessageHandlerDelegate(handler);
client.ApplicationMessageReceivedHandler = new MqttApplicationMessageReceivedHandlerDelegate(handler);
return client;
}
public static IMqttClient UseReceivedApplicationMessageHandler(this IMqttClient client, IMqttApplicationMessageHandler handler)
public static IMqttClient UseApplicationMessageReceivedHandler(this IMqttClient client, IMqttApplicationMessageReceivedHandler handler)
{
client.ReceivedApplicationMessageHandler = handler;
client.ApplicationMessageReceivedHandler = handler;
return client;
}
@@ -1,9 +0,0 @@
using System.Threading.Tasks;
namespace MQTTnet.Client.Receiving
{
public interface IMqttApplicationMessageHandler
{
Task HandleApplicationMessageAsync(MqttApplicationMessageHandlerContext context);
}
}
@@ -0,0 +1,9 @@
using System.Threading.Tasks;
namespace MQTTnet.Client.Receiving
{
public interface IMqttApplicationMessageReceivedHandler
{
Task HandleApplicationMessageReceivedAsync(MqttApplicationMessageReceivedEventArgs eventArgs);
}
}
@@ -1,15 +0,0 @@
namespace MQTTnet.Client.Receiving
{
public class MqttApplicationMessageHandlerContext
{
public MqttApplicationMessageHandlerContext(string senderClientId, MqttApplicationMessage applicationMessage)
{
SenderClientId = senderClientId;
ApplicationMessage = applicationMessage;
}
public string SenderClientId { get; }
public MqttApplicationMessage ApplicationMessage { get; }
}
}
@@ -1,31 +0,0 @@
using System;
using System.Threading.Tasks;
namespace MQTTnet.Client.Receiving
{
public class MqttApplicationMessageHandlerDelegate : IMqttApplicationMessageHandler
{
private readonly Func<MqttApplicationMessageHandlerContext, Task> _handler;
public MqttApplicationMessageHandlerDelegate(Action<MqttApplicationMessageHandlerContext> handler)
{
if (handler == null) throw new ArgumentNullException(nameof(handler));
_handler = context =>
{
handler(context);
return Task.FromResult(0);
};
}
public MqttApplicationMessageHandlerDelegate(Func<MqttApplicationMessageHandlerContext, Task> handler)
{
_handler = handler ?? throw new ArgumentNullException(nameof(handler));
}
public Task HandleApplicationMessageAsync(MqttApplicationMessageHandlerContext context)
{
return _handler(context);
}
}
}
@@ -0,0 +1,31 @@
using System;
using System.Threading.Tasks;
namespace MQTTnet.Client.Receiving
{
public class MqttApplicationMessageReceivedHandlerDelegate : IMqttApplicationMessageReceivedHandler
{
private readonly Func<MqttApplicationMessageReceivedEventArgs, Task> _handler;
public MqttApplicationMessageReceivedHandlerDelegate(Action<MqttApplicationMessageReceivedEventArgs> handler)
{
if (handler == null) throw new ArgumentNullException(nameof(handler));
_handler = context =>
{
handler(context);
return Task.FromResult(0);
};
}
public MqttApplicationMessageReceivedHandlerDelegate(Func<MqttApplicationMessageReceivedEventArgs, Task> handler)
{
_handler = handler ?? throw new ArgumentNullException(nameof(handler));
}
public Task HandleApplicationMessageReceivedAsync(MqttApplicationMessageReceivedEventArgs context)
{
return _handler(context);
}
}
}
@@ -1,13 +1,9 @@
using System;
using MQTTnet.Client.Receiving;
using MQTTnet.Client.Receiving;
namespace MQTTnet
{
public interface IApplicationMessageReceiver
{
IMqttApplicationMessageHandler ReceivedApplicationMessageHandler { get; set; }
[Obsolete("Use _ReceivedApplicationMessageHandler_ instead.")]
event EventHandler<MqttApplicationMessageReceivedEventArgs> ApplicationMessageReceived;
IMqttApplicationMessageReceivedHandler ApplicationMessageReceivedHandler { get; set; }
}
}
+11
View File
@@ -0,0 +1,11 @@
using MQTTnet.Client;
using MQTTnet.Diagnostics;
using MQTTnet.Server;
namespace MQTTnet
{
public interface IMqttFactory : IMqttClientFactory, IMqttServerFactory
{
IMqttNetLogger DefaultLogger { get; }
}
}
@@ -1,6 +1,5 @@
using System;
using MQTTnet.Adapter;
using MQTTnet.Client;
using MQTTnet.Client.Options;
using MQTTnet.Diagnostics;
using MQTTnet.Formatter;
@@ -36,6 +36,8 @@ namespace MQTTnet.Implementations
_bufferSize = serverOptions.DefaultEndpointOptions.BufferSize;
CreateStreams();
IsSecureConnection = socket.Information.ProtectionLevel >= SocketProtectionLevel.Tls12;
}
public static Func<MqttClientTcpOptions, IEnumerable<ChainValidationResult>> CustomIgnorableServerCertificateErrorsResolver { get; set; }
@@ -53,6 +55,8 @@ namespace MQTTnet.Implementations
}
}
public bool IsSecureConnection { get; }
public async Task ConnectAsync(CancellationToken cancellationToken)
{
if (_socket == null)
@@ -27,6 +27,8 @@ namespace MQTTnet.Implementations
{
_clientOptions = clientOptions ?? throw new ArgumentNullException(nameof(clientOptions));
_options = (MqttClientTcpOptions)clientOptions.ChannelOptions;
IsSecureConnection = clientOptions.ChannelOptions?.TlsOptions?.UseTls == true;
}
/// <summary>
@@ -37,6 +39,8 @@ namespace MQTTnet.Implementations
{
_socket = socket ?? throw new ArgumentNullException(nameof(socket));
IsSecureConnection = sslStream != null;
CreateStream(sslStream);
}
@@ -45,6 +49,8 @@ namespace MQTTnet.Implementations
public string Endpoint => _socket?.RemoteEndPoint?.ToString();
public bool IsSecureConnection { get; }
public async Task ConnectAsync(CancellationToken cancellationToken)
{
if (_socket == null)
@@ -23,7 +23,7 @@ namespace MQTTnet.Implementations
_logger = logger.CreateChildLogger(nameof(MqttTcpServerAdapter));
}
public event EventHandler<MqttServerAdapterClientAcceptedEventArgs> ClientAccepted;
public Action<MqttServerAdapterClientAcceptedEventArgs> ClientAcceptedHandler { get; set; }
public async Task StartAsync(IMqttServerOptions options)
{
@@ -73,7 +73,7 @@ namespace MQTTnet.Implementations
try
{
var clientAdapter = new MqttChannelAdapter(new MqttTcpChannel(args.Socket, _options), new MqttPacketFormatterAdapter(), _logger);
ClientAccepted?.Invoke(this, new MqttServerAdapterClientAcceptedEventArgs(clientAdapter));
ClientAcceptedHandler?.Invoke(new MqttServerAdapterClientAcceptedEventArgs(clientAdapter));
}
catch (Exception exception)
{
@@ -26,7 +26,7 @@ namespace MQTTnet.Implementations
_logger = logger.CreateChildLogger(nameof(MqttTcpServerAdapter));
}
public event EventHandler<MqttServerAdapterClientAcceptedEventArgs> ClientAccepted;
public Action<MqttServerAdapterClientAcceptedEventArgs> ClientAcceptedHandler { get; set; }
public Task StartAsync(IMqttServerOptions options)
{
@@ -87,9 +87,11 @@ namespace MQTTnet.Implementations
options,
tlsCertificate,
_cancellationTokenSource.Token,
_logger);
_logger)
{
ClientAcceptedHandler = OnClientAccepted
};
listenerV4.ClientAccepted += OnClientAccepted;
listenerV4.Start();
_listeners.Add(listenerV4);
}
@@ -101,17 +103,19 @@ namespace MQTTnet.Implementations
options,
tlsCertificate,
_cancellationTokenSource.Token,
_logger);
_logger)
{
ClientAcceptedHandler = OnClientAccepted
};
listenerV6.ClientAccepted += OnClientAccepted;
listenerV6.Start();
_listeners.Add(listenerV6);
}
}
private void OnClientAccepted(object sender, MqttServerAdapterClientAcceptedEventArgs e)
private void OnClientAccepted(MqttServerAdapterClientAcceptedEventArgs eventArgs)
{
ClientAccepted?.Invoke(this, e);
ClientAcceptedHandler?.Invoke(eventArgs);
}
}
}
@@ -42,7 +42,7 @@ namespace MQTTnet.Implementations
}
}
public event EventHandler<MqttServerAdapterClientAcceptedEventArgs> ClientAccepted;
public Action<MqttServerAdapterClientAcceptedEventArgs> ClientAcceptedHandler;
public void Start()
{
@@ -88,7 +88,7 @@ namespace MQTTnet.Implementations
_addressFamily == AddressFamily.InterNetwork ? "ipv4" : "ipv6");
var clientAdapter = new MqttChannelAdapter(new MqttTcpChannel(clientSocket, sslStream), new MqttPacketFormatterAdapter(), _logger);
ClientAccepted?.Invoke(this, new MqttServerAdapterClientAcceptedEventArgs(clientAdapter));
ClientAcceptedHandler?.Invoke(new MqttServerAdapterClientAcceptedEventArgs(clientAdapter));
}
catch (ObjectDisposedException)
{
@@ -1,4 +1,5 @@
using System;
using System.Globalization;
using System.Net;
using System.Net.WebSockets;
using System.Security.Cryptography.X509Certificates;
@@ -21,14 +22,18 @@ namespace MQTTnet.Implementations
_options = options ?? throw new ArgumentNullException(nameof(options));
}
public MqttWebSocketChannel(WebSocket webSocket, string endpoint)
public MqttWebSocketChannel(WebSocket webSocket, string endpoint, bool isSecureConnection)
{
_webSocket = webSocket ?? throw new ArgumentNullException(nameof(webSocket));
Endpoint = endpoint;
IsSecureConnection = isSecureConnection;
}
public string Endpoint { get; }
public bool IsSecureConnection { get; private set; }
public async Task ConnectAsync(CancellationToken cancellationToken)
{
var uri = _options.Uri;
@@ -83,6 +88,8 @@ namespace MQTTnet.Implementations
await clientWebSocket.ConnectAsync(new Uri(uri), cancellationToken).ConfigureAwait(false);
_webSocket = clientWebSocket;
IsSecureConnection = uri.StartsWith("wss://", StringComparison.OrdinalIgnoreCase);
}
public async Task DisconnectAsync(CancellationToken cancellationToken)
@@ -16,6 +16,8 @@ namespace MQTTnet.Internal
public string Endpoint { get; } = "<Test channel>";
public bool IsSecureConnection { get; } = false;
public Task ConnectAsync(CancellationToken cancellationToken)
{
return Task.FromResult(0);
@@ -13,5 +13,7 @@ namespace MQTTnet
public string ClientId { get; }
public MqttApplicationMessage ApplicationMessage { get; }
public bool ProcessingFailed { get; set; }
}
}
+22 -5
View File
@@ -8,11 +8,22 @@ using MQTTnet.Server;
namespace MQTTnet
{
public class MqttFactory : IMqttClientFactory, IMqttServerFactory
public class MqttFactory : IMqttFactory
{
public MqttFactory() : this(new MqttNetLogger())
{
}
public MqttFactory(IMqttNetLogger logger)
{
DefaultLogger = logger ?? throw new ArgumentNullException(nameof(logger));
}
public IMqttNetLogger DefaultLogger { get; }
public IMqttClient CreateMqttClient()
{
return CreateMqttClient(new MqttNetLogger());
return CreateMqttClient(DefaultLogger);
}
public IMqttClient CreateMqttClient(IMqttNetLogger logger)
@@ -26,7 +37,7 @@ namespace MQTTnet
{
if (adapterFactory == null) throw new ArgumentNullException(nameof(adapterFactory));
return new MqttClient(adapterFactory, new MqttNetLogger());
return new MqttClient(adapterFactory, DefaultLogger);
}
public IMqttClient CreateMqttClient(IMqttNetLogger logger, IMqttClientAdapterFactory adapterFactory)
@@ -39,8 +50,7 @@ namespace MQTTnet
public IMqttServer CreateMqttServer()
{
var logger = new MqttNetLogger();
return CreateMqttServer(logger);
return CreateMqttServer(DefaultLogger);
}
public IMqttServer CreateMqttServer(IMqttNetLogger logger)
@@ -57,5 +67,12 @@ namespace MQTTnet
return new MqttServer(adapters, logger.CreateChildLogger());
}
public IMqttServer CreateMqttServer(IEnumerable<IMqttServerAdapter> adapters)
{
if (adapters == null) throw new ArgumentNullException(nameof(adapters));
return new MqttServer(adapters, DefaultLogger.CreateChildLogger());
}
}
}
+7 -1
View File
@@ -27,7 +27,13 @@
public override string ToString()
{
return string.Concat("Connect: [ProtocolLevel=", ProtocolLevel, "] [ClientId=", ClientId, "] [Username=", Username, "] [Password=", Password, "] [KeepAlivePeriod=", KeepAlivePeriod, "] [CleanSession=", CleanSession, "]");
var password = Password;
if (!string.IsNullOrEmpty(password))
{
password = "****";
}
return string.Concat("Connect: [ProtocolLevel=", ProtocolLevel, "] [ClientId=", ClientId, "] [Username=", Username, "] [Password=", password, "] [KeepAlivePeriod=", KeepAlivePeriod, "] [CleanSession=", CleanSession, "]");
}
}
}
+7 -8
View File
@@ -1,5 +1,4 @@
using System;
using System.Collections.Generic;
using System.Collections.Generic;
using System.Threading.Tasks;
using MQTTnet.Server.Status;
@@ -7,13 +6,13 @@ namespace MQTTnet.Server
{
public interface IMqttServer : IApplicationMessageReceiver, IApplicationMessagePublisher
{
event EventHandler Started;
event EventHandler Stopped;
IMqttServerStartedHandler StartedHandler { get; set; }
IMqttServerStoppedHandler StoppedHandler { get; set; }
event EventHandler<MqttClientConnectedEventArgs> ClientConnected;
event EventHandler<MqttClientDisconnectedEventArgs> ClientDisconnected;
event EventHandler<MqttClientSubscribedTopicEventArgs> ClientSubscribedTopic;
event EventHandler<MqttClientUnsubscribedTopicEventArgs> ClientUnsubscribedTopic;
IMqttServerClientConnectedHandler ClientConnectedHandler { get; set; }
IMqttServerClientDisconnectedHandler ClientDisconnectedHandler { get; set; }
IMqttServerClientSubscribedTopicHandler ClientSubscribedTopicHandler { get; set; }
IMqttServerClientUnsubscribedTopicHandler ClientUnsubscribedTopicHandler { get; set; }
IMqttServerOptions Options { get; }
@@ -0,0 +1,9 @@
using System.Threading.Tasks;
namespace MQTTnet.Server
{
public interface IMqttServerClientConnectedHandler
{
Task HandleClientConnectedAsync(MqttServerClientConnectedEventArgs eventArgs);
}
}
@@ -0,0 +1,9 @@
using System.Threading.Tasks;
namespace MQTTnet.Server
{
public interface IMqttServerClientDisconnectedHandler
{
Task HandleClientDisconnectedAsync(MqttServerClientDisconnectedEventArgs eventArgs);
}
}
@@ -0,0 +1,9 @@
using System.Threading.Tasks;
namespace MQTTnet.Server
{
public interface IMqttServerClientSubscribedTopicHandler
{
Task HandleClientSubscribedTopicAsync(MqttServerClientSubscribedTopicEventArgs eventArgs);
}
}
@@ -0,0 +1,9 @@
using System.Threading.Tasks;
namespace MQTTnet.Server
{
public interface IMqttServerClientUnsubscribedTopicHandler
{
Task HandleClientUnsubscribedTopicAsync(MqttServerClientUnsubscribedTopicEventArgs eventArgs);
}
}
@@ -10,6 +10,8 @@ namespace MQTTnet.Server
IMqttServer CreateMqttServer(IMqttNetLogger logger);
IMqttServer CreateMqttServer(IEnumerable<IMqttServerAdapter> adapters);
IMqttServer CreateMqttServer(IEnumerable<IMqttServerAdapter> adapters, IMqttNetLogger logger);
}
}
@@ -0,0 +1,10 @@
using System;
using System.Threading.Tasks;
namespace MQTTnet.Server
{
public interface IMqttServerStartedHandler
{
Task HandleServerStartedAsync(EventArgs eventArgs);
}
}
@@ -0,0 +1,10 @@
using System;
using System.Threading.Tasks;
namespace MQTTnet.Server
{
public interface IMqttServerStoppedHandler
{
Task HandleServerStoppedAsync(EventArgs eventArgs);
}
}
+1 -57
View File
@@ -14,62 +14,6 @@ using MQTTnet.Server.Status;
namespace MQTTnet.Server
{
public class MqttClientSession
{
private readonly DateTime _createdTimestamp = DateTime.UtcNow;
public MqttClientSession(string clientId, MqttServerEventDispatcher eventDispatcher, IMqttServerOptions serverOptions)
{
ClientId = clientId ?? throw new ArgumentNullException(nameof(clientId));
SubscriptionsManager = new MqttClientSubscriptionsManager(clientId, eventDispatcher, serverOptions);
ApplicationMessagesQueue = new MqttClientSessionApplicationMessagesQueue(serverOptions);
}
public string ClientId { get; }
public bool IsCleanSession { get; set; } = true;
public MqttApplicationMessage WillMessage { get; set; }
public MqttClientSubscriptionsManager SubscriptionsManager { get; }
public MqttClientSessionApplicationMessagesQueue ApplicationMessagesQueue { get; }
public void EnqueueApplicationMessage(MqttApplicationMessage applicationMessage, string senderClientId, bool isRetainedApplicationMessage)
{
var checkSubscriptionsResult = SubscriptionsManager.CheckSubscriptions(applicationMessage.Topic, applicationMessage.QualityOfServiceLevel);
if (!checkSubscriptionsResult.IsSubscribed)
{
return;
}
ApplicationMessagesQueue.Enqueue(applicationMessage, senderClientId, checkSubscriptionsResult.QualityOfServiceLevel, isRetainedApplicationMessage);
}
public async Task SubscribeAsync(ICollection<TopicFilter> topicFilters, MqttRetainedMessagesManager retainedMessagesManager)
{
await SubscriptionsManager.SubscribeAsync(topicFilters).ConfigureAwait(false);
var matchingRetainedMessages = await retainedMessagesManager.GetSubscribedMessagesAsync(topicFilters).ConfigureAwait(false);
foreach (var matchingRetainedMessage in matchingRetainedMessages)
{
EnqueueApplicationMessage(matchingRetainedMessage, null, true);
}
}
public Task UnsubscribeAsync(IEnumerable<string> topicFilters)
{
return SubscriptionsManager.UnsubscribeAsync(topicFilters);
}
public void FillStatus(MqttSessionStatus status)
{
status.ClientId = ClientId;
status.CreatedTimestamp = _createdTimestamp;
status.PendingApplicationMessagesCount = ApplicationMessagesQueue.Count;
}
}
public class MqttClientConnection : IMqttClientSession, IDisposable
{
private readonly MqttPacketIdentifierProvider _packetIdentifierProvider = new MqttPacketIdentifierProvider();
@@ -425,7 +369,7 @@ namespace MQTTnet.Server
//// }
////});
await Task.FromResult(0);
//await Task.FromResult(0);
}
private async Task SendPendingPacketsAsync()
@@ -0,0 +1,63 @@
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using MQTTnet.Server.Status;
namespace MQTTnet.Server
{
public class MqttClientSession
{
private readonly DateTime _createdTimestamp = DateTime.UtcNow;
public MqttClientSession(string clientId, MqttServerEventDispatcher eventDispatcher, IMqttServerOptions serverOptions)
{
ClientId = clientId ?? throw new ArgumentNullException(nameof(clientId));
SubscriptionsManager = new MqttClientSubscriptionsManager(clientId, eventDispatcher, serverOptions);
ApplicationMessagesQueue = new MqttClientSessionApplicationMessagesQueue(serverOptions);
}
public string ClientId { get; }
public bool IsCleanSession { get; set; } = true;
public MqttApplicationMessage WillMessage { get; set; }
public MqttClientSubscriptionsManager SubscriptionsManager { get; }
public MqttClientSessionApplicationMessagesQueue ApplicationMessagesQueue { get; }
public void EnqueueApplicationMessage(MqttApplicationMessage applicationMessage, string senderClientId, bool isRetainedApplicationMessage)
{
var checkSubscriptionsResult = SubscriptionsManager.CheckSubscriptions(applicationMessage.Topic, applicationMessage.QualityOfServiceLevel);
if (!checkSubscriptionsResult.IsSubscribed)
{
return;
}
ApplicationMessagesQueue.Enqueue(applicationMessage, senderClientId, checkSubscriptionsResult.QualityOfServiceLevel, isRetainedApplicationMessage);
}
public async Task SubscribeAsync(ICollection<TopicFilter> topicFilters, MqttRetainedMessagesManager retainedMessagesManager)
{
await SubscriptionsManager.SubscribeAsync(topicFilters).ConfigureAwait(false);
var matchingRetainedMessages = await retainedMessagesManager.GetSubscribedMessagesAsync(topicFilters).ConfigureAwait(false);
foreach (var matchingRetainedMessage in matchingRetainedMessages)
{
EnqueueApplicationMessage(matchingRetainedMessage, null, true);
}
}
public Task UnsubscribeAsync(IEnumerable<string> topicFilters)
{
return SubscriptionsManager.UnsubscribeAsync(topicFilters);
}
public void FillStatus(MqttSessionStatus status)
{
status.ClientId = ClientId;
status.CreatedTimestamp = _createdTimestamp;
status.PendingApplicationMessagesCount = ApplicationMessagesQueue.Count;
}
}
}
@@ -15,6 +15,7 @@ namespace MQTTnet.Server
{
private readonly BlockingCollection<MqttEnqueuedApplicationMessage> _messageQueue = new BlockingCollection<MqttEnqueuedApplicationMessage>();
private readonly SemaphoreSlim _createConnectionGate = new SemaphoreSlim(1, 1);
private readonly ConcurrentDictionary<string, MqttClientConnection> _connections = new ConcurrentDictionary<string, MqttClientConnection>();
private readonly ConcurrentDictionary<string, MqttClientSession> _sessions = new ConcurrentDictionary<string, MqttClientSession>();
@@ -49,8 +50,6 @@ namespace MQTTnet.Server
public async Task StopAsync()
{
//using (await _sessionsLock.WaitAsync(CancellationToken.None).ConfigureAwait(false))
foreach (var connection in _connections.Values)
{
await connection.StopAsync().ConfigureAwait(false);
@@ -133,7 +132,7 @@ namespace MQTTnet.Server
{
if (_connections.TryGetValue(clientId, out var connection))
{
await connection.StopAsync();
await connection.StopAsync().ConfigureAwait(false);
}
if (_sessions.TryRemove(clientId, out var session))
@@ -196,7 +195,7 @@ namespace MQTTnet.Server
applicationMessage = interceptorContext.ApplicationMessage;
}
_eventDispatcher.OnApplicationMessageReceived(sender?.ClientId, applicationMessage);
await _eventDispatcher.HandleApplicationMessageReceivedAsync(sender?.ClientId, applicationMessage).ConfigureAwait(false);
if (applicationMessage.Retain)
{
@@ -258,7 +257,7 @@ namespace MQTTnet.Server
var connection = await CreateConnectionAsync(channelAdapter, connectPacket).ConfigureAwait(false);
_eventDispatcher.OnClientConnected(clientId);
await _eventDispatcher.HandleClientConnectedAsync(clientId).ConfigureAwait(false);
disconnectType = await connection.RunAsync().ConfigureAwait(false);
}
@@ -288,7 +287,7 @@ namespace MQTTnet.Server
await TryCleanupChannelAsync(channelAdapter).ConfigureAwait(false);
_eventDispatcher.OnClientDisconnected(clientId, disconnectType);
await _eventDispatcher.HandleClientDisconnectedAsync(clientId, disconnectType).ConfigureAwait(false);
}
}
@@ -299,7 +298,8 @@ namespace MQTTnet.Server
connectPacket.Username,
connectPacket.Password,
connectPacket.WillMessage,
clientAdapter.Endpoint);
clientAdapter.Endpoint,
clientAdapter.IsSecureConnection);
var connectionValidator = _options.ConnectionValidator;
@@ -313,8 +313,6 @@ namespace MQTTnet.Server
return context;
}
private readonly SemaphoreSlim _createConnectionGate = new SemaphoreSlim(1, 1);
private async Task<MqttClientConnection> CreateConnectionAsync(IMqttChannelAdapter channelAdapter, MqttConnectPacket connectPacket)
{
await _createConnectionGate.WaitAsync(_cancellationToken).ConfigureAwait(false);
@@ -61,7 +61,7 @@ namespace MQTTnet.Server
_subscriptions[topicFilter.Topic] = topicFilter.QualityOfServiceLevel;
}
_eventDispatcher.OnClientSubscribedTopic(_clientId, topicFilter);
await _eventDispatcher.HandleClientSubscribedTopicAsync(_clientId, topicFilter).ConfigureAwait(false);
}
}
@@ -85,12 +85,12 @@ namespace MQTTnet.Server
_subscriptions[topicFilter.Topic] = topicFilter.QualityOfServiceLevel;
}
_eventDispatcher.OnClientSubscribedTopic(_clientId, topicFilter);
await _eventDispatcher.HandleClientSubscribedTopicAsync(_clientId, topicFilter).ConfigureAwait(false);
}
}
}
public Task<MqttUnsubAckPacket> UnsubscribeAsync(MqttUnsubscribePacket unsubscribePacket)
public async Task<MqttUnsubAckPacket> UnsubscribeAsync(MqttUnsubscribePacket unsubscribePacket)
{
if (unsubscribePacket == null) throw new ArgumentNullException(nameof(unsubscribePacket));
@@ -111,12 +111,15 @@ namespace MQTTnet.Server
{
unsubAckPacket.ReasonCodes.Add(MqttUnsubscribeReasonCode.NoSubscriptionExisted);
}
_eventDispatcher.OnClientUnsubscribedTopic(_clientId, topicFilter);
}
}
return Task.FromResult(unsubAckPacket);
foreach (var topicFilter in unsubscribePacket.TopicFilters)
{
await _eventDispatcher.HandleClientUnsubscribedTopicAsync(_clientId, topicFilter).ConfigureAwait(false);
}
return unsubAckPacket;
}
public Task UnsubscribeAsync(IEnumerable<string> topicFilters)
@@ -4,13 +4,14 @@ namespace MQTTnet.Server
{
public class MqttConnectionValidatorContext
{
public MqttConnectionValidatorContext(string clientId, string username, string password, MqttApplicationMessage willMessage, string endpoint)
public MqttConnectionValidatorContext(string clientId, string username, string password, MqttApplicationMessage willMessage, string endpoint, bool isSecureConnection)
{
ClientId = clientId;
Username = username;
Password = password;
WillMessage = willMessage;
Endpoint = endpoint;
IsSecureConnection = isSecureConnection;
}
public string ClientId { get; }
@@ -23,6 +24,8 @@ namespace MQTTnet.Server
public string Endpoint { get; }
public bool IsSecureConnection { get; }
public MqttConnectReturnCode ReturnCode { get; set; } = MqttConnectReturnCode.ConnectionAccepted;
}
}
+46 -30
View File
@@ -28,35 +28,41 @@ namespace MQTTnet.Server
if (logger == null) throw new ArgumentNullException(nameof(logger));
_logger = logger.CreateChildLogger(nameof(MqttServer));
_eventDispatcher.ClientConnected += (s, e) => ClientConnected?.Invoke(s, e);
_eventDispatcher.ClientDisconnected += (s, e) => ClientDisconnected?.Invoke(s, e);
_eventDispatcher.ClientSubscribedTopic += (s, e) => ClientSubscribedTopic?.Invoke(s, e);
_eventDispatcher.ClientUnsubscribedTopic += (s, e) => ClientUnsubscribedTopic?.Invoke(s, e);
_eventDispatcher.ApplicationMessageReceived += async (s, e) =>
{
// TODO: Migrate EventDispatcher to proper handlers and no events anymore.
ApplicationMessageReceived?.Invoke(s, e);
var handler = ReceivedApplicationMessageHandler;
if (handler != null)
{
await handler.HandleApplicationMessageAsync(
new MqttApplicationMessageHandlerContext(e.ClientId, e.ApplicationMessage)).ConfigureAwait(false);
}
};
}
public event EventHandler Started;
public event EventHandler Stopped;
public IMqttServerStartedHandler StartedHandler { get; set; }
public event EventHandler<MqttClientConnectedEventArgs> ClientConnected;
public event EventHandler<MqttClientDisconnectedEventArgs> ClientDisconnected;
public event EventHandler<MqttClientSubscribedTopicEventArgs> ClientSubscribedTopic;
public event EventHandler<MqttClientUnsubscribedTopicEventArgs> ClientUnsubscribedTopic;
public IMqttServerStoppedHandler StoppedHandler { get; set; }
public IMqttApplicationMessageHandler ReceivedApplicationMessageHandler { get; set; }
public event EventHandler<MqttApplicationMessageReceivedEventArgs> ApplicationMessageReceived;
public IMqttServerClientConnectedHandler ClientConnectedHandler
{
get => _eventDispatcher.ClientConnectedHandler;
set => _eventDispatcher.ClientConnectedHandler = value;
}
public IMqttServerClientDisconnectedHandler ClientDisconnectedHandler
{
get => _eventDispatcher.ClientDisconnectedHandler;
set => _eventDispatcher.ClientDisconnectedHandler = value;
}
public IMqttServerClientSubscribedTopicHandler ClientSubscribedTopicHandler
{
get => _eventDispatcher.ClientSubscribedTopicHandler;
set => _eventDispatcher.ClientSubscribedTopicHandler = value;
}
public IMqttServerClientUnsubscribedTopicHandler ClientUnsubscribedTopicHandler
{
get => _eventDispatcher.ClientUnsubscribedTopicHandler;
set => _eventDispatcher.ClientUnsubscribedTopicHandler = value;
}
public IMqttApplicationMessageReceivedHandler ApplicationMessageReceivedHandler
{
get => _eventDispatcher.ApplicationMessageReceivedHandler;
set => _eventDispatcher.ApplicationMessageReceivedHandler = value;
}
public IMqttServerOptions Options { get; private set; }
@@ -118,12 +124,17 @@ namespace MQTTnet.Server
foreach (var adapter in _adapters)
{
adapter.ClientAccepted += OnClientAccepted;
adapter.ClientAcceptedHandler = OnClientAccepted;
await adapter.StartAsync(Options).ConfigureAwait(false);
}
_logger.Info("Started.");
Started?.Invoke(this, EventArgs.Empty);
var startedHandler = StartedHandler;
if (startedHandler != null)
{
await startedHandler.HandleServerStartedAsync(EventArgs.Empty).ConfigureAwait(false);
}
}
public async Task StopAsync()
@@ -141,12 +152,11 @@ namespace MQTTnet.Server
foreach (var adapter in _adapters)
{
adapter.ClientAccepted -= OnClientAccepted;
adapter.ClientAcceptedHandler = null;
await adapter.StopAsync().ConfigureAwait(false);
}
_logger.Info("Stopped.");
Stopped?.Invoke(this, EventArgs.Empty);
}
finally
{
@@ -158,6 +168,12 @@ namespace MQTTnet.Server
_clientSessionsManager?.Dispose();
_clientSessionsManager = null;
}
var stoppedHandler = StoppedHandler;
if (stoppedHandler != null)
{
await stoppedHandler.HandleServerStoppedAsync(EventArgs.Empty).ConfigureAwait(false);
}
}
public Task ClearRetainedMessagesAsync()
@@ -165,7 +181,7 @@ namespace MQTTnet.Server
return _retainedMessagesManager?.ClearMessagesAsync();
}
private void OnClientAccepted(object sender, MqttServerAdapterClientAcceptedEventArgs eventArgs)
private void OnClientAccepted(MqttServerAdapterClientAcceptedEventArgs eventArgs)
{
eventArgs.SessionTask = _clientSessionsManager.HandleConnectionAsync(eventArgs.Client);
}
@@ -2,9 +2,9 @@
namespace MQTTnet.Server
{
public class MqttClientConnectedEventArgs : EventArgs
public class MqttServerClientConnectedEventArgs : EventArgs
{
public MqttClientConnectedEventArgs(string clientId)
public MqttServerClientConnectedEventArgs(string clientId)
{
ClientId = clientId ?? throw new ArgumentNullException(nameof(clientId));
}
@@ -0,0 +1,31 @@
using System;
using System.Threading.Tasks;
namespace MQTTnet.Server
{
public class MqttServerClientConnectedHandlerDelegate : IMqttServerClientConnectedHandler
{
private readonly Func<MqttServerClientConnectedEventArgs, Task> _handler;
public MqttServerClientConnectedHandlerDelegate(Action<MqttServerClientConnectedEventArgs> handler)
{
if (handler == null) throw new ArgumentNullException(nameof(handler));
_handler = eventArgs =>
{
handler(eventArgs);
return Task.FromResult(0);
};
}
public MqttServerClientConnectedHandlerDelegate(Func<MqttServerClientConnectedEventArgs, Task> handler)
{
_handler = handler ?? throw new ArgumentNullException(nameof(handler));
}
public Task HandleClientConnectedAsync(MqttServerClientConnectedEventArgs eventArgs)
{
return _handler(eventArgs);
}
}
}
@@ -2,9 +2,9 @@
namespace MQTTnet.Server
{
public class MqttClientDisconnectedEventArgs : EventArgs
public class MqttServerClientDisconnectedEventArgs : EventArgs
{
public MqttClientDisconnectedEventArgs(string clientId, MqttClientDisconnectType disconnectType)
public MqttServerClientDisconnectedEventArgs(string clientId, MqttClientDisconnectType disconnectType)
{
ClientId = clientId ?? throw new ArgumentNullException(nameof(clientId));
DisconnectType = disconnectType;
@@ -0,0 +1,31 @@
using System;
using System.Threading.Tasks;
namespace MQTTnet.Server
{
public class MqttServerClientDisconnectedHandlerDelegate : IMqttServerClientDisconnectedHandler
{
private readonly Func<MqttServerClientDisconnectedEventArgs, Task> _handler;
public MqttServerClientDisconnectedHandlerDelegate(Action<MqttServerClientDisconnectedEventArgs> handler)
{
if (handler == null) throw new ArgumentNullException(nameof(handler));
_handler = eventArgs =>
{
handler(eventArgs);
return Task.FromResult(0);
};
}
public MqttServerClientDisconnectedHandlerDelegate(Func<MqttServerClientDisconnectedEventArgs, Task> handler)
{
_handler = handler ?? throw new ArgumentNullException(nameof(handler));
}
public Task HandleClientDisconnectedAsync(MqttServerClientDisconnectedEventArgs eventArgs)
{
return _handler(eventArgs);
}
}
}
@@ -2,9 +2,9 @@
namespace MQTTnet.Server
{
public class MqttClientSubscribedTopicEventArgs : EventArgs
public class MqttServerClientSubscribedTopicEventArgs : EventArgs
{
public MqttClientSubscribedTopicEventArgs(string clientId, TopicFilter topicFilter)
public MqttServerClientSubscribedTopicEventArgs(string clientId, TopicFilter topicFilter)
{
ClientId = clientId ?? throw new ArgumentNullException(nameof(clientId));
TopicFilter = topicFilter ?? throw new ArgumentNullException(nameof(topicFilter));
@@ -0,0 +1,31 @@
using System;
using System.Threading.Tasks;
namespace MQTTnet.Server
{
public class MqttServerClientSubscribedHandlerDelegate : IMqttServerClientSubscribedTopicHandler
{
private readonly Func<MqttServerClientSubscribedTopicEventArgs, Task> _handler;
public MqttServerClientSubscribedHandlerDelegate(Action<MqttServerClientSubscribedTopicEventArgs> handler)
{
if (handler == null) throw new ArgumentNullException(nameof(handler));
_handler = eventArgs =>
{
handler(eventArgs);
return Task.FromResult(0);
};
}
public MqttServerClientSubscribedHandlerDelegate(Func<MqttServerClientSubscribedTopicEventArgs, Task> handler)
{
_handler = handler ?? throw new ArgumentNullException(nameof(handler));
}
public Task HandleClientSubscribedTopicAsync(MqttServerClientSubscribedTopicEventArgs eventArgs)
{
return _handler(eventArgs);
}
}
}
@@ -2,9 +2,9 @@
namespace MQTTnet.Server
{
public class MqttClientUnsubscribedTopicEventArgs : EventArgs
public class MqttServerClientUnsubscribedTopicEventArgs : EventArgs
{
public MqttClientUnsubscribedTopicEventArgs(string clientId, string topicFilter)
public MqttServerClientUnsubscribedTopicEventArgs(string clientId, string topicFilter)
{
ClientId = clientId ?? throw new ArgumentNullException(nameof(clientId));
TopicFilter = topicFilter ?? throw new ArgumentNullException(nameof(topicFilter));
@@ -0,0 +1,31 @@
using System;
using System.Threading.Tasks;
namespace MQTTnet.Server
{
public class MqttServerClientUnsubscribedTopicHandlerDelegate : IMqttServerClientUnsubscribedTopicHandler
{
private readonly Func<MqttServerClientUnsubscribedTopicEventArgs, Task> _handler;
public MqttServerClientUnsubscribedTopicHandlerDelegate(Action<MqttServerClientUnsubscribedTopicEventArgs> handler)
{
if (handler == null) throw new ArgumentNullException(nameof(handler));
_handler = eventArgs =>
{
handler(eventArgs);
return Task.FromResult(0);
};
}
public MqttServerClientUnsubscribedTopicHandlerDelegate(Func<MqttServerClientUnsubscribedTopicEventArgs, Task> handler)
{
_handler = handler ?? throw new ArgumentNullException(nameof(handler));
}
public Task HandleClientUnsubscribedTopicAsync(MqttServerClientUnsubscribedTopicEventArgs eventArgs)
{
return _handler(eventArgs);
}
}
}
@@ -1,42 +1,73 @@
using System;
using System.Threading.Tasks;
using MQTTnet.Client.Receiving;
namespace MQTTnet.Server
{
public class MqttServerEventDispatcher
{
public event EventHandler<MqttClientSubscribedTopicEventArgs> ClientSubscribedTopic;
public IMqttServerClientConnectedHandler ClientConnectedHandler { get; set; }
public event EventHandler<MqttClientUnsubscribedTopicEventArgs> ClientUnsubscribedTopic;
public IMqttServerClientDisconnectedHandler ClientDisconnectedHandler { get; set; }
public event EventHandler<MqttClientConnectedEventArgs> ClientConnected;
public IMqttServerClientSubscribedTopicHandler ClientSubscribedTopicHandler { get; set; }
public event EventHandler<MqttClientDisconnectedEventArgs> ClientDisconnected;
public IMqttServerClientUnsubscribedTopicHandler ClientUnsubscribedTopicHandler { get; set; }
public event EventHandler<MqttApplicationMessageReceivedEventArgs> ApplicationMessageReceived;
public IMqttApplicationMessageReceivedHandler ApplicationMessageReceivedHandler { get; set; }
public void OnClientSubscribedTopic(string clientId, TopicFilter topicFilter)
public Task HandleClientConnectedAsync(string clientId)
{
ClientSubscribedTopic?.Invoke(this, new MqttClientSubscribedTopicEventArgs(clientId, topicFilter));
var handler = ClientConnectedHandler;
if (handler == null)
{
return Task.FromResult(0);
}
return handler.HandleClientConnectedAsync(new MqttServerClientConnectedEventArgs(clientId));
}
public void OnClientUnsubscribedTopic(string clientId, string topicFilter)
public Task HandleClientDisconnectedAsync(string clientId, MqttClientDisconnectType disconnectType)
{
ClientUnsubscribedTopic?.Invoke(this, new MqttClientUnsubscribedTopicEventArgs(clientId, topicFilter));
var handler = ClientDisconnectedHandler;
if (handler == null)
{
return Task.FromResult(0);
}
return handler.HandleClientDisconnectedAsync(new MqttServerClientDisconnectedEventArgs(clientId, disconnectType));
}
public void OnClientDisconnected(string clientId, MqttClientDisconnectType disconnectType)
public Task HandleClientSubscribedTopicAsync(string clientId, TopicFilter topicFilter)
{
ClientDisconnected?.Invoke(this, new MqttClientDisconnectedEventArgs(clientId, disconnectType));
var handler = ClientSubscribedTopicHandler;
if (handler == null)
{
return Task.FromResult(0);
}
return handler.HandleClientSubscribedTopicAsync(new MqttServerClientSubscribedTopicEventArgs(clientId, topicFilter));
}
public void OnApplicationMessageReceived(string senderClientId, MqttApplicationMessage applicationMessage)
public Task HandleClientUnsubscribedTopicAsync(string clientId, string topicFilter)
{
ApplicationMessageReceived?.Invoke(this, new MqttApplicationMessageReceivedEventArgs(senderClientId, applicationMessage));
var handler = ClientUnsubscribedTopicHandler;
if (handler == null)
{
return Task.FromResult(0);
}
return handler.HandleClientUnsubscribedTopicAsync(new MqttServerClientUnsubscribedTopicEventArgs(clientId, topicFilter));
}
public void OnClientConnected(string clientId)
public Task HandleApplicationMessageReceivedAsync(string senderClientId, MqttApplicationMessage applicationMessage)
{
ClientConnected?.Invoke(this, new MqttClientConnectedEventArgs(clientId));
var handler = ApplicationMessageReceivedHandler;
if (handler == null)
{
return Task.FromResult(0);
}
return handler.HandleApplicationMessageReceivedAsync(new MqttApplicationMessageReceivedEventArgs(senderClientId, applicationMessage));
}
}
}
@@ -75,6 +75,12 @@ namespace MQTTnet.Server
return this;
}
public MqttServerOptionsBuilder WithEncryptedEndpointBoundIPV6Address(IPAddress value)
{
_options.TlsEndpointOptions.BoundInterNetworkV6Address = value;
return this;
}
public MqttServerOptionsBuilder WithEncryptionCertificate(byte[] value)
{
_options.TlsEndpointOptions.Certificate = value;

Some files were not shown because too many files have changed in this diff Show More