Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
59 changes: 51 additions & 8 deletions AppBroker.App/Controller/LayoutController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@
namespace AppBroker.App.Controller;

public record LayoutRequest(string TypeName, string IconName, long DeviceId);
public record LayoutResponse(DeviceLayout? Layout, SvgIcon? Icon);
public record IconResponse(SvgIcon Icon, string Name);
public record LayoutResponse(DeviceLayout? Layout, IconResponse? Icon, IconResponse[] additionalIcons);


[Route("app/layout")]
Expand All @@ -37,9 +38,31 @@ public LayoutResponse GetSingle([FromQuery] LayoutRequest request)
{
var layout = GetLayout(request);
var icon = GetIcon(request, layout?.IconName);
var additional = GetAdditionalIcons(layout);

return new LayoutResponse(layout, icon);
return new LayoutResponse(layout, icon, additional);
}

private IconResponse[] GetAdditionalIcons(DeviceLayout? layout)
{
var histIconNames =
(layout?.DetailDeviceLayout?.HistoryProperties?.Select(x => x?.IconName) ?? Array.Empty<string>())
.Concat(layout?.DetailDeviceLayout?.TabInfos?.Select(x=>x.IconName) ?? Array.Empty<string>())
.Distinct();
var additional = Array.Empty<IconResponse>();
if (histIconNames is not null)
{
additional = histIconNames
.Where(x => x is not null)
.Select(x => GetIcon(null, x))
.Where(x => x is not null)
.Select(x => x!)
.ToArray();
}

return additional;
}

[HttpGet("multi")]
public List<LayoutResponse> GetMultiple([FromQuery] List<LayoutRequest> request)
{
Expand All @@ -50,18 +73,31 @@ public List<LayoutResponse> GetMultiple([FromQuery] List<LayoutRequest> request)
var layout = GetLayout(req);
var icon = GetIcon(req, layout?.IconName);
if (icon is not null || layout is not null)
response.Add(new LayoutResponse(layout, icon));
response.Add(new LayoutResponse(layout, icon, GetAdditionalIcons(layout)));
}
return response;
}

[HttpGet("all")]
public List<LayoutResponse> GetAll()
{
return DeviceLayoutService
try
{
return DeviceLayoutService
.GetAllLayouts()
.Select(x => new LayoutResponse(x, GetIcon(null, x.IconName)))
.ToList();
.Select(x => new LayoutResponse(x, GetIcon(null, x.IconName), GetAdditionalIcons(x)))
.ToList();
}
catch (Exception)
{
throw;
}
}

[HttpGet("iconByName")]
public SvgIcon GetAllIcons(string name)
{
return iconService.GetIconByName(name);
}

private DeviceLayout? GetLayout(LayoutRequest request)
Expand All @@ -85,25 +121,32 @@ public List<LayoutResponse> GetAll()
return layout;
}

private SvgIcon? GetIcon(LayoutRequest? request, string? iconName)
private IconResponse? GetIcon(LayoutRequest? request, string? iconName)
{
IconResponse? res = null;
SvgIcon? icon = null;
if (!string.IsNullOrWhiteSpace(iconName))
{
icon = iconService.GetIconByName(iconName);
if (icon is not null)
res = new IconResponse(icon, iconName);
}
if (request is not null)
{
if (icon is null && !string.IsNullOrWhiteSpace(request?.IconName))
{
icon = iconService.GetIconByName(request.IconName);
if (icon is not null)
res = new IconResponse(icon, request!.IconName);
}
if (icon is null && !string.IsNullOrWhiteSpace(request?.TypeName))
{
icon = iconService.GetBestFitIcon(request.TypeName);
if (icon is not null)
res = new IconResponse(icon, request!.TypeName);
}
}
return icon;
return res;
}

[HttpPatch]
Expand Down
4 changes: 2 additions & 2 deletions AppBroker.App/Controller/SmarthomeController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,10 @@ public class SmarthomeController : ControllerBase
private readonly IDeviceManager deviceManager;
private readonly NLog.ILogger logger;

public SmarthomeController(IDeviceManager deviceManager, ILogger logger)
public SmarthomeController(IDeviceManager deviceManager)
{
this.deviceManager = deviceManager;
this.logger = logger;
logger = LogManager.LogFactory.GetCurrentClassLogger();
}

/// <summary>
Expand Down
2 changes: 1 addition & 1 deletion AppBroker.App/Plugin.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ internal class Plugin : IPlugin
{
public string Name => "App";

public int LoadOrder => int.MinValue;
public int LoadOrder => 0;

public bool Initialize(LogFactory logFactory)
{
Expand Down
4 changes: 3 additions & 1 deletion AppBroker.Core/AppBroker.Core.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,16 @@
<PackageReference Include="CoordinateSharp" Version="2.22.1.1" />

<PackageReference Include="Jint" Version="3.1.1" />

<PackageReference Include="JsonPath.Net" Version="2.1.1" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Proxies" Version="8.0.11" />
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="8.0.11" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Relational" Version="8.0.11" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
<PackageReference Include="NLog.Extensions.Logging" Version="5.3.11" />
<PackageReference Include="NonSucking.Framework.Extension" Version="1.0.0" />
<PackageReference Include="NonSucking.Framework.Extension.EntityFrameworkCore" Version="0.1.0.107-alpha" />
<PackageReference Include="NonSucking.Framework.Serialization" Version="1.0.0" />
<!--<PackageReference Include="NonSucking.Framework.Serialization" Version="1.0.0" />-->
<PackageReference Include="NSwag.Annotations" Version="14.2.0" />
<PackageReference Include="NSwag.Core" Version="14.2.0" />
<PackageReference Include="Quartz" Version="3.9.0" />
Expand Down
2 changes: 2 additions & 0 deletions AppBroker.Core/BasicMessage.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;

using System.ComponentModel;

namespace AppBroker.Core;

public abstract class BaseSmarthomeMessage
Expand Down
2 changes: 0 additions & 2 deletions AppBroker.Core/Configuration/DatabaseConfig.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,6 @@ public DatabaseConfig()
HistoryDBConnectionString = "Data Source=history.db";
BrokerDatabasePluginName = "NonSucking.Framework.Extension.Database.Sqlite.dll";
HistoryDatabasePluginName = "NonSucking.Framework.Extension.Database.Sqlite.dll";


}

}
120 changes: 104 additions & 16 deletions AppBroker.Core/DynamicUI/DeviceLayoutService.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
using Newtonsoft.Json;
using Json.Path;

using Newtonsoft.Json;
using Newtonsoft.Json.Linq;

using System.Diagnostics;
using System.Security.Cryptography;
using System.Text;
using System.Text.Json.Nodes;

namespace AppBroker.Core.DynamicUI;

Expand Down Expand Up @@ -29,25 +35,25 @@ static DeviceLayoutService()
}

#pragma warning disable CA5351 // Do Not Use Broken Cryptographic Algorithms
private static string GetMD5StringFor(byte[] bytes)
private static string GetMD5StringFor(ReadOnlySpan<byte> bytes)
{
Span<byte> toWriteBytes = stackalloc byte[16];
_ = MD5.HashData(bytes, toWriteBytes);
return Convert.ToHexString(toWriteBytes);
}
#pragma warning restore CA5351 // Do Not Use Broken Cryptographic Algorithms

private static DeviceLayout GetLayout(string path)
private static DeviceLayout GetLayout(string fileName, JToken rawData)
{
var text = File.ReadAllText(path);
var hash = GetMD5StringFor(File.ReadAllBytes(path));
var layout = JsonConvert.DeserializeObject<DeviceLayout>(text);
if(layout is null)
var hash = GetMD5StringFor(Encoding.UTF8.GetBytes(rawData.ToString()));

var layout = rawData.ToObject<DeviceLayout>();
if (layout is null)
{
throw new FileLoadException($"Could not parse {text} to DeviceLayout");
throw new FileLoadException($"Could not parse {fileName} to DeviceLayout");
}
return layout with { AdditionalDataDes = layout.AdditionalDataDes ?? [], Hash= hash };
return layout with { AdditionalDataDes = layout.AdditionalDataDes ?? [], Hash = hash };

}
private static void FileChanged(object sender, FileSystemEventArgs e)
{
Expand All @@ -56,7 +62,10 @@ private static void FileChanged(object sender, FileSystemEventArgs e)
_ = Task.Delay(100).ContinueWith((t) =>
{
logger.Info($"Layout change detected: {e.FullPath}");
var layout = GetLayout(e.FullPath);

var (name, token) = GetLayoutsWithPathReplaced("DeviceLayouts").FirstOrDefault(x => x.Key == e.Name);

var layout = GetLayout(name, token);

if (layout is null)
return;
Expand Down Expand Up @@ -137,17 +146,17 @@ private static void CheckLayout(DeviceLayout layout, string hash, HashSet<string

public static void ReloadLayouts()
{
string[]? files = Directory.GetFiles("DeviceLayouts", "*.json");
var layouts = GetLayoutsWithPathReplaced("DeviceLayouts");

TypeDeviceLayouts.Clear();
InstanceDeviceLayouts.Clear();
foreach (string? file in files)

foreach (var (name, token) in layouts.Where(x => x.Value["UniqueName"] is not null))
{
// TODO: try catch
try
{
var layout = GetLayout(file);
var hash = layout.Hash;
var layout = GetLayout(name, token);
var hash = layout.Hash;
if (layout is null)
continue;

Expand Down Expand Up @@ -222,4 +231,83 @@ public static List<DeviceLayout> GetAllLayouts()
.ToList();
}

const string refStr = "\"@ref\"";
private static Dictionary<string, JToken> GetLayoutsWithPathReplaced(string directory)
{
StringBuilder sb = new();
sb.Append("{");
foreach (var path in Directory.GetFiles(directory, "*.json", SearchOption.AllDirectories))
{
sb.Append(
$$"""
"{{Path.GetRelativePath(directory, path).Replace('\\', '/')}}" : {{File.ReadAllText(path)}},
""");
}

sb.Remove(sb.Length - 1, 1);
sb.Append("}");
var allCombined = sb.ToString();
var jo = JsonNode.Parse(allCombined,
documentOptions:
new System.Text.Json.JsonDocumentOptions()
{
CommentHandling = System.Text.Json.JsonCommentHandling.Skip,
AllowTrailingCommas = true
});
int currentIndex = 0;
while (currentIndex < allCombined.Length)
{
var refIndex = allCombined.IndexOf(refStr, currentIndex);
if (refIndex == -1)
break;
int refFrom = 0;
int refTo = 0;
byte foundQuotations = 0;
for (int i = refIndex + refStr.Length; i < allCombined.Length - 1; i++)
{
if (allCombined[i] == '"' && allCombined[i - 1] != '\\')
{
foundQuotations++;
if (foundQuotations == 1)
{
refFrom = i;
}
else
{
refTo = i + 1;
break;
}
}
}
if (foundQuotations < 2)
break;
refIndex = allCombined.LastIndexOf('{', refIndex);
var removeTo = allCombined.IndexOf('}', refTo) + 1;
var path = allCombined[(refFrom + 1)..(refTo - 1)];
allCombined = allCombined.Remove(refIndex, removeTo - refIndex);

var jPath = JsonPath.Parse(path);
var res = jPath.Evaluate(jo);
if (res.Matches.Count == 0)
{
throw new JsonPathNotResolvableException(path);
}
var match = res.Matches[0];
var key = jPath.Segments.Last().Selectors.Last().ToString().Replace("'", "\"");
allCombined = allCombined.Insert(refIndex, match.Value.ToJsonString());
currentIndex = refIndex;
}

return
JsonConvert
.DeserializeObject<Dictionary<string, JToken>>(allCombined);

}
private class JsonPathNotResolvableException : Exception
{
public JsonPathNotResolvableException(string? path) : base($"The json path ´{path}´ is not resolvable.")
{

}
}
}
2 changes: 0 additions & 2 deletions AppBroker.Core/IconService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,6 @@

namespace AppBroker.Core;

[NonSucking.Framework.Serialization.Nooson]

public partial record SvgIcon(string Name, string Hash,[property: JsonIgnore] string Path, byte[]? Data, string TypeName ="");


Expand Down
2 changes: 1 addition & 1 deletion AppBroker.IOBroker/Plugin.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ namespace AppBroker.IOBroker;
public class Plugin : IPlugin
{
public string Name { get; }
public int LoadOrder => int.MinValue;
public int LoadOrder => 0;

public bool Initialize(LogFactory logFactory)
{
Expand Down
18 changes: 9 additions & 9 deletions AppBroker.Mail/AppBroker.Mail.csproj
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net9.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
</PropertyGroup>
<PropertyGroup>
<TargetFramework>net9.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="MailKit" Version="4.8.0" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="MailKit" Version="4.8.0" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\AppBroker.Core\AppBroker.Core.csproj" />
Expand Down
15 changes: 15 additions & 0 deletions AppBroker.Mail/Configuration/MailConfig.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
using AppBroker.Core.Configuration;


namespace AppBroker.Windmill.Configuration;

public class MailConfig : IConfig
{
public string Name => "Mail";

public string Host { get; set; }
public ushort Port {get;set;}
public bool UseSsl {get;set;}
public string Username {get;set;}
public string Password {get;set;}
}
Loading