Add more function mappings for MQTTnet Server.

This commit is contained in:
Christian Kratky
2019-03-06 22:42:00 +01:00
parent dffc27c1f4
commit 8708609498
55 changed files with 664 additions and 363 deletions
@@ -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);
}
}
}
@@ -10,7 +10,7 @@ namespace MQTTnet.Server.Mqtt
public class MqttApplicationMessageInterceptor : IMqttServerApplicationMessageInterceptor
{
private readonly PythonScriptHostService _pythonScriptHostService;
private readonly ILogger<MqttApplicationMessageInterceptor> _logger;
private readonly ILogger _logger;
public MqttApplicationMessageInterceptor(PythonScriptHostService pythonScriptHostService, ILogger<MqttApplicationMessageInterceptor> logger)
{
@@ -31,7 +31,7 @@ namespace MQTTnet.Server.Mqtt
{ "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);
@@ -46,5 +46,21 @@ namespace MQTTnet.Server.Mqtt
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;
}
}
}
@@ -10,7 +10,7 @@ namespace MQTTnet.Server.Mqtt
public class MqttConnectionValidator : IMqttServerConnectionValidator
{
private readonly PythonScriptHostService _pythonScriptHostService;
private readonly ILogger<MqttConnectionValidator> _logger;
private readonly ILogger _logger;
public MqttConnectionValidator(PythonScriptHostService pythonScriptHostService, ILogger<MqttConnectionValidator> logger)
{
+58 -29
View File
@@ -8,7 +8,6 @@ using MQTTnet.Adapter;
using MQTTnet.AspNetCore;
using MQTTnet.Implementations;
using MQTTnet.Protocol;
using MQTTnet.Server.Logging;
using MQTTnet.Server.Scripting;
namespace MQTTnet.Server.Mqtt
@@ -17,6 +16,10 @@ namespace MQTTnet.Server.Mqtt
{
private readonly ILogger<MqttServerService> _logger;
private readonly MqttClientConnectedHandler _mqttClientConnectedHandler;
private readonly MqttClientDisconnectedHandler _mqttClientDisconnectedHandler;
private readonly MqttClientSubscribedTopicHandler _mqttClientSubscribedTopicHandler;
private readonly MqttClientUnsubscribedTopicHandler _mqttClientUnsubscribedTopicHandler;
private readonly MqttConnectionValidator _mqttConnectionValidator;
private readonly MqttSubscriptionInterceptor _mqttSubscriptionInterceptor;
private readonly MqttApplicationMessageInterceptor _mqttApplicationMessageInterceptor;
@@ -25,15 +28,22 @@ namespace MQTTnet.Server.Mqtt
private readonly IMqttServer _mqttServer;
public MqttServerService(
IMqttServerFactory mqttServerFactory,
CustomMqttFactory mqttFactory,
MqttWebSocketServerAdapter webSocketServerAdapter,
MqttNetLoggerWrapper mqttNetLogger,
MqttClientConnectedHandler mqttClientConnectedHandler,
MqttClientDisconnectedHandler mqttClientDisconnectedHandler,
MqttClientSubscribedTopicHandler mqttClientSubscribedTopicHandler,
MqttClientUnsubscribedTopicHandler mqttClientUnsubscribedTopicHandler,
MqttConnectionValidator mqttConnectionValidator,
MqttSubscriptionInterceptor mqttSubscriptionInterceptor,
MqttApplicationMessageInterceptor mqttApplicationMessageInterceptor,
PythonScriptHostService pythonScriptHostService,
ILogger<MqttServerService> logger)
{
_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));
@@ -42,11 +52,11 @@ namespace MQTTnet.Server.Mqtt
var adapters = new List<IMqttServerAdapter>
{
new MqttTcpServerAdapter(new MqttNetChildLoggerWrapper(null, mqttNetLogger)),
new MqttTcpServerAdapter(mqttFactory.Logger.CreateChildLogger(nameof(MqttTcpServerAdapter))),
webSocketServerAdapter
};
_mqttServer = mqttServerFactory.CreateMqttServer(adapters);
_mqttServer = mqttFactory.CreateMqttServer(adapters);
}
public void Configure()
@@ -61,6 +71,11 @@ namespace MQTTnet.Server.Mqtt
.WithSubscriptionInterceptor(_mqttSubscriptionInterceptor)
.Build();
_mqttServer.ClientConnectedHandler = _mqttClientConnectedHandler;
_mqttServer.ClientDisconnectedHandler = _mqttClientDisconnectedHandler;
_mqttServer.ClientSubscribedTopicHandler = _mqttClientSubscribedTopicHandler;
_mqttServer.ClientUnsubscribedTopicHandler = _mqttClientUnsubscribedTopicHandler;
_mqttServer.StartAsync(options).GetAwaiter().GetResult();
_logger.LogInformation("MQTT server started.");
@@ -68,34 +83,48 @@ namespace MQTTnet.Server.Mqtt
private void Publish(PythonDictionary parameters)
{
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);
var binaryPayload = new byte[0];
if (payload is string stringPayload)
try
{
binaryPayload = Encoding.UTF8.GetBytes(stringPayload);
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();
}
else if (payload is ByteArray byteArray)
catch (Exception exception)
{
binaryPayload = byteArray.ToArray();
_logger.LogError(exception, "Error while publishing application message from server.");
}
else if (payload is IEnumerable<int> intArray)
{
binaryPayload = intArray.Select(Convert.ToByte).ToArray();
}
applicationMessageBuilder = applicationMessageBuilder
.WithPayload(binaryPayload);
var applicationMessage = applicationMessageBuilder.Build();
_mqttServer.PublishAsync(applicationMessage).GetAwaiter().GetResult();
_logger.LogInformation($"Published topic '{applicationMessage.Topic}' from server.");
}
}
}
@@ -9,7 +9,7 @@ namespace MQTTnet.Server.Mqtt
public class MqttSubscriptionInterceptor : IMqttServerSubscriptionInterceptor
{
private readonly PythonScriptHostService _pythonScriptHostService;
private readonly ILogger<MqttSubscriptionInterceptor> _logger;
private readonly ILogger _logger;
public MqttSubscriptionInterceptor(PythonScriptHostService pythonScriptHostService, ILogger<MqttSubscriptionInterceptor> logger)
{