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
8 changes: 7 additions & 1 deletion Oma.WndwCtrl.Abstractions/ICommand.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
using System.Text.Json.Serialization;
using JetBrains.Annotations;
using LanguageExt;
using Oma.WndwCtrl.Abstractions.Model;
using ValueType = Oma.WndwCtrl.Abstractions.Model.ValueType;

namespace Oma.WndwCtrl.Abstractions;

Expand All @@ -17,8 +19,12 @@ public interface ICommand
[JsonIgnore]
string Category { get; }

IEnumerable<ITransformation> Transformations { get; }
IList<ITransformation> Transformations { get; }

[JsonIgnore]
Option<IComponent> Component { get; set; }

ValueType InferredType => Transformations.LastOrDefault()?.ValueType ?? default;

Cardinality InferredCardinality => Transformations.LastOrDefault()?.Cardinality ?? default;
}
10 changes: 9 additions & 1 deletion Oma.WndwCtrl.Abstractions/ITransformation.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,11 @@
using Oma.WndwCtrl.Abstractions.Model;
using ValueType = Oma.WndwCtrl.Abstractions.Model.ValueType;

namespace Oma.WndwCtrl.Abstractions;

public interface ITransformation;
public interface ITransformation
{
public Cardinality Cardinality { get; }

public ValueType ValueType { get; }
}
4 changes: 2 additions & 2 deletions Oma.WndwCtrl.Abstractions/Model/Cardinality.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,6 @@ namespace Oma.WndwCtrl.Abstractions.Model;
[JsonConverter(typeof(JsonStringEnumConverter))]
public enum Cardinality
{
Single,
Multiple,
Single = 0,
Multiple = 1,
}
8 changes: 4 additions & 4 deletions Oma.WndwCtrl.Abstractions/Model/ValueType.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ namespace Oma.WndwCtrl.Abstractions.Model;
[JsonConverter(typeof(JsonStringEnumConverter))]
public enum ValueType
{
Boolean,
String,
Long,
Decimal,
String = 0,
Boolean = 1,
Long = 2,
Decimal = 3,
}
13 changes: 12 additions & 1 deletion Oma.WndwCtrl.Api/CtrlApiService.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Options;
using Microsoft.OpenApi.Any;
using Microsoft.OpenApi.Interfaces;
using Microsoft.OpenApi.Models;
Expand All @@ -9,6 +10,7 @@
using Oma.WndwCtrl.Api.Hubs.MessageConsumer;
using Oma.WndwCtrl.Api.OpenApi;
using Oma.WndwCtrl.Configuration.Model;
using Oma.WndwCtrl.Core.Model.Settings;
using Oma.WndwCtrl.CoreAsp;
using Oma.WndwCtrl.Messaging.Bus;
using Oma.WndwCtrl.Messaging.Extensions;
Expand Down Expand Up @@ -44,8 +46,11 @@ protected override IServiceCollection ConfigureServices(IServiceCollection servi
options =>
{
options.AddDocumentTransformer(
(document, _, _) =>
(document, context, _) =>
{
GeneralSettings generalSettings = context.ApplicationServices
.GetRequiredService<IOptions<GeneralSettings>>().Value;

document.Info = new OpenApiInfo
{
Title = "Component Control API",
Expand All @@ -54,6 +59,12 @@ protected override IServiceCollection ConfigureServices(IServiceCollection servi
Extensions = new Dictionary<string, IOpenApiExtension>
{
["acaad"] = new OpenApiString("commithash"),
["acaad.metadata"] = new OpenApiObject
{
["name"] = new OpenApiString(generalSettings.Name),
["os"] = new OpenApiString(generalSettings.OS),
["otlpEnabled"] = new OpenApiBoolean(generalSettings.UseOtlp),
},
},
};

Expand Down
4 changes: 0 additions & 4 deletions Oma.WndwCtrl.Api/Oma.WndwCtrl.Api.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,6 @@
<Content Remove="ctrl-api.json"/>
</ItemGroup>

<ItemGroup>
<Folder Include="Actions\"/>
</ItemGroup>

<ItemGroup>
<None Include="CtrlApiService.config.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
Expand Down
20 changes: 17 additions & 3 deletions Oma.WndwCtrl.Api/OpenApi/ComponentWriters/SensorComponentWriter.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using LanguageExt;
using Microsoft.OpenApi.Any;
using Oma.WndwCtrl.Api.OpenApi.Interfaces;
using Oma.WndwCtrl.Api.OpenApi.Model;
using Oma.WndwCtrl.Core.Model;
Expand All @@ -7,12 +8,25 @@ namespace Oma.WndwCtrl.Api.OpenApi.ComponentWriters;

public class SensorComponentWriter(ILogger<SensorComponentWriter> logger) : IOpenApiComponentWriter<Sensor>
{
public Task<Option<OpenApiComponentExtension>> CreateExtensionAsync(Sensor component) =>
Task.FromResult(
public Task<Option<OpenApiComponentExtension>> CreateExtensionAsync(Sensor component)
{
OpenApiComponentExtension componentExtension = new(component)
{
["type"] = new OpenApiString(component.QueryCommand.InferredType.ToString()),
["cardinality"] = new OpenApiString(component.QueryCommand.InferredCardinality.ToString()),
};

if (!string.IsNullOrEmpty(component.UnitOfMeasure))
{
componentExtension["unitOfMeasure"] = new OpenApiString(component.UnitOfMeasure);
}

return Task.FromResult(
Option<OpenApiComponentExtension>.Some(
new OpenApiComponentExtension(component)
componentExtension
)
);
}

public ILogger Logger { get; } = logger;
}
27 changes: 24 additions & 3 deletions Oma.WndwCtrl.Api/OpenApi/ComponentWriters/SwitchComponentWriter.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using LanguageExt;
using Microsoft.OpenApi.Any;
using Oma.WndwCtrl.Api.OpenApi.Interfaces;
using Oma.WndwCtrl.Api.OpenApi.Model;
using Oma.WndwCtrl.Core.Model;
Expand All @@ -7,12 +8,32 @@ namespace Oma.WndwCtrl.Api.OpenApi.ComponentWriters;

public class SwitchComponentWriter(ILogger<SwitchComponentWriter> logger) : IOpenApiComponentWriter<Switch>
{
public Task<Option<OpenApiComponentExtension>> CreateExtensionAsync(Switch component) =>
Task.FromResult(
public Task<Option<OpenApiComponentExtension>> CreateExtensionAsync(Switch component)
{
OpenApiComponentExtension componentExtension = new(component)
{
["onIff"] = MapOnIff(component),
};

return Task.FromResult(
Option<OpenApiComponentExtension>.Some(
new OpenApiComponentExtension(component)
componentExtension
)
);
}

public ILogger Logger { get; } = logger;

private static IOpenApiPrimitive MapOnIff(Switch component)
=> component.OnIff switch
{
// TODO: Quite ugly to have different type mappings in Switch and here.. Oh well, fix later.
string s => new OpenApiString(s),
bool b => new OpenApiBoolean(b),
long l => new OpenApiLong(l),
decimal d => new OpenApiDouble((double)d),
var _ => throw new ArgumentException(
$"Unsupported type {component.OnIff.GetType()} for onIff (inferred value type: {component.InferredComparisonType})."
),
};
}
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@
},
"ping-google": {
"type": "sensor",
"unitOfMeasure": "ms",
"queryCommand": {
"type": "cli",
"fileName": "ping",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@
"ping-google": {
"type": "sensor",
"active": true,
"unitOfMeasure": "ms",
"queryCommand": {
"type": "cli",
"fileName": "ping",
Expand Down Expand Up @@ -132,6 +133,7 @@
"test-switch": {
"type": "switch",
"active": true,
"onIff": "RUNNING",
"queryCommand": {
"type": "cli",
"fileName": "C:\\Program Files\\Git\\usr\\bin\\bash.exe",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ IConfiguration configuration
.Configure<CliParserLoggerOptions>(
coreConfig.GetSection(CliParserLoggerOptions.SectionName)
)
.Configure<GeneralSettings>(coreConfig.GetSection(GeneralSettings.SectionName));
.Configure<GeneralSettings>(configuration.GetSection(GeneralSettings.SectionName));

ExtensionSettings extensions = [];
coreConfig.GetSection(ExtensionSettings.SectionName).Bind(extensions);
Expand Down
2 changes: 1 addition & 1 deletion Oma.WndwCtrl.Core/Model/Commands/BaseCommand.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ public abstract class BaseCommand : ICommand
[JsonIgnore]
public abstract string Category { get; }

public IEnumerable<ITransformation> Transformations { get; set; } = new List<ITransformation>();
public IList<ITransformation> Transformations { get; set; } = new List<ITransformation>();

[JsonIgnore]
public Option<IComponent> Component { get; set; }
Expand Down
107 changes: 107 additions & 0 deletions Oma.WndwCtrl.Core/Model/Switch.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
using System.Text.Json.Serialization;
using JetBrains.Annotations;
using Oma.WndwCtrl.Abstractions;
using Oma.WndwCtrl.Core.Interfaces;
using ValueType = Oma.WndwCtrl.Abstractions.Model.ValueType;

namespace Oma.WndwCtrl.Core.Model;

Expand All @@ -11,6 +13,20 @@ namespace Oma.WndwCtrl.Core.Model;
/// </summary>
public class Switch : Component, IStateQueryable
{
public delegate (bool Is, object? instance) TryParse(object obj);

[PublicAPI]
public static readonly IReadOnlyDictionary<ValueType, TryParse> ValueTypeValidators =
new Dictionary<ValueType, TryParse>
{
[ValueType.Boolean] = TryParseBool,
[ValueType.Long] = TryParseLong,
[ValueType.Decimal] = TryParseDecimal,
[ValueType.String] = TryParseString,
};

private object _onIff = true;

[JsonIgnore]
public override string Type => "switch";

Expand All @@ -25,7 +41,98 @@ public class Switch : Component, IStateQueryable
[JsonIgnore]
public override IEnumerable<ICommand> Commands => [QueryCommand,];

[JsonInclude]
public object OnIff
{
get => _onIff;
set
{
foreach ((ValueType valueType, TryParse validator) in ValueTypeValidators)
{
(bool typeMatch, object? instance) = validator(value);

if (!typeMatch)
{
continue;
}

InferredComparisonType = valueType;
_onIff = instance!;
break;
}

if (InferredComparisonType is null)
{
throw new InvalidOperationException(
$"Unsupported type for OnIff: {value}. Allowed value types are [{string.Join(", ", ValueTypeValidators.Keys.Select(vt => vt.ToString()))}]"
);
}
}
}

[JsonIgnore]
public ValueType? InferredComparisonType { get; private set; }

[JsonInclude]
[JsonRequired]
public ICommand QueryCommand { get; internal set; } = null!;

private static (bool, object?) TryParseBool(object obj)
{
if (obj is bool res)
{
return (true, res);
}

if (bool.TryParse(obj.ToString(), out bool resParsed))
{
return (true, resParsed);
}

return (false, null);
}

private static (bool, object?) TryParseString(object obj)
{
if (obj is string res)
{
return (true, res);
}

string? asString = obj.ToString();

return !string.IsNullOrEmpty(asString)
? (true, asString)
: (false, null);
}

private static (bool, object?) TryParseLong(object obj)
{
if (obj is long res)
{
return (true, res);
}

if (long.TryParse(obj.ToString(), out long resParsed))
{
return (true, resParsed);
}

return (false, null);
}

private static (bool, object?) TryParseDecimal(object obj)
{
if (obj is decimal res)
{
return (true, res);
}

if (decimal.TryParse(obj.ToString(), out decimal resParsed))
{
return (true, resParsed);
}

return (false, null);
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
using Oma.WndwCtrl.Abstractions;
using Oma.WndwCtrl.Abstractions.Model;
using ValueType = Oma.WndwCtrl.Abstractions.Model.ValueType;

namespace Oma.WndwCtrl.Core.Model.Transformations;

public record BaseTransformation : ITransformation;
public record BaseTransformation : ITransformation
{
public ValueType ValueType { get; init; } = ValueType.String;
public Cardinality Cardinality { get; init; } = Cardinality.Single;
}
Original file line number Diff line number Diff line change
@@ -1,14 +1,7 @@
using Oma.WndwCtrl.Abstractions.Model;
using ValueType = Oma.WndwCtrl.Abstractions.Model.ValueType;

namespace Oma.WndwCtrl.Core.Model.Transformations;

[Serializable]
public record ParserTransformation : BaseTransformation
{
public IReadOnlyList<string> Statements { get; init; } = [];

public Cardinality Cardinality { get; init; } = Cardinality.Single;

public ValueType ValueType { get; init; } = ValueType.String;
}
Loading