@@ -0,0 +1,24 @@ | |||||
using System; | |||||
using System.IO; | |||||
namespace MQTTnet.Server.Configuration | |||||
{ | |||||
public static class PathHelper | |||||
{ | |||||
public static string ExpandPath(string path) | |||||
{ | |||||
if (path == null) | |||||
{ | |||||
return null; | |||||
} | |||||
var uri = new Uri(path, UriKind.RelativeOrAbsolute); | |||||
if (!uri.IsAbsoluteUri) | |||||
{ | |||||
return Path.Combine(AppDomain.CurrentDomain.BaseDirectory, path); | |||||
} | |||||
return path; | |||||
} | |||||
} | |||||
} |
@@ -4,6 +4,8 @@ namespace MQTTnet.Server.Configuration | |||||
{ | { | ||||
public class ScriptingSettingsModel | public class ScriptingSettingsModel | ||||
{ | { | ||||
public string ScriptsPath { get; set; } | |||||
public List<string> IncludePaths { get; set; } | public List<string> IncludePaths { get; set; } | ||||
} | } | ||||
} | } |
@@ -7,12 +7,12 @@ using MQTTnet.Server.Scripting; | |||||
namespace MQTTnet.Server.Mqtt | namespace MQTTnet.Server.Mqtt | ||||
{ | { | ||||
public class MqttConnectionValidator : IMqttServerConnectionValidator | |||||
public class MqttServerConnectionValidator : IMqttServerConnectionValidator | |||||
{ | { | ||||
private readonly PythonScriptHostService _pythonScriptHostService; | private readonly PythonScriptHostService _pythonScriptHostService; | ||||
private readonly ILogger _logger; | private readonly ILogger _logger; | ||||
public MqttConnectionValidator(PythonScriptHostService pythonScriptHostService, ILogger<MqttConnectionValidator> logger) | |||||
public MqttServerConnectionValidator(PythonScriptHostService pythonScriptHostService, ILogger<MqttServerConnectionValidator> logger) | |||||
{ | { | ||||
_pythonScriptHostService = pythonScriptHostService ?? throw new ArgumentNullException(nameof(pythonScriptHostService)); | _pythonScriptHostService = pythonScriptHostService ?? throw new ArgumentNullException(nameof(pythonScriptHostService)); | ||||
_logger = logger ?? throw new ArgumentNullException(nameof(logger)); | _logger = logger ?? throw new ArgumentNullException(nameof(logger)); | ||||
@@ -24,18 +24,22 @@ namespace MQTTnet.Server.Mqtt | |||||
{ | { | ||||
var pythonContext = new PythonDictionary | var pythonContext = new PythonDictionary | ||||
{ | { | ||||
{ "client_id", context.ClientId }, | |||||
{ "endpoint", context.Endpoint }, | { "endpoint", context.Endpoint }, | ||||
{ "is_secure_connection", context.IsSecureConnection }, | { "is_secure_connection", context.IsSecureConnection }, | ||||
{ "client_id", context.ClientId }, | |||||
{ "username", context.Username }, | { "username", context.Username }, | ||||
{ "password", context.Password }, | { "password", context.Password }, | ||||
{ "raw_password", context.RawPassword }, | |||||
{ "result", PythonConvert.Pythonfy(context.ReturnCode) } | |||||
{ "raw_password", new Bytes(context.RawPassword) }, | |||||
{ "clean_session", context.CleanSession}, | |||||
{ "authentication_method", context.AuthenticationMethod}, | |||||
{ "authentication_data", new Bytes(context.AuthenticationData)}, | |||||
{ "result", PythonConvert.Pythonfy(context.ReasonCode) } | |||||
}; | }; | ||||
_pythonScriptHostService.InvokeOptionalFunction("on_validate_client_connection", pythonContext); | _pythonScriptHostService.InvokeOptionalFunction("on_validate_client_connection", pythonContext); | ||||
context.ReturnCode = PythonConvert.ParseEnum<MqttConnectReturnCode>((string)pythonContext["result"]); | |||||
context.ReasonCode = PythonConvert.ParseEnum<MqttConnectReasonCode>((string)pythonContext["result"]); | |||||
} | } | ||||
catch (Exception exception) | catch (Exception exception) | ||||
{ | { |
@@ -30,7 +30,7 @@ namespace MQTTnet.Server.Mqtt | |||||
private readonly MqttClientDisconnectedHandler _mqttClientDisconnectedHandler; | private readonly MqttClientDisconnectedHandler _mqttClientDisconnectedHandler; | ||||
private readonly MqttClientSubscribedTopicHandler _mqttClientSubscribedTopicHandler; | private readonly MqttClientSubscribedTopicHandler _mqttClientSubscribedTopicHandler; | ||||
private readonly MqttClientUnsubscribedTopicHandler _mqttClientUnsubscribedTopicHandler; | private readonly MqttClientUnsubscribedTopicHandler _mqttClientUnsubscribedTopicHandler; | ||||
private readonly MqttConnectionValidator _mqttConnectionValidator; | |||||
private readonly MqttServerConnectionValidator _mqttConnectionValidator; | |||||
private readonly IMqttServer _mqttServer; | private readonly IMqttServer _mqttServer; | ||||
private readonly MqttSubscriptionInterceptor _mqttSubscriptionInterceptor; | private readonly MqttSubscriptionInterceptor _mqttSubscriptionInterceptor; | ||||
private readonly PythonScriptHostService _pythonScriptHostService; | private readonly PythonScriptHostService _pythonScriptHostService; | ||||
@@ -43,7 +43,7 @@ namespace MQTTnet.Server.Mqtt | |||||
MqttClientDisconnectedHandler mqttClientDisconnectedHandler, | MqttClientDisconnectedHandler mqttClientDisconnectedHandler, | ||||
MqttClientSubscribedTopicHandler mqttClientSubscribedTopicHandler, | MqttClientSubscribedTopicHandler mqttClientSubscribedTopicHandler, | ||||
MqttClientUnsubscribedTopicHandler mqttClientUnsubscribedTopicHandler, | MqttClientUnsubscribedTopicHandler mqttClientUnsubscribedTopicHandler, | ||||
MqttConnectionValidator mqttConnectionValidator, | |||||
MqttServerConnectionValidator mqttConnectionValidator, | |||||
MqttSubscriptionInterceptor mqttSubscriptionInterceptor, | MqttSubscriptionInterceptor mqttSubscriptionInterceptor, | ||||
MqttApplicationMessageInterceptor mqttApplicationMessageInterceptor, | MqttApplicationMessageInterceptor mqttApplicationMessageInterceptor, | ||||
MqttServerStorage mqttServerStorage, | MqttServerStorage mqttServerStorage, | ||||
@@ -35,7 +35,7 @@ namespace MQTTnet.Server.Mqtt | |||||
return; | return; | ||||
} | } | ||||
_path = ExpandPath(); | |||||
_path = PathHelper.ExpandPath(_mqttSettings.RetainedApplicationMessages.Path); | |||||
// The retained application messages are stored in a separate thread. | // The retained application messages are stored in a separate thread. | ||||
// This is mandatory because writing them to a slow storage (like RaspberryPi SD card) | // This is mandatory because writing them to a slow storage (like RaspberryPi SD card) | ||||
@@ -115,18 +115,5 @@ namespace MQTTnet.Server.Mqtt | |||||
return null; | return null; | ||||
} | } | ||||
} | } | ||||
private string ExpandPath() | |||||
{ | |||||
var path = _mqttSettings.RetainedApplicationMessages.Path; | |||||
var uri = new Uri(path, UriKind.RelativeOrAbsolute); | |||||
if (!uri.IsAbsoluteUri) | |||||
{ | |||||
path = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, path); | |||||
} | |||||
return path; | |||||
} | |||||
} | } | ||||
} | } |
@@ -17,7 +17,7 @@ namespace MQTTnet.Server.Scripting | |||||
{ | { | ||||
private readonly IDictionary<string, object> _proxyObjects = new ExpandoObject(); | private readonly IDictionary<string, object> _proxyObjects = new ExpandoObject(); | ||||
private readonly List<PythonScriptInstance> _scriptInstances = new List<PythonScriptInstance>(); | private readonly List<PythonScriptInstance> _scriptInstances = new List<PythonScriptInstance>(); | ||||
private readonly string _scriptsPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Scripts"); | |||||
private readonly string _scriptsPath; | |||||
private readonly ScriptingSettingsModel _scriptingSettings; | private readonly ScriptingSettingsModel _scriptingSettings; | ||||
private readonly ILogger<PythonScriptHostService> _logger; | private readonly ILogger<PythonScriptHostService> _logger; | ||||
private readonly ScriptEngine _scriptEngine; | private readonly ScriptEngine _scriptEngine; | ||||
@@ -29,6 +29,8 @@ namespace MQTTnet.Server.Scripting | |||||
_scriptEngine = IronPython.Hosting.Python.CreateEngine(); | _scriptEngine = IronPython.Hosting.Python.CreateEngine(); | ||||
_scriptEngine.Runtime.IO.SetOutput(pythonIOStream, Encoding.UTF8); | _scriptEngine.Runtime.IO.SetOutput(pythonIOStream, Encoding.UTF8); | ||||
_scriptsPath = PathHelper.ExpandPath(scriptingSettings.ScriptsPath); | |||||
} | } | ||||
public void Configure() | public void Configure() | ||||
@@ -186,13 +188,7 @@ namespace MQTTnet.Server.Scripting | |||||
foreach (var path in _scriptingSettings.IncludePaths) | foreach (var path in _scriptingSettings.IncludePaths) | ||||
{ | { | ||||
var effectivePath = path; | |||||
var uri = new Uri(effectivePath, UriKind.RelativeOrAbsolute); | |||||
if (!uri.IsAbsoluteUri) | |||||
{ | |||||
effectivePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, effectivePath); | |||||
} | |||||
var effectivePath = PathHelper.ExpandPath(path); | |||||
if (Directory.Exists(effectivePath)) | if (Directory.Exists(effectivePath)) | ||||
{ | { | ||||
@@ -25,20 +25,45 @@ def on_validate_client_connection(context): | |||||
print(context) | print(context) | ||||
# Access some custom data here which was inserted upon connect and may use it for validation. | |||||
mqtt_net_server.write_shared_data(context["client_id"], {"custom_value_1": 1, "custom_value_2": True}) | mqtt_net_server.write_shared_data(context["client_id"], {"custom_value_1": 1, "custom_value_2": True}) | ||||
return | return | ||||
# Supported results: | |||||
# * success | |||||
# * unspecified_error | |||||
# * malformed_packet | |||||
# * protocol_error | |||||
# * implementation_specific_error | |||||
# * unsupported_protocol_version | |||||
# * client_identifier_not_valid | |||||
# * bad_user_name_or_password | |||||
# * not_authorized | |||||
# * server_unavailable | |||||
# * server_busy | |||||
# * banned | |||||
# * bad_authentication_method | |||||
# * topic_name_invalid | |||||
# * packet_too_large | |||||
# * quota_exceeded | |||||
# * payload_format_invalid | |||||
# * retain_not_supported | |||||
# * qos_not_supported | |||||
# * use_another_server | |||||
# * server_moved | |||||
# * connection_rate_exceeded | |||||
if context["client_id"] != "test_client": | if context["client_id"] != "test_client": | ||||
context["result"] = "connection_refused_not_authorized" | |||||
context["result"] = "bad_user_name_or_password" | |||||
return | return | ||||
if context["username"] != "bud spencer": | if context["username"] != "bud spencer": | ||||
context["result"] = "connection_refused_not_authorized" | |||||
context["result"] = "bad_user_name_or_password" | |||||
return | return | ||||
if context["password_string"] != "secret": | if context["password_string"] != "secret": | ||||
context["result"] = "connection_refused_not_authorized" | |||||
context["result"] = "bad_user_name_or_password" | |||||
print(context) | print(context) | ||||
@@ -3,7 +3,6 @@ using System.Collections.Generic; | |||||
using System.Linq; | using System.Linq; | ||||
using System.Net; | using System.Net; | ||||
using Microsoft.AspNetCore.Authentication; | using Microsoft.AspNetCore.Authentication; | ||||
using Microsoft.AspNetCore.Authentication.Cookies; | |||||
using Microsoft.AspNetCore.Builder; | using Microsoft.AspNetCore.Builder; | ||||
using Microsoft.AspNetCore.Hosting; | using Microsoft.AspNetCore.Hosting; | ||||
using Microsoft.AspNetCore.Mvc; | using Microsoft.AspNetCore.Mvc; | ||||
@@ -17,7 +16,6 @@ using MQTTnet.Server.Logging; | |||||
using MQTTnet.Server.Mqtt; | using MQTTnet.Server.Mqtt; | ||||
using MQTTnet.Server.Scripting; | using MQTTnet.Server.Scripting; | ||||
using MQTTnet.Server.Scripting.DataSharing; | using MQTTnet.Server.Scripting.DataSharing; | ||||
using Swashbuckle.AspNetCore.SwaggerGen; | |||||
using Swashbuckle.AspNetCore.SwaggerUI; | using Swashbuckle.AspNetCore.SwaggerUI; | ||||
namespace MQTTnet.Server.Web | namespace MQTTnet.Server.Web | ||||
@@ -111,7 +109,7 @@ namespace MQTTnet.Server.Web | |||||
services.AddSingleton<MqttClientDisconnectedHandler>(); | services.AddSingleton<MqttClientDisconnectedHandler>(); | ||||
services.AddSingleton<MqttClientSubscribedTopicHandler>(); | services.AddSingleton<MqttClientSubscribedTopicHandler>(); | ||||
services.AddSingleton<MqttClientUnsubscribedTopicHandler>(); | services.AddSingleton<MqttClientUnsubscribedTopicHandler>(); | ||||
services.AddSingleton<MqttConnectionValidator>(); | |||||
services.AddSingleton<MqttServerConnectionValidator>(); | |||||
services.AddSingleton<MqttSubscriptionInterceptor>(); | services.AddSingleton<MqttSubscriptionInterceptor>(); | ||||
services.AddSingleton<MqttApplicationMessageInterceptor>(); | services.AddSingleton<MqttApplicationMessageInterceptor>(); | ||||
@@ -48,6 +48,7 @@ | |||||
"EnableDebugLogging": false | "EnableDebugLogging": false | ||||
}, | }, | ||||
"Scripting": { | "Scripting": { | ||||
"ScriptsPath": "Scripts", | |||||
"IncludePaths": [ | "IncludePaths": [ | ||||
"Lib", | "Lib", | ||||
"/usr/lib/python2.7", | "/usr/lib/python2.7", | ||||