Skip to content

Commit

Permalink
Merge branch 'feature/servers'
Browse files Browse the repository at this point in the history
  • Loading branch information
diogotr7 committed Mar 3, 2024
2 parents b9e2ed0 + 951762c commit 04d946b
Show file tree
Hide file tree
Showing 22 changed files with 289 additions and 208 deletions.
6 changes: 3 additions & 3 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,16 +10,16 @@ jobs:
- name: Setup .NET
uses: actions/setup-dotnet@v1
with:
dotnet-version: '7.0.x'
dotnet-version: '8.0.x'

- name: Clone Plugins
uses: actions/checkout@v2

- name: Build Plugin
run: dotnet publish -c Release src/Artemis.Plugins.Mqtt.sln
run: dotnet publish -c Release src

- name: Upload
uses: actions/upload-artifact@v2
with:
name: Artemis.Plugins.Mqtt
path: src/Artemis.Plugins.Mqtt/bin/x64/Release/net7.0/publish
path: src/Artemis.Plugins.Mqtt/bin/x64/Release/net8.0/publish
5 changes: 5 additions & 0 deletions src/Artemis.Plugins.Mqtt.sln
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,11 @@
Microsoft Visual Studio Solution File, Format Version 12.00
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Artemis.Plugins.Mqtt", "Artemis.Plugins.Mqtt\Artemis.Plugins.Mqtt.csproj", "{C49EFF75-D1D3-486D-BA37-DF65481EA6EB}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{BC333B86-D4D6-4D67-B713-293CAAAD0A1F}"
ProjectSection(SolutionItems) = preProject
..\.github\workflows\build.yml = ..\.github\workflows\build.yml
EndProjectSection
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand Down
3 changes: 2 additions & 1 deletion src/Artemis.Plugins.Mqtt/Artemis.Plugins.Mqtt.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,11 @@
<TargetFramework>net8.0</TargetFramework>
<Platforms>x64</Platforms>
<EnableDynamicLoading>true</EnableDynamicLoading>
<Nullable>enable</Nullable>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="ArtemisRGB.UI.Shared" IncludeAssets="compile;build;buildTransitive" Version="1.2024.225.6" />
<PackageReference Include="ArtemisRGB.UI.Shared" IncludeAssets="compile;build;buildTransitive" Version="1.2024.302.1" />
<PackageReference Include="MQTTnet" Version="4.3.3.952" />
<PackageReference Include="MQTTnet.Extensions.ManagedClient" Version="4.3.3.952" />
</ItemGroup>
Expand Down
2 changes: 2 additions & 0 deletions src/Artemis.Plugins.Mqtt/DataModels/MqttDataModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,6 @@ public class MqttDataModel : DataModel
public StatusesDataModel Statuses { get; } = new();

public NodeDataModel Root { get; } = new(new());

public MqttServersDataModel Servers { get; } = new();
}
35 changes: 35 additions & 0 deletions src/Artemis.Plugins.Mqtt/DataModels/MqttNodeDataModel.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using Artemis.Core.Modules;
using Swan;

namespace Artemis.Plugins.Mqtt.DataModels;

public class MqttNodeDataModel : DataModel
{
public string Data { get; set; }

public MqttNodeDataModel()
{
Data = "";
}

public void PropagateValue(string[] topics, object data)
{
if (topics.Length == 0)
{
Data = data.ToString() ?? "";
return;
}

var key = topics[0];
var remainingPartialTopics = topics[1..];
if (!TryGetDynamicChild<MqttNodeDataModel>(key, out var child))
child = AddDynamicChild<MqttNodeDataModel>(key, new());

child.Value.PropagateValue(remainingPartialTopics, data);
}
}
34 changes: 34 additions & 0 deletions src/Artemis.Plugins.Mqtt/DataModels/MqttServersDataModel.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
using System;
using System.Collections.Generic;
using Artemis.Core.Modules;

namespace Artemis.Plugins.Mqtt.DataModels;

public class MqttServersDataModel : DataModel
{
private readonly Dictionary<Guid, DynamicChild<MqttNodeDataModel>> _servers = new();

internal void CreateServers(IEnumerable<MqttConnectionSettings> servers)
{
ClearDynamicChildren();
_servers.Clear();

foreach (var server in servers)
{
var id = server.ServerId.ToString();
_servers.Add(
server.ServerId,
AddDynamicChild(id, new MqttNodeDataModel(), server.DisplayName)
);
}
}

public void PropagateValue(Guid sourceServer, string topic, object data)
{
if (!_servers.TryGetValue(sourceServer, out var server))
return;

var parts = topic.Split('/');
server.Value.PropagateValue(parts, data);
}
}
6 changes: 4 additions & 2 deletions src/Artemis.Plugins.Mqtt/DataModels/NodeDataModel.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
using System;
using System.Collections.Concurrent;
using Artemis.Core.Modules;
using Artemis.Plugins.Mqtt.DataModels.Dynamic;

namespace Artemis.Plugins.Mqtt.DataModels;

Expand All @@ -18,6 +17,9 @@ internal void CreateStructure(StructureDefinitionNode dataModelStructure)
ClearDynamicChildren();
_allDynamicChildren.Clear();

if (dataModelStructure.Children == null)
return;

foreach (var childDefinition in dataModelStructure.Children)
{
var id = GetNodeId(childDefinition.Server ?? Guid.NewGuid(), childDefinition.Topic);
Expand Down Expand Up @@ -67,7 +69,7 @@ public void PropagateValue(Guid sourceServer, string topic, object data)
boolChild.Value = string.Compare(data.ToString(), "true", StringComparison.OrdinalIgnoreCase) == 0;
return;
case DynamicChild<string> stringChild:
stringChild.Value = data.ToString();
stringChild.Value = data.ToString()!;
return;
}
}
Expand Down
33 changes: 25 additions & 8 deletions src/Artemis.Plugins.Mqtt/DataModels/StructureDefinitionNode.cs
Original file line number Diff line number Diff line change
@@ -1,13 +1,23 @@
using System;
using System.Collections.Generic;
using System.Text.Json.Serialization;

namespace Artemis.Plugins.Mqtt.DataModels.Dynamic;
namespace Artemis.Plugins.Mqtt.DataModels;

/// <summary>
/// Class that defines a single node of the DataModel structure.
/// </summary>
public class StructureDefinitionNode
{
public StructureDefinitionNode(string label, Guid? server, string topic, Type? type, bool isGroup)
{
Label = label;
Server = server;
Topic = topic;
AssemblyQualifiedTypeName = type?.AssemblyQualifiedName ?? "";
Children = isGroup ? new List<StructureDefinitionNode>() : null;
}

/// <summary>
/// The display name this node will appear as in the Artemis Data Model.
/// </summary>
Expand All @@ -22,23 +32,30 @@ public class StructureDefinitionNode
/// The topic that can be used to set the value of this node.
/// </summary>
public string Topic { get; set; }

/// <summary>
/// The type of value stored in this node.
/// </summary>
public string AssemblyQualifiedTypeName { get; set; }

/// <summary>
/// The type of value stored in this node.
/// </summary>
public Type Type { get; set; }
[JsonIgnore]
public Type? Type => Type.GetType(AssemblyQualifiedTypeName);

/// <summary>
/// Whether this node is a group or not.
/// </summary>
public bool IsGroup => Children != null;

/// <summary>
/// Any children this node has.
/// </summary>
public List<StructureDefinitionNode> Children { get; set; }
public List<StructureDefinitionNode>? Children { get; set; }

/// <summary>
/// Returns a default root <see cref="StructureDefinitionNode" />.
/// </summary>
public static StructureDefinitionNode RootDefault => new()
{
Label = "Root",
Children = new List<StructureDefinitionNode>()
};
public static StructureDefinitionNode RootDefault => new("Root", null, "", typeof(object), true);
}
34 changes: 18 additions & 16 deletions src/Artemis.Plugins.Mqtt/MqttConnector.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
using System;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
Expand All @@ -13,41 +13,42 @@ namespace Artemis.Plugins.Mqtt;
/// </summary>
public sealed class MqttConnector : IDisposable
{
private static readonly MqttFactory clientFactory = new();
private readonly IManagedMqttClient client;
private static readonly MqttFactory ClientFactory = new();
private readonly IManagedMqttClient _client;

public MqttConnector()
{
client = clientFactory.CreateManagedMqttClient();
client.ApplicationMessageReceivedAsync += OnClientMessageReceived;
client.ConnectedAsync += OnClientConnected;
client.DisconnectedAsync += OnClientDisconnected;
_client = ClientFactory.CreateManagedMqttClient();
_client.ApplicationMessageReceivedAsync += OnClientMessageReceived;
_client.ConnectedAsync += OnClientConnected;
_client.DisconnectedAsync += OnClientDisconnected;
}

/// <summary>
/// The ID of the server this connector is connected to.
/// <para />
/// Based on the 'ServerId' property from the settings object passed to <see cref="Start(MqttConnectionSettings)" />.
/// Based on the 'ServerId' property from the settings object passed to <see cref="Start(MqttConnectionSettings,IEnumerable{string})" />.
/// </summary>
public Guid ServerId { get; private set; }

/// <summary>
/// Whether or not this connector is currently connected to a server.
/// </summary>
// ReSharper disable once UnusedAutoPropertyAccessor.Global
public bool IsConnected { get; private set; }

public void Dispose()
{
client.Dispose();
_client.Dispose();
}

/// <summary>
/// Event that fires when this connector receives a message from the server it is connected to.
/// </summary>
public event EventHandler<MqttApplicationMessageReceivedEventArgs> MessageReceived;
public event EventHandler<MqttApplicationMessageReceivedEventArgs>? MessageReceived;

public event EventHandler<MqttClientConnectedEventArgs> Connected;
public event EventHandler<MqttClientDisconnectedEventArgs> Disconnected;
public event EventHandler<MqttClientConnectedEventArgs>? Connected;
public event EventHandler<MqttClientDisconnectedEventArgs>? Disconnected;

/// <summary>
/// Sets up and starts listening with the MQTT client behind this connector.
Expand Down Expand Up @@ -75,19 +76,20 @@ public async Task Start(MqttConnectionSettings settings, IEnumerable<string> top
.WithClientOptions(clientOptions.Build())
.Build();

await client.StopAsync();
await client.StartAsync(managedClientOptions);
await _client.StopAsync();
await _client.StartAsync(managedClientOptions);
await Task.WhenAll(
topics.Select(topic => client.SubscribeAsync(topic))
topics.Where(t => !string.IsNullOrWhiteSpace(t)).Select(topic => _client.SubscribeAsync(topic))
);
await _client.SubscribeAsync("#");
}

/// <summary>
/// Disconnects the connector from the server it is connected to.
/// </summary>
public Task Stop()
{
return client.StopAsync();
return _client.StopAsync();
}

private Task OnClientMessageReceived(MqttApplicationMessageReceivedEventArgs e)
Expand Down
Loading

0 comments on commit 04d946b

Please sign in to comment.