diff --git a/ServiceHub/Modules/ServiceHub.Modules.MQTT/MqttModule.cs b/ServiceHub/Modules/ServiceHub.Modules.MQTT/MqttModule.cs new file mode 100644 index 0000000..aa2ab84 --- /dev/null +++ b/ServiceHub/Modules/ServiceHub.Modules.MQTT/MqttModule.cs @@ -0,0 +1,47 @@ +using MQTTnet.Diagnostics.Logger; +using MQTTnet.Server; +using ServiceHub.Contracts.Enums; +using ServiceHub.Contracts.Interfaces; + +namespace ServiceHub.Modules.MQTT +{ + public class MqttModule : IServiceModule + { + private MqttServer? _server = null; + private ILogContext? _log = null; + + public string Name => "MqttModule"; + + public void Initialize(ILogContext log, IServiceContext config) + { + _log = log; + _log.Info($"{Name} initialized."); + } + + public Task StartAsync(CancellationToken token) + { + Stop(); + + var logger = new MqttNetEventLogger(); + + logger.LogMessagePublished += (o, e) => + { + switch (e.LogMessage.Level) + { + case MqttNetLogLevel.Error: _log?.Error($"{Name} {e.LogMessage.Message}"); break; + case MqttNetLogLevel.Warning: _log?.Warning($"{Name} {e.LogMessage.Message}"); break; + case MqttNetLogLevel.Info: + case MqttNetLogLevel.Verbose: _log?.Info($"{Name} {e.LogMessage.Message}"); break; + } + }; + + _server = new MqttServerFactory(logger).CreateMqttServer(new MqttServerOptions()); + + return _server.StartAsync(); + } + + public ServiceState State() => (_server?.IsStarted ?? false ) ? ServiceState.Running : ServiceState.Stoped; + + public void Stop() => _server?.StopAsync().Wait(); + } +} diff --git a/ServiceHub/Modules/ServiceHub.Modules.MQTT/ServiceHub.Modules.MQTT.csproj b/ServiceHub/Modules/ServiceHub.Modules.MQTT/ServiceHub.Modules.MQTT.csproj new file mode 100644 index 0000000..c10761d --- /dev/null +++ b/ServiceHub/Modules/ServiceHub.Modules.MQTT/ServiceHub.Modules.MQTT.csproj @@ -0,0 +1,17 @@ + + + + net10.0 + enable + enable + + + + + + + + + + + diff --git a/ServiceHub/Modules/ServiceHub.Modules.StaticWeb/StaticWebModule.cs b/ServiceHub/Modules/ServiceHub.Modules.StaticWeb/StaticWebModule.cs index 122808e..5e3c2fd 100644 --- a/ServiceHub/Modules/ServiceHub.Modules.StaticWeb/StaticWebModule.cs +++ b/ServiceHub/Modules/ServiceHub.Modules.StaticWeb/StaticWebModule.cs @@ -14,17 +14,17 @@ public class StaticWebModule : IServiceModule private WebServer? _server; private CancellationToken _token; private ILogContext? _logContext; - private IConfigContext? _configContext; + private IServiceContext? _configContext; public string Name => "StaticWebModule"; - public void Initialize(ILogContext log, IConfigContext config) + public void Initialize(ILogContext log, IServiceContext config) { _logContext = log; _configContext = config; - var port = _configContext.Get("port") ?? "8080"; - var root = _configContext.Get("directory") ?? "wwwroot"; + var port = _configContext.Get("parameters:port") ?? "8080"; + var root = _configContext.Get("parameters:directory") ?? "wwwroot"; _port = int.Parse(port); _directory = root; @@ -34,6 +34,8 @@ public void Initialize(ILogContext log, IConfigContext config) public async Task StartAsync(CancellationToken token) { + Stop(); + _token = token; var fileProvider = new PhysicalFileProvider(_directory); diff --git a/ServiceHub/ServiceHub.Contracts/Interfaces/IConfigContext.cs b/ServiceHub/ServiceHub.Contracts/Interfaces/IConfigContext.cs deleted file mode 100644 index f9b6f38..0000000 --- a/ServiceHub/ServiceHub.Contracts/Interfaces/IConfigContext.cs +++ /dev/null @@ -1,13 +0,0 @@ -namespace ServiceHub.Contracts.Interfaces -{ - public interface IConfigContext - { - string? Get(string path); - - IConfigContext? GetConfig(string path); - - string? Value { get; } - - IConfigContext[] Items { get; } - } -} diff --git a/ServiceHub/ServiceHub.Contracts/Interfaces/IServiceContext.cs b/ServiceHub/ServiceHub.Contracts/Interfaces/IServiceContext.cs new file mode 100644 index 0000000..a15ce72 --- /dev/null +++ b/ServiceHub/ServiceHub.Contracts/Interfaces/IServiceContext.cs @@ -0,0 +1,22 @@ +using ServiceHub.Contracts.Classes; +using System.Text.Json; + +namespace ServiceHub.Contracts.Interfaces +{ + public interface IServiceContext + { + string? Value { get; } + + void SetNode(string path); + + void ResetNode(); + + IServiceContext[] Items { get; } + + void LoadJson(string json); + + string? Get(string path); + + IServiceContext? GetConfig(string path); + } +} diff --git a/ServiceHub/ServiceHub.Contracts/Interfaces/IServiceModule.cs b/ServiceHub/ServiceHub.Contracts/Interfaces/IServiceModule.cs index 3320819..f9acaa9 100644 --- a/ServiceHub/ServiceHub.Contracts/Interfaces/IServiceModule.cs +++ b/ServiceHub/ServiceHub.Contracts/Interfaces/IServiceModule.cs @@ -5,7 +5,7 @@ namespace ServiceHub.Contracts.Interfaces public interface IServiceModule { string Name { get; } - void Initialize(ILogContext log, IConfigContext config); + void Initialize(ILogContext log, IServiceContext config); Task StartAsync(CancellationToken token); void Stop(); ServiceState State(); diff --git a/ServiceHub/ServiceHub.Core/Classes/SimpleContext.cs b/ServiceHub/ServiceHub.Core/Classes/SimpleContext.cs index e40492f..c689d12 100644 --- a/ServiceHub/ServiceHub.Core/Classes/SimpleContext.cs +++ b/ServiceHub/ServiceHub.Core/Classes/SimpleContext.cs @@ -1,23 +1,37 @@ using ServiceHub.Contracts.Interfaces; using System.Text.Json; +using System.Xml.Linq; namespace ServiceHub.Core.Classes { - public class SimpleContext : IConfigContext + public class SimpleContext : IServiceContext { - internal ConfigNode Root { get; } = new(); + private ConfigNode Root { get; } = new (); + + private ConfigNode? Node { get; set; } = null; public string? Value { get { - if (Root == null) - return null; - return Root.Value; + if (Node == null) + return Root.Value; + return Node.Value; } } - public IConfigContext[] Items { get => Root.Items.Select(x => new SimpleContext(x)).ToArray(); } + public void SetNode(string path) + { + if (Root == null) + return; + Node = Traverse(path); + } + + public void ResetNode() { + Node = null; + } + + public IServiceContext[] Items { get => (Node ?? Root).Items.Select(x => new SimpleContext(x)).ToArray(); } public SimpleContext() { } internal SimpleContext(ConfigNode root) { Root = root; } @@ -59,12 +73,16 @@ private void LoadElement(ConfigNode node, JsonElement element) public string? Get(string path) => Traverse(path)?.Value; - public IConfigContext? GetConfig(string path) => Traverse(path); + public IServiceContext? GetConfig(string path) + { + var data = Traverse(path); + return data == null ? null : (IServiceContext) new SimpleContext(data); + } - private IConfigContext? Traverse(string path) + private ConfigNode? Traverse(string path) { var parts = path.Split(':', StringSplitOptions.RemoveEmptyEntries); - ConfigNode current = Root; + ConfigNode? current = Node ?? Root; foreach (var part in parts) { @@ -78,7 +96,7 @@ private void LoadElement(ConfigNode node, JsonElement element) return null; } - return new SimpleContext(current); + return current; } } } diff --git a/ServiceHub/ServiceHub.Core/Model/ServiceInstance.cs b/ServiceHub/ServiceHub.Core/Model/ServiceInstance.cs index 3a68b04..a93c73c 100644 --- a/ServiceHub/ServiceHub.Core/Model/ServiceInstance.cs +++ b/ServiceHub/ServiceHub.Core/Model/ServiceInstance.cs @@ -7,7 +7,7 @@ internal sealed class ServiceInstance { private string _serviceName; private IServiceModule? _serviceModule { get; set; } - private IConfigContext _config { get; set; } + private IServiceContext _config { get; set; } private ILogContext _log { get; set; } public ServiceState State => _serviceModule?.State() ?? ServiceState.Error; @@ -17,7 +17,7 @@ internal sealed class ServiceInstance public void Stop(CancellationToken ct) => _serviceModule?.Stop(); - public ServiceInstance(ILogContext log, IConfigContext config, Type type) + public ServiceInstance(ILogContext log, IServiceContext config, Type type) { _config = config; _log = log; @@ -26,7 +26,7 @@ public ServiceInstance(ILogContext log, IConfigContext config, Type type) if (string.IsNullOrEmpty(_serviceName)) throw new ArgumentNullException("name"); - IConfigContext? contextValue = config.GetConfig("parameters"); + IServiceContext? contextValue = config.GetConfig("parameters"); if (contextValue == null) throw new ArgumentNullException("parameters"); @@ -35,8 +35,8 @@ public ServiceInstance(ILogContext log, IConfigContext config, Type type) if (!typeof(IServiceModule).IsAssignableFrom(type) || type.IsAbstract) throw new Exception($"The {type.Name} Module is not valid" ); - _serviceModule = (IServiceModule)Activator.CreateInstance(type); - _serviceModule?.Initialize(log, contextValue); + _serviceModule = (IServiceModule?)Activator.CreateInstance(type); + _serviceModule?.Initialize(log, config); } catch (Exception ex) { diff --git a/ServiceHub/ServiceHub.Core/ServiceHub.cs b/ServiceHub/ServiceHub.Core/ServiceHub.cs index 43beffe..d43b0fe 100644 --- a/ServiceHub/ServiceHub.Core/ServiceHub.cs +++ b/ServiceHub/ServiceHub.Core/ServiceHub.cs @@ -28,7 +28,7 @@ private ServiceHub() { } #region Public Methods - public bool InitModule(ILogContext log, IConfigContext config) + public bool InitModule(ILogContext log, IServiceContext config) { var typeService = config.Get("type") ?? string.Empty; @@ -87,7 +87,7 @@ public void LoadModules(ILogContext log, string folderPath) if (!typeof(IServiceModule).IsAssignableFrom(type) || type.IsAbstract) continue; - var name = ((IServiceModule)Activator.CreateInstance(type))?.Name; + var name = ((IServiceModule?)Activator.CreateInstance(type))?.Name; if (!string.IsNullOrWhiteSpace(name)) { _availableModules.Add(name ?? string.Empty, type); diff --git a/ServiceHub/ServiceHub.Host/Program.cs b/ServiceHub/ServiceHub.Host/Program.cs index 8fb3a5d..7707981 100644 --- a/ServiceHub/ServiceHub.Host/Program.cs +++ b/ServiceHub/ServiceHub.Host/Program.cs @@ -18,6 +18,11 @@ static void Main(string[] args) ""port"": ""8080"", ""root"": ""wwwroot"" } + }, + { + ""name"": ""MqttIot"", + ""type"": ""MqttModule"", + ""parameters"": { } } ] }"); @@ -28,12 +33,19 @@ static void Main(string[] args) throw new Exception("Json Config is not valid"); log.Info("ServiceHub running..."); - foreach (var localContext in context.GetConfig("services").Items) - { - Core.ServiceHub.Instance.InitModule(log, localContext); - Core.ServiceHub.Instance.Start(localContext.Get("name")); + + var servicesCount = context.GetConfig("services")?.Items.Count() ?? 0; + for (int i = 0; i +