Merge remote-tracking branch 'origin/main'
This commit is contained in:
commit
965a85ba81
|
@ -13,7 +13,7 @@
|
|||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="System.Linq.Async" Version="5.0.0" />
|
||||
<PackageReference Include="System.Linq.Async" Version="6.0.1" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
|
|
@ -134,7 +134,7 @@ public static class Program
|
|||
var company = x.LastOrDefault()?.Split('(').FirstOrDefault()?.Trim() ?? "";
|
||||
var sn = x.LastOrDefault()?.Split('(').LastOrDefault()?.Trim("() ".ToCharArray()) ?? "";
|
||||
|
||||
var created = i.Created.ToUtcDateTime().ToString("dd.MM.yyyy HH:mm");
|
||||
var created = i.Created.DateTimeFromUnixTime().ToString("dd.MM.yyyy HH:mm");
|
||||
|
||||
var line = new[]
|
||||
{
|
||||
|
|
|
@ -18,7 +18,6 @@
|
|||
<ProjectReference Include="../../Lib/Devices/Trumpf/SystemControl/SystemControl.csproj" />
|
||||
<ProjectReference Include="../../Lib/Devices/Trumpf/TruConvertAc/TruConvertAc.csproj" />
|
||||
<ProjectReference Include="../../Lib/Devices/Trumpf/TruConvertDc/TruConvertDc.csproj" />
|
||||
<ProjectReference Include="../../Lib/Time/Time.csproj" />
|
||||
<ProjectReference Include="../../Lib/Units/Units.csproj" />
|
||||
<ProjectReference Include="../../Lib/Utils/Utils.csproj" />
|
||||
</ItemGroup>
|
||||
|
|
|
@ -3,11 +3,10 @@ Description=Battery48TL_TCP_Bridge
|
|||
|
||||
[Service]
|
||||
Type=simple
|
||||
#ExecStart=socat -v -v TCP-LISTEN:6855,nodelay,fork,reuseaddr GOPEN:/dev/ttyUSB0,raw,b115200
|
||||
#ExecStart=socat -x -d -d TCP-LISTEN:6855,fork,max-children=1 GOPEN:/dev/ttyUSB0,rawer,b115200,cs8,parenb=1,parodd=1
|
||||
ExecStart=socat -x -d -d TCP-LISTEN:6855 GOPEN:/dev/ttyUSB0,rawer,b115200,cs8,parenb=1,parodd=1
|
||||
Restart=always
|
||||
RestartSec=500ms
|
||||
StartLimitInterval=0
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
using InnovEnergy.Lib.Time.Unix;
|
||||
using InnovEnergy.Lib.Utils;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace InnovEnergy.App.SaliMax;
|
||||
|
@ -37,7 +37,7 @@ public class CustomLogger : ILogger
|
|||
File.AppendAllText(_LogFilePath, logMessage + Environment.NewLine);
|
||||
_CurrentFileSizeBytes += logMessage.Length;
|
||||
|
||||
Console.WriteLine(logMessage);
|
||||
//Console.WriteLine(logMessage);
|
||||
}
|
||||
|
||||
private void RotateLogFile()
|
||||
|
@ -56,7 +56,7 @@ public class CustomLogger : ILogger
|
|||
File.Delete(logFiles.First());
|
||||
|
||||
// Rename the current log file with a timestamp
|
||||
var logFileBackupPath = Path.Combine(logFileDir, $"{logFileBaseName}_{UnixTime.Now}{logFileExt}");
|
||||
var logFileBackupPath = Path.Combine(logFileDir, $"{logFileBaseName}_{DateTime.Now.ToUnixTime()}{logFileExt}");
|
||||
File.Move(_LogFilePath, logFileBackupPath);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,9 +6,9 @@ public static class Logger
|
|||
{
|
||||
// Specify the maximum log file size in bytes (e.g., 1 MB)
|
||||
|
||||
private const Int32 MaxFileSizeBytes = 1024 * 1024; // TODO: move to settings
|
||||
private const Int32 MaxLogFileCount = 1000; // TODO: move to settings
|
||||
private const String LogFilePath = "LogDirectory/log.txt"; // TODO: move to settings
|
||||
private const Int32 MaxFileSizeBytes = 1024 * 21; // TODO: move to settings
|
||||
private const Int32 MaxLogFileCount = 5000; // TODO: move to settings
|
||||
private const String LogFilePath = "LogDirectory/log.csv"; // TODO: move to settings
|
||||
|
||||
// ReSharper disable once InconsistentNaming
|
||||
private static readonly ILogger _logger = new CustomLogger(LogFilePath, MaxFileSizeBytes, MaxLogFileCount);
|
||||
|
|
|
@ -16,18 +16,18 @@ using InnovEnergy.Lib.Devices.Trumpf.TruConvertAc.DataTypes;
|
|||
using InnovEnergy.Lib.Devices.Trumpf.TruConvertDc;
|
||||
using InnovEnergy.Lib.Devices.Trumpf.TruConvertDc.Control;
|
||||
using InnovEnergy.Lib.Protocols.Modbus.Channels;
|
||||
using InnovEnergy.Lib.Time.Unix;
|
||||
using InnovEnergy.Lib.Units;
|
||||
using InnovEnergy.Lib.Utils;
|
||||
using static InnovEnergy.Lib.Devices.Trumpf.SystemControl.DataTypes.SystemConfig;
|
||||
|
||||
|
||||
#pragma warning disable IL2026
|
||||
|
||||
namespace InnovEnergy.App.SaliMax;
|
||||
|
||||
internal static class Program
|
||||
{
|
||||
private static readonly UnixTimeSpan UpdateInterval = UnixTimeSpan.FromSeconds(2);
|
||||
private static readonly TimeSpan UpdateInterval = TimeSpan.FromSeconds(2);
|
||||
|
||||
private static readonly IReadOnlyList<Byte> BatteryNodes;
|
||||
|
||||
|
@ -148,9 +148,9 @@ internal static class Program
|
|||
while (true)
|
||||
{
|
||||
await Observable
|
||||
.Interval(UpdateInterval.ToTimeSpan())
|
||||
.Interval(UpdateInterval)
|
||||
.Select(_ => RunIteration())
|
||||
.SelectMany(r => UploadCsv(r, UnixTime.Now.RoundTo(UpdateInterval)))
|
||||
.SelectMany(r => UploadCsv(r, DateTime.UtcNow))
|
||||
.SelectError()
|
||||
.ToTask();
|
||||
}
|
||||
|
@ -172,13 +172,14 @@ internal static class Program
|
|||
var record = ReadStatus();
|
||||
|
||||
// If control Special Error return true, we must stop the system.(break;)
|
||||
var specialErrorOccured = record.ControlSpecialError();
|
||||
var alarmCondition = record.DetectAlarmStates();
|
||||
|
||||
if (specialErrorOccured.Item1)
|
||||
|
||||
if (alarmCondition is not null)
|
||||
{
|
||||
//stop the system
|
||||
//return
|
||||
specialErrorOccured.Item2.WriteLine();
|
||||
alarmCondition.LogInfo();
|
||||
}
|
||||
|
||||
record.ControlConstants();
|
||||
|
@ -186,7 +187,7 @@ internal static class Program
|
|||
|
||||
$"{record.StateMachine.State}: {record.StateMachine.Message}".LogInfo();
|
||||
|
||||
var essControl = record.ControlEss().LogInfo();
|
||||
var essControl = record.ControlEss().WriteLine().LogInfo();
|
||||
|
||||
record.EssControl = essControl;
|
||||
|
||||
|
@ -212,36 +213,13 @@ internal static class Program
|
|||
// ReSharper disable once FunctionNeverReturns
|
||||
}
|
||||
|
||||
private static (Boolean, String) ControlSpecialError (this StatusRecord r) // to find a better name
|
||||
private static String? DetectAlarmStates(this StatusRecord r) => r.Relays switch
|
||||
{
|
||||
// Those errors must not occurs. Stop the system in case this is happen.
|
||||
var isSpecialErrorOccured = false;
|
||||
var errorMessage = "No Error";
|
||||
|
||||
// 1. relay0 is open and K2 Close.
|
||||
if (r.Relays is { K2ConnectIslandBusToGridBus: false, K2IslandBusIsConnectedToGridBus: true } )
|
||||
{
|
||||
isSpecialErrorOccured = true;
|
||||
errorMessage = " Contradiction: R0 is opening the K2 but the K2 is still close ";
|
||||
}
|
||||
|
||||
// 2. If K1 is open, K2 must be open .
|
||||
if (r.Relays is { K1GridBusIsConnectedToGrid: false, K2IslandBusIsConnectedToGridBus: true } )
|
||||
{
|
||||
isSpecialErrorOccured = true;
|
||||
errorMessage = " Contradiction: K1 is open but the K2 is still close ";
|
||||
}
|
||||
|
||||
// 3. If FI error is occured, K2 must be open.
|
||||
if (r.Relays is { FiError: true, K2IslandBusIsConnectedToGridBus: true } )
|
||||
{
|
||||
isSpecialErrorOccured = true;
|
||||
errorMessage = " Contradiction: Fi error occured but the K2 is still close ";
|
||||
}
|
||||
|
||||
|
||||
return (isSpecialErrorOccured, errorMessage);
|
||||
}
|
||||
{ K2ConnectIslandBusToGridBus: false, K2IslandBusIsConnectedToGridBus: true } => " Contradiction: R0 is opening the K2 but the K2 is still close ",
|
||||
{ K1GridBusIsConnectedToGrid : false, K2IslandBusIsConnectedToGridBus: true } => " Contradiction: K1 is open but the K2 is still close ",
|
||||
{ FiError: true, K2IslandBusIsConnectedToGridBus: true } => " Contradiction: Fi error occured but the K2 is still close ",
|
||||
_ => null
|
||||
};
|
||||
|
||||
private static void ControlConstants(this StatusRecord r)
|
||||
{
|
||||
|
@ -335,7 +313,7 @@ internal static class Program
|
|||
sc.ResetAlarmsAndWarnings = true;
|
||||
}
|
||||
|
||||
private static async Task<Boolean> UploadCsv(StatusRecord status, UnixTime timeStamp)
|
||||
private static async Task<Boolean> UploadCsv(StatusRecord status, DateTime timeStamp)
|
||||
{
|
||||
var s3Config = status.Config.S3;
|
||||
if (s3Config is null)
|
||||
|
|
|
@ -2,7 +2,7 @@ namespace InnovEnergy.App.SaliMax.SystemConfig;
|
|||
|
||||
public class AcDcConfig
|
||||
{
|
||||
public required Double MaxDcLinkVoltage { get; set; }
|
||||
public required Double MinDcLinkVoltage { get; set; }
|
||||
public required Double ReferenceDcLinkVoltage { get; set; }
|
||||
public required Double MaxDcLinkVoltage { get; init; }
|
||||
public required Double MinDcLinkVoltage { get; init; }
|
||||
public required Double ReferenceDcLinkVoltage { get; init; }
|
||||
}
|
|
@ -1,5 +1,4 @@
|
|||
using System.Text.Json;
|
||||
using InnovEnergy.Lib.Time.Unix;
|
||||
using InnovEnergy.Lib.Utils;
|
||||
using static System.Text.Json.JsonSerializer;
|
||||
|
||||
|
@ -27,7 +26,6 @@ public class Config //TODO: let IE choose from config files (Json) and connect t
|
|||
public required Double MaxBatteryDischargingCurrent { get; set; }
|
||||
public required Double MaxDcPower { get; set; }
|
||||
|
||||
|
||||
public required Double MaxChargeBatteryVoltage { get; set; }
|
||||
public required Double MinDischargeBatteryVoltage { get; set; }
|
||||
|
||||
|
@ -85,6 +83,7 @@ public class Config //TODO: let IE choose from config files (Json) and connect t
|
|||
|
||||
MaxChargeBatteryVoltage = 57,
|
||||
MinDischargeBatteryVoltage = 0,
|
||||
|
||||
Devices = new ()
|
||||
{
|
||||
TruConvertAcIp = new() { Host = "localhost", Port = 5001},
|
||||
|
|
|
@ -2,7 +2,7 @@ namespace InnovEnergy.App.SaliMax.SystemConfig;
|
|||
|
||||
public class DcDcConfig
|
||||
{
|
||||
public required Double LowerDcLinkVoltage { get; set; }
|
||||
public required Double ReferenceDcLinkVoltage { get; set; }
|
||||
public required Double UpperDcLinkVoltage { get; set; }
|
||||
public required Double LowerDcLinkVoltage { get; init; }
|
||||
public required Double ReferenceDcLinkVoltage { get; init; }
|
||||
public required Double UpperDcLinkVoltage { get; init; }
|
||||
}
|
|
@ -2,6 +2,6 @@ namespace InnovEnergy.App.SaliMax.SystemConfig;
|
|||
|
||||
public class DevicesConfig
|
||||
{
|
||||
public required AcDcConfig AcDc { get; set; }
|
||||
public required DcDcConfig DcDc { get; set; }
|
||||
public required AcDcConfig AcDc { get; init; }
|
||||
public required DcDcConfig DcDc { get; init; }
|
||||
}
|
|
@ -72,7 +72,7 @@ public static class Topology
|
|||
var h = g;
|
||||
var i = status.PvOnDc?.Dc.Power.Value;
|
||||
var k = status.DcDc.Dc.Link.Power.Value;
|
||||
var l = k;
|
||||
var l = status.Battery is not null ? status.Battery.Dc.Power.Value : 0;
|
||||
var j = status.LoadOnDc?.Power.Value;
|
||||
var d = status.AcGridToAcIsland?.Power.Active;
|
||||
var c = status.LoadOnAcGrid?.Power.Active;
|
||||
|
@ -260,9 +260,9 @@ public static class Topology
|
|||
.Apply(TextBlock.AlignLeft)
|
||||
.TitleBox("AC/DC");
|
||||
|
||||
var gridFlow = Flow.Horizontal(h);
|
||||
var dcFlow = Flow.Horizontal(h);
|
||||
|
||||
return TextBlock.AlignCenterVertical(inverterBox, gridFlow);
|
||||
return TextBlock.AlignCenterVertical(inverterBox, dcFlow);
|
||||
}
|
||||
|
||||
|
||||
|
@ -285,7 +285,7 @@ public static class Topology
|
|||
return Switch.Open("K3");
|
||||
}
|
||||
|
||||
private static TextBlock CreateDcDcColumn(this StatusRecord status, ActivePower? l)
|
||||
private static TextBlock CreateDcDcColumn(this StatusRecord status, ActivePower? p)
|
||||
{
|
||||
var dc48Voltage = status.DcDc.Dc.Battery.Voltage.ToDisplayString();
|
||||
|
||||
|
@ -293,7 +293,7 @@ public static class Topology
|
|||
.AlignLeft(dc48Voltage)
|
||||
.TitleBox("DC/DC");
|
||||
|
||||
var busFlow = Flow.Horizontal(l);
|
||||
var busFlow = Flow.Horizontal(p);
|
||||
|
||||
return TextBlock.AlignCenterVertical(busBox, busFlow);
|
||||
}
|
||||
|
@ -371,6 +371,7 @@ public static class Topology
|
|||
return batteryAvgBox; // TODO: individualBatteries hidden atm
|
||||
|
||||
|
||||
#pragma warning disable CS0162
|
||||
var batteryBoxes = bat
|
||||
.Devices
|
||||
.Select(CreateBatteryBox)
|
||||
|
@ -386,6 +387,8 @@ public static class Topology
|
|||
batteryAvgBox ,
|
||||
individualBatteries
|
||||
);
|
||||
|
||||
#pragma warning enable CS0162
|
||||
}
|
||||
|
||||
private static TextBlock CreateAveragedBatteryBox(Battery48TlRecords? bat)
|
||||
|
@ -394,8 +397,9 @@ public static class Topology
|
|||
return TextBlock.AlignLeft("no battery").Box();
|
||||
|
||||
var voltage = bat.Dc.Voltage.ToDisplayString();
|
||||
var soc = bat.Devices.Any() ? bat.Devices.Average(b => b.Soc).Percent().ToDisplayString() : "0";
|
||||
var soc = bat.Devices.Any() ? bat.Devices.Average(b => b.Soc).Percent().ToDisplayString() : "0"; // TODO
|
||||
var current = bat.Dc.Current.ToDisplayString();
|
||||
var busCurrent = bat.Devices.Any() ? bat.Devices.Sum(b => b.BusCurrent).A().ToDisplayString() : "0";
|
||||
var temp = bat.Temperature.ToDisplayString();
|
||||
var heatingPower = bat.HeatingPower.ToDisplayString();
|
||||
var alarms = bat.Alarms.Count + " Alarms";
|
||||
|
@ -408,6 +412,7 @@ public static class Topology
|
|||
voltage,
|
||||
soc,
|
||||
current,
|
||||
busCurrent,
|
||||
temp,
|
||||
heatingPower,
|
||||
warnings,
|
||||
|
@ -447,7 +452,7 @@ public static class Topology
|
|||
battery.Soc.ToDisplayString(),
|
||||
battery.Dc.Current.ToDisplayString() + " C/D",
|
||||
battery.Temperatures.Cells.Average.ToDisplayString(),
|
||||
battery.BusCurrent.ToDisplayString() + " T",
|
||||
battery.BusCurrent.ToDisplayString() ,
|
||||
batteryWarnings,
|
||||
batteryAlarms,
|
||||
battery.HeatingCurrent.ToDisplayString() + " H"
|
||||
|
|
|
@ -1,12 +1,8 @@
|
|||
using CliWrap;
|
||||
using CliWrap.Buffered;
|
||||
using HandlebarsDotNet;
|
||||
using InnovEnergy.App.VrmGrabber.Database;
|
||||
using InnovEnergy.App.VrmGrabber.DataTypes;
|
||||
using InnovEnergy.Lib.Utils;
|
||||
using InnovEnergy.Lib.Victron.VictronVRM;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using FILE=System.IO.File;
|
||||
using VrmInstallation = InnovEnergy.Lib.Victron.VictronVRM.Installation;
|
||||
|
||||
namespace InnovEnergy.App.VrmGrabber;
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
using InnovEnergy.Lib.Victron.VictronVRM;
|
||||
using SQLite;
|
||||
|
||||
namespace InnovEnergy.App.VrmGrabber.DataTypes;
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
using InnovEnergy.App.VrmGrabber.DataTypes;
|
||||
|
||||
|
||||
namespace InnovEnergy.App.VrmGrabber.Database;
|
||||
|
||||
|
||||
|
|
|
@ -7,7 +7,6 @@ using CliWrap.Buffered;
|
|||
using InnovEnergy.App.RemoteSupportConsole;
|
||||
using InnovEnergy.Lib.Utils;
|
||||
using InnovEnergy.Lib.Victron.VictronVRM;
|
||||
using Newtonsoft.Json;
|
||||
using SQLite;
|
||||
using static System.Text.Json.JsonSerializer;
|
||||
using static InnovEnergy.App.VrmGrabber.Database.Systemd;
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
using InnovEnergy.App.VrmGrabber.DataTypes;
|
||||
|
||||
|
||||
namespace InnovEnergy.App.VrmGrabber.Database;
|
||||
|
||||
|
||||
|
|
|
@ -1,8 +1,11 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk.Web">
|
||||
|
||||
<Import Project="../InnovEnergy.App.props" />
|
||||
|
||||
<PropertyGroup>
|
||||
<PublishTrimmed>false</PublishTrimmed>
|
||||
<RootNamespace>InnovEnergy.App.VrmGrabber</RootNamespace>
|
||||
</PropertyGroup>
|
||||
<Import Project="../InnovEnergy.App.props" />
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Flurl.Http" Version="3.2.4" />
|
||||
|
@ -30,12 +33,12 @@
|
|||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="../../Lib/Utils/Utils.csproj" />
|
||||
<ProjectReference Include="..\..\Lib\Victron\VictronVRM\VictronVRM.csproj" />
|
||||
<ProjectReference Include="..\RemoteSupportConsole\RemoteSupportConsole.csproj" />
|
||||
<ProjectReference Include="../../Lib/Victron/VictronVRM/VictronVRM.csproj" />
|
||||
<ProjectReference Include="../RemoteSupportConsole/RemoteSupportConsole.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<_ContentIncludedByDefault Remove="wwwroot\index.html" />
|
||||
<_ContentIncludedByDefault Remove="wwwroot/index.html" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
|
|
@ -10,8 +10,6 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SysTools", "Lib/SysTools/Sy
|
|||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WebServer", "Lib/WebServer/WebServer.csproj", "{B2627B9F-41DF-44F7-A0D1-CA71FF4A007A}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Time", "Lib/Time/Time.csproj", "{442A8366-C177-48FE-84A7-BDF6470A09FF}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EmuMeterDriver", "App/EmuMeterDriver/EmuMeterDriver.csproj", "{F65F33B0-3522-4008-8D1E-47EF8E4C7AC7}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BmsTunnel", "App/BmsTunnel/BmsTunnel.csproj", "{40B45363-BE34-420B-8F87-775EE6EE3513}"
|
||||
|
@ -81,6 +79,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "S3Explorer", "App\S3Explore
|
|||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "VrmGrabber", "App\VrmGrabber\VrmGrabber.csproj", "{88633C71-D701-49B3-A6DE-9D7CED9046E3}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "S3Utils", "Lib\S3Utils\S3Utils.csproj", "{E3914C76-808C-48E0-B5EC-FB24DD999CCC}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Mailer", "Lib\Mailer\Mailer.csproj", "{73B97F6E-2BDC-40DA-84A7-7FB0264387D6}"
|
||||
EndProject
|
||||
|
||||
|
@ -110,10 +110,6 @@ Global
|
|||
{B2627B9F-41DF-44F7-A0D1-CA71FF4A007A}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{B2627B9F-41DF-44F7-A0D1-CA71FF4A007A}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{B2627B9F-41DF-44F7-A0D1-CA71FF4A007A}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{442A8366-C177-48FE-84A7-BDF6470A09FF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{442A8366-C177-48FE-84A7-BDF6470A09FF}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{442A8366-C177-48FE-84A7-BDF6470A09FF}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{442A8366-C177-48FE-84A7-BDF6470A09FF}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{F65F33B0-3522-4008-8D1E-47EF8E4C7AC7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{F65F33B0-3522-4008-8D1E-47EF8E4C7AC7}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{F65F33B0-3522-4008-8D1E-47EF8E4C7AC7}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
|
@ -210,6 +206,10 @@ Global
|
|||
{88633C71-D701-49B3-A6DE-9D7CED9046E3}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{88633C71-D701-49B3-A6DE-9D7CED9046E3}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{88633C71-D701-49B3-A6DE-9D7CED9046E3}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{E3914C76-808C-48E0-B5EC-FB24DD999CCC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{E3914C76-808C-48E0-B5EC-FB24DD999CCC}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{E3914C76-808C-48E0-B5EC-FB24DD999CCC}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{E3914C76-808C-48E0-B5EC-FB24DD999CCC}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{73B97F6E-2BDC-40DA-84A7-7FB0264387D6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{73B97F6E-2BDC-40DA-84A7-7FB0264387D6}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{73B97F6E-2BDC-40DA-84A7-7FB0264387D6}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
|
@ -218,7 +218,6 @@ Global
|
|||
GlobalSection(NestedProjects) = preSolution
|
||||
{CF4834CB-91B7-4172-AC13-ECDA8613CD17} = {145597B4-3E30-45E6-9F72-4DD43194539A}
|
||||
{B1268C03-66EB-4486-8BFC-B439225D9D54} = {145597B4-3E30-45E6-9F72-4DD43194539A}
|
||||
{442A8366-C177-48FE-84A7-BDF6470A09FF} = {AD5B98A8-AB7F-4DA2-B66D-5B4E63E7D854}
|
||||
{40B45363-BE34-420B-8F87-775EE6EE3513} = {145597B4-3E30-45E6-9F72-4DD43194539A}
|
||||
{B2627B9F-41DF-44F7-A0D1-CA71FF4A007A} = {AD5B98A8-AB7F-4DA2-B66D-5B4E63E7D854}
|
||||
{F65F33B0-3522-4008-8D1E-47EF8E4C7AC7} = {145597B4-3E30-45E6-9F72-4DD43194539A}
|
||||
|
@ -250,6 +249,7 @@ Global
|
|||
{1391165D-51F1-45B4-8B7F-042A20AA0277} = {4931A385-24DC-4E78-BFF4-356F8D6D5183}
|
||||
{EB56EF94-D8A7-4111-A8E7-A87EF13596DA} = {145597B4-3E30-45E6-9F72-4DD43194539A}
|
||||
{88633C71-D701-49B3-A6DE-9D7CED9046E3} = {145597B4-3E30-45E6-9F72-4DD43194539A}
|
||||
{E3914C76-808C-48E0-B5EC-FB24DD999CCC} = {AD5B98A8-AB7F-4DA2-B66D-5B4E63E7D854}
|
||||
{73B97F6E-2BDC-40DA-84A7-7FB0264387D6} = {AD5B98A8-AB7F-4DA2-B66D-5B4E63E7D854}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
|
|
|
@ -20,7 +20,7 @@ public partial class Battery48TlRecord
|
|||
public Boolean Eoc => Leds is { Green: On, Amber: Off, Blue : Off };
|
||||
|
||||
|
||||
public String SerialNumber => $"{_SerialNum1:D4}{_SerialNum2:D4}{_SerialNum3:D4}{_SerialNum4:D4}".TrimStart('0');
|
||||
public String SerialNumber => $"{_SerialNum1:X4} {_SerialNum2:X4} {_SerialNum3:X4} {_SerialNum4:X4}".TrimStart('0');
|
||||
|
||||
public String FwVersion => _FwVersion.ToString("X4");
|
||||
public Strings Warnings => ParseWarnings().OrderBy(w => w).ToList();
|
||||
|
|
|
@ -2,7 +2,4 @@ namespace InnovEnergy.Lib.Protocols.DBus.Protocol.DataTypes.Signatures.Specializ
|
|||
|
||||
public abstract class BasicTypeSignature : Signature
|
||||
{
|
||||
|
||||
|
||||
|
||||
}
|
|
@ -176,11 +176,11 @@ public readonly struct Message
|
|||
|
||||
var raw = reader.ReadSegment((Int32)payloadLength);
|
||||
|
||||
var br = new DBusBufferReader(raw, reader.SwapEndian);
|
||||
|
||||
if (signature.IsEmpty)
|
||||
return (raw.ToArray(), true); // no signature, but data available. should probably not happen.
|
||||
|
||||
var br = new DBusBufferReader(raw, reader.SwapEndian);
|
||||
|
||||
// try
|
||||
// {
|
||||
return (signature.Read(br), false);
|
||||
|
|
|
@ -53,11 +53,11 @@ public static class Replies
|
|||
|
||||
HeaderType header =
|
||||
(
|
||||
(Byte)Env.Endianness,
|
||||
(Byte)MessageType.MethodReturn,
|
||||
(Byte)HeaderFlags.NoReplyExpected,
|
||||
(Byte) Env.Endianness,
|
||||
(Byte) MessageType.MethodReturn,
|
||||
(Byte) HeaderFlags.NoReplyExpected,
|
||||
Message.ProtocolVersion,
|
||||
(UInt32)signature.MeasureSize(payload),
|
||||
(UInt32) signature.MeasureSize(payload),
|
||||
SerialSource.Next(),
|
||||
fields
|
||||
);
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
namespace InnovEnergy.Lib.S3Utils.Data;
|
||||
|
||||
public record S3Bucket : S3RegionCredentials
|
||||
{
|
||||
public required String Bucket { get; init; }
|
||||
}
|
|
@ -0,0 +1,47 @@
|
|||
using static System.Environment;
|
||||
|
||||
namespace InnovEnergy.Lib.S3Utils.Data;
|
||||
|
||||
public record S3Credentials
|
||||
{
|
||||
protected static readonly String S3CfgFile = GetFolderPath(SpecialFolder.UserProfile).TrimEnd('\\', '/') + "/.s3cfg";
|
||||
|
||||
public required String Key { get; init; }
|
||||
public required String Secret { get; init; }
|
||||
|
||||
public static S3Credentials? FromS3Cfg() => FromFile(S3CfgFile);
|
||||
|
||||
public static S3Credentials? FromFile(String file)
|
||||
{
|
||||
// [default]
|
||||
// host_base = sos-ch-dk-2.exo.io
|
||||
// host_bucket = %(bucket)s.sos-ch-dk-2.exo.io
|
||||
// access_key = xxxxxxxxxxxxxxx
|
||||
// secret_key = xxxxxxxxxxxxxxx
|
||||
// use_https = True
|
||||
|
||||
try
|
||||
{
|
||||
var cfg = ParseFile(file);
|
||||
|
||||
return new S3Credentials
|
||||
{
|
||||
Key = cfg["access_key"],
|
||||
Secret = cfg["secret_key"]
|
||||
};
|
||||
}
|
||||
catch
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
protected static Dictionary<String, String> ParseFile(String cfgFile)
|
||||
{
|
||||
return File
|
||||
.ReadAllLines(cfgFile)
|
||||
.Where(l => l.Contains("="))
|
||||
.Select(l => l.Split("="))
|
||||
.ToDictionary(l => l[0].Trim(), l => l[1].Trim());
|
||||
}
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
namespace InnovEnergy.Lib.S3Utils.Data;
|
||||
|
||||
public record S3Path : S3Bucket
|
||||
{
|
||||
public required String Path { get; init; }
|
||||
}
|
|
@ -0,0 +1,49 @@
|
|||
using Amazon.Runtime;
|
||||
using Amazon.S3;
|
||||
using InnovEnergy.Lib.Utils;
|
||||
|
||||
namespace InnovEnergy.Lib.S3Utils.Data;
|
||||
|
||||
public record S3RegionCredentials : S3Credentials
|
||||
{
|
||||
public required String Region { get; init; }
|
||||
|
||||
private AmazonS3Client? _Client;
|
||||
internal AmazonS3Client Client => _Client ??= new AmazonS3Client
|
||||
(
|
||||
credentials: new BasicAWSCredentials(Key, Secret),
|
||||
clientConfig: new()
|
||||
{
|
||||
ServiceURL = Region.EnsureStartsWith("https://"),
|
||||
ForcePathStyle = true,
|
||||
}
|
||||
);
|
||||
|
||||
public new static S3RegionCredentials? FromS3Cfg() => FromFile(S3CfgFile);
|
||||
|
||||
public new static S3RegionCredentials? FromFile(String file)
|
||||
{
|
||||
// [default]
|
||||
// host_base = sos-ch-dk-2.exo.io
|
||||
// host_bucket = %(bucket)s.sos-ch-dk-2.exo.io
|
||||
// access_key = xxxxxxxxxxxxxxx
|
||||
// secret_key = xxxxxxxxxxxxxxx
|
||||
// use_https = True
|
||||
|
||||
try
|
||||
{
|
||||
var cfg = ParseFile(file);
|
||||
|
||||
return new S3RegionCredentials
|
||||
{
|
||||
Key = cfg["access_key"],
|
||||
Secret = cfg["secret_key"],
|
||||
Region = cfg["host_base"],
|
||||
};
|
||||
}
|
||||
catch
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
|
||||
using InnovEnergy.Lib.S3Utils.Data;
|
||||
|
||||
namespace InnovEnergy.Lib.S3Utils.ExoScale;
|
||||
|
||||
public static class DefaultCredentials
|
||||
{
|
||||
public static S3Credentials ReadOnly => new S3Credentials
|
||||
{
|
||||
Key = "EXOb6d6dc1880cdd51f1ebc6692",
|
||||
Secret = "kpIey4QJlQFuWG_WoTazcY7kBEjN2f_ll2cDBeg64m4",
|
||||
};
|
||||
|
||||
|
||||
public static S3Credentials ReadWrite => new S3Credentials
|
||||
{
|
||||
Key = "EXO87ca85e29dd412f1238f1cf0",
|
||||
Secret = "-T9TAqy9a3-0-xj7HKsFFJOCcxfRpcnL6OW5oOrOcWU",
|
||||
};
|
||||
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
namespace InnovEnergy.Lib.S3Utils.ExoScale;
|
||||
|
||||
public static class Regions
|
||||
{
|
||||
public static String Default => "sos-ch-dk-2.exo.io";
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
<?xml version="1.0" ?>
|
||||
<CORSConfiguration xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
|
||||
<CORSRule>
|
||||
<AllowedOrigin>*</AllowedOrigin>
|
||||
<AllowedMethod>GET</AllowedMethod>
|
||||
<AllowedMethod>HEAD</AllowedMethod>
|
||||
<AllowedHeader>*</AllowedHeader>
|
||||
</CORSRule>
|
||||
</CORSConfiguration>
|
|
@ -0,0 +1,4 @@
|
|||
{
|
||||
"Key": "EXO1abcb772bf43ab72951ba1dc",
|
||||
"Secret": "_ym1KsGBSp90S5dwhZn18XD-u9Y4ghHvyIxg5gv5fHw"
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"Key": "EXOb6d6dc1880cdd51f1ebc6692",
|
||||
"Secret": "kpIey4QJlQFuWG_WoTazcY7kBEjN2f_ll2cDBeg64m4",
|
||||
"Region": "sos-ch-dk-2.exo.io"
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"Key": "EXO87ca85e29dd412f1238f1cf0",
|
||||
"Secret": "-T9TAqy9a3-0-xj7HKsFFJOCcxfRpcnL6OW5oOrOcWU",
|
||||
"Region": "sos-ch-dk-2.exo.io"
|
||||
}
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,6 @@
|
|||
{
|
||||
"Url": "mail.agenturserver.de",
|
||||
"Port": 587,
|
||||
"Username": "p518526p69",
|
||||
"Password": "i;b*xqm4iB5uhl"
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
{
|
||||
"ReadOnlyS3Key": "EXO44d2979c8e570eae81ead564",
|
||||
"ReadOnlyS3Secret": "55MAqyO_FqUmh7O64VIO0egq50ERn_WIAWuc2QC44QU" ,
|
||||
"ReadWriteS3Key": "EXO87ca85e29dd412f1238f1cf0",
|
||||
"ReadWriteS3Secret": "-T9TAqy9a3-0-xj7HKsFFJOCcxfRpcnL6OW5oOrOcWU"
|
||||
}
|
|
@ -0,0 +1,90 @@
|
|||
using Amazon.S3.Model;
|
||||
using InnovEnergy.Lib.S3Utils.Data;
|
||||
using InnovEnergy.Lib.Utils;
|
||||
using S3Bucket = InnovEnergy.Lib.S3Utils.Data.S3Bucket;
|
||||
|
||||
namespace InnovEnergy.Lib.S3Utils;
|
||||
|
||||
public static class S3
|
||||
{
|
||||
public static S3RegionCredentials Region(this S3Credentials credentials, String region) => new()
|
||||
{
|
||||
Secret = credentials.Secret,
|
||||
Key = credentials.Key,
|
||||
Region = region,
|
||||
};
|
||||
|
||||
public static S3Bucket Bucket(this S3RegionCredentials region, String bucket) => new()
|
||||
{
|
||||
Region = region.Region,
|
||||
Secret = region.Secret,
|
||||
Key = region.Key,
|
||||
Bucket = bucket,
|
||||
};
|
||||
|
||||
public static S3Path Path(this S3Bucket bucket, String path) => new()
|
||||
{
|
||||
Bucket = bucket.Bucket,
|
||||
Region = bucket.Region,
|
||||
Secret = bucket.Secret,
|
||||
Key = bucket.Key,
|
||||
Path = path
|
||||
};
|
||||
|
||||
public static IAsyncEnumerable<S3Path> ListObjects(this S3Bucket bucketOrPrefixPath)
|
||||
{
|
||||
var path = bucketOrPrefixPath as S3Path ?? bucketOrPrefixPath.Path(null!);
|
||||
|
||||
var request = new ListObjectsV2Request
|
||||
{
|
||||
BucketName = path.Bucket,
|
||||
Prefix = path.Path
|
||||
};
|
||||
|
||||
return bucketOrPrefixPath
|
||||
.Client
|
||||
.Paginators
|
||||
.ListObjectsV2(request)
|
||||
.Responses
|
||||
.SelectMany(r => r.S3Objects)
|
||||
.Select(o => path with { Path = o.Key });
|
||||
}
|
||||
|
||||
public static async Task<String> GetObject(this S3Path path)
|
||||
{
|
||||
var request = new GetObjectRequest
|
||||
{
|
||||
BucketName = path.Bucket,
|
||||
Key = path.Path
|
||||
};
|
||||
|
||||
using var response = await path.Client.GetObjectAsync(request);
|
||||
await using var responseStream = response.ResponseStream;
|
||||
using var reader = new StreamReader(responseStream);
|
||||
|
||||
return await reader.ReadToEndAsync();
|
||||
}
|
||||
|
||||
public static async IAsyncEnumerable<String> GetObjectLineByLine(this S3Path path)
|
||||
{
|
||||
var request = new GetObjectRequest
|
||||
{
|
||||
BucketName = path.Bucket,
|
||||
Key = path.Path
|
||||
};
|
||||
|
||||
using var response = await path.Client.GetObjectAsync(request);
|
||||
await using var responseStream = response.ResponseStream;
|
||||
using var reader = new StreamReader(responseStream);
|
||||
|
||||
while (true)
|
||||
{
|
||||
var line = await reader.ReadLineAsync();
|
||||
|
||||
if (line is not null)
|
||||
yield return line;
|
||||
else
|
||||
yield break;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<Import Project="../InnovEnergy.Lib.props" />
|
||||
|
||||
<PropertyGroup>
|
||||
<RootNamespace>InnovEnergy.Lib.S3Utils</RootNamespace>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="../Utils/Utils.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="AWSSDK.S3" Version="3.7.203.12" />
|
||||
<PackageReference Include="System.Linq.Async" Version="6.0.1" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
|
@ -9,4 +9,8 @@
|
|||
<RootNamespace>InnovEnergy.Lib.Time</RootNamespace>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Utils\Utils.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
namespace InnovEnergy.Lib.Time.Unix;
|
||||
|
||||
public readonly partial struct UnixTime : IComparable<UnixTime>, IEquatable<UnixTime>
|
||||
{
|
||||
Int32 IComparable<UnixTime>.CompareTo(UnixTime other) => Ticks.CompareTo(other.Ticks);
|
||||
Boolean IEquatable<UnixTime>.Equals(UnixTime other) => Ticks == other.Ticks;
|
||||
}
|
||||
// namespace InnovEnergy.Lib.Time.Unix;
|
||||
//
|
||||
// public readonly partial struct UnixTime : IComparable<UnixTime>, IEquatable<UnixTime>
|
||||
// {
|
||||
// Int32 IComparable<UnixTime>.CompareTo(UnixTime other) => Ticks.CompareTo(other.Ticks);
|
||||
// Boolean IEquatable<UnixTime>.Equals(UnixTime other) => Ticks == other.Ticks;
|
||||
// }
|
|
@ -1,20 +1,19 @@
|
|||
namespace InnovEnergy.Lib.Time.Unix;
|
||||
|
||||
public readonly partial struct UnixTime
|
||||
{
|
||||
private UnixTime(UInt32 ticks) => Ticks = ticks;
|
||||
|
||||
public static UnixTime FromTicks(UInt32 ticks) => new UnixTime(ticks);
|
||||
public static UnixTime FromTicks(Int32 ticks) => new UnixTime((UInt32) ticks);
|
||||
|
||||
public static UnixTime FromUtcDateTime(DateTime dateTime)
|
||||
{
|
||||
var timeSinceEpoch = dateTime - DateTime.UnixEpoch;
|
||||
var ticks = (UInt32) timeSinceEpoch.TotalSeconds;
|
||||
|
||||
return new UnixTime(ticks);
|
||||
}
|
||||
|
||||
public static UnixTime Epoch => new UnixTime(0);
|
||||
public static UnixTime Now => FromUtcDateTime(DateTime.UtcNow);
|
||||
}
|
||||
// namespace InnovEnergy.Lib.Time.Unix;
|
||||
//
|
||||
// public readonly partial struct UnixTime
|
||||
// {
|
||||
// public static UnixTime FromTicks(Int32 ticks) => new UnixTime { Ticks = ticks };
|
||||
//
|
||||
// public static UnixTime FromUtcDateTime(DateTime dateTime)
|
||||
// {
|
||||
// var timeSinceEpoch = dateTime - DateTime.UnixEpoch;
|
||||
// var ticks = (Int32) timeSinceEpoch.TotalSeconds;
|
||||
//
|
||||
// return new UnixTime{ Ticks = ticks};
|
||||
// }
|
||||
//
|
||||
// public static UnixTime Epoch => new UnixTime { Ticks = 0 };
|
||||
// public static UnixTime Now => FromUtcDateTime(DateTime.UtcNow);
|
||||
//
|
||||
//
|
||||
// }
|
|
@ -1,9 +1,9 @@
|
|||
namespace InnovEnergy.Lib.Time.Unix;
|
||||
|
||||
public readonly partial struct UnixTime
|
||||
{
|
||||
public DateTime ToUtcDateTime() => DateTime.UnixEpoch + TimeSpan.FromSeconds(Ticks);
|
||||
|
||||
public static implicit operator DateTime(UnixTime unixTimeSpan) => unixTimeSpan.ToUtcDateTime();
|
||||
public static implicit operator UnixTime(DateTime dateTime) => FromUtcDateTime(dateTime);
|
||||
}
|
||||
// namespace InnovEnergy.Lib.Time.Unix;
|
||||
//
|
||||
// public readonly partial struct UnixTime
|
||||
// {
|
||||
// public DateTime ToUtcDateTime() => DateTime.UnixEpoch + TimeSpan.FromSeconds(Ticks);
|
||||
//
|
||||
// public static implicit operator DateTime(UnixTime unixTimeSpan) => unixTimeSpan.ToUtcDateTime();
|
||||
// public static implicit operator UnixTime(DateTime dateTime) => FromUtcDateTime(dateTime);
|
||||
// }
|
|
@ -1,20 +1,27 @@
|
|||
namespace InnovEnergy.Lib.Time.Unix;
|
||||
|
||||
public readonly partial struct UnixTime
|
||||
{
|
||||
public static UnixTime operator -(UnixTime a, UnixTimeSpan b) => FromTicks(a.Ticks - b.Ticks);
|
||||
public static UnixTime operator +(UnixTime a, UnixTimeSpan b) => FromTicks(a.Ticks + b.Ticks);
|
||||
public static UnixTime operator +(UnixTimeSpan a, UnixTime b) => FromTicks(a.Ticks + b.Ticks);
|
||||
|
||||
public static UInt32 operator /(UnixTime a, UnixTimeSpan b) => a.Ticks / b.Ticks;
|
||||
public static UInt32 operator %(UnixTime a, UnixTimeSpan b) => a.Ticks % b.Ticks;
|
||||
|
||||
public static Boolean operator < (UnixTime l, UnixTime r) => l.Ticks < r.Ticks;
|
||||
public static Boolean operator > (UnixTime l, UnixTime r) => l.Ticks > r.Ticks;
|
||||
public static Boolean operator <= (UnixTime l, UnixTime r) => l.Ticks <= r.Ticks;
|
||||
public static Boolean operator >= (UnixTime l, UnixTime r) => l.Ticks >= r.Ticks;
|
||||
public static Boolean operator == (UnixTime l, UnixTime r) => l.Ticks == r.Ticks;
|
||||
public static Boolean operator != (UnixTime l, UnixTime r) => l.Ticks != r.Ticks;
|
||||
|
||||
public static UnixTimeSpan operator -(UnixTime a, UnixTime b) => UnixTimeSpan.FromTicks(a.Ticks - b.Ticks);
|
||||
}
|
||||
// using InnovEnergy.Lib.Utils;
|
||||
//
|
||||
// namespace InnovEnergy.Lib.Time.Unix;
|
||||
//
|
||||
// public readonly partial struct UnixTime
|
||||
// {
|
||||
// public static UnixTime operator -(UnixTime a, TimeSpan b) => FromTicks(a.Ticks - GetUnixTicks(b));
|
||||
// public static UnixTime operator +(UnixTime a, TimeSpan b) => FromTicks(a.Ticks + GetUnixTicks(b));
|
||||
// public static UnixTime operator +(TimeSpan a, UnixTime b) => FromTicks(GetUnixTicks(a) + b.Ticks);
|
||||
//
|
||||
// public static Double operator /(UnixTime a, TimeSpan b) => a.Ticks.ConvertTo<Double>() / b.Ticks;
|
||||
// public static Int32 operator %(UnixTime a, TimeSpan b) => a.Ticks % GetUnixTicks(b);
|
||||
//
|
||||
// public static Boolean operator < (UnixTime l, UnixTime r) => l.Ticks < r.Ticks;
|
||||
// public static Boolean operator > (UnixTime l, UnixTime r) => l.Ticks > r.Ticks;
|
||||
// public static Boolean operator <= (UnixTime l, UnixTime r) => l.Ticks <= r.Ticks;
|
||||
// public static Boolean operator >= (UnixTime l, UnixTime r) => l.Ticks >= r.Ticks;
|
||||
// public static Boolean operator == (UnixTime l, UnixTime r) => l.Ticks == r.Ticks;
|
||||
// public static Boolean operator != (UnixTime l, UnixTime r) => l.Ticks != r.Ticks;
|
||||
//
|
||||
// public static TimeSpan operator -(UnixTime a, UnixTime b) => TimeSpan.FromSeconds(a.Ticks - b.Ticks);
|
||||
//
|
||||
// private static Int32 GetUnixTicks(TimeSpan ts)
|
||||
// {
|
||||
// return (Int32) (ts.Ticks / 10000000L);
|
||||
// }
|
||||
// }
|
|
@ -1,8 +1,8 @@
|
|||
namespace InnovEnergy.Lib.Time.Unix;
|
||||
|
||||
public readonly partial struct UnixTime
|
||||
{
|
||||
public override Boolean Equals(Object? obj) => obj is UnixTime other && Ticks == other.Ticks;
|
||||
public override Int32 GetHashCode() => (Int32) (Ticks & 0x7F_FF_FF_FF);
|
||||
public override String ToString() => Ticks.ToString();
|
||||
}
|
||||
// namespace InnovEnergy.Lib.Time.Unix;
|
||||
//
|
||||
// public readonly partial struct UnixTime
|
||||
// {
|
||||
// public override Boolean Equals(Object? obj) => obj is UnixTime other && Ticks == other.Ticks;
|
||||
// public override Int32 GetHashCode() => (Int32) (Ticks & 0x7F_FF_FF_FF);
|
||||
// public override String ToString() => Ticks.ToString();
|
||||
// }
|
|
@ -1,14 +1,6 @@
|
|||
|
||||
|
||||
// ReSharper disable ArrangeStaticMemberQualifier
|
||||
|
||||
namespace InnovEnergy.Lib.Time.Unix;
|
||||
|
||||
public readonly partial struct UnixTime
|
||||
{
|
||||
// IMPORTANT: init is necessary for JSON deserializer
|
||||
// ReSharper disable once AutoPropertyCanBeMadeGetOnly.Global
|
||||
public UInt32 Ticks { get; init; }
|
||||
|
||||
public UnixTime RoundTo(UnixTimeSpan span) => Epoch + this / span * span;
|
||||
}
|
||||
// namespace InnovEnergy.Lib.Time.Unix;
|
||||
//
|
||||
// public readonly partial struct UnixTime
|
||||
// {
|
||||
// public required Int32 Ticks { get; init; }
|
||||
// }
|
|
@ -1,7 +0,0 @@
|
|||
namespace InnovEnergy.Lib.Time.Unix;
|
||||
|
||||
public readonly partial struct UnixTimeSpan : IComparable<UnixTimeSpan>, IEquatable<UnixTimeSpan>
|
||||
{
|
||||
Int32 IComparable<UnixTimeSpan>.CompareTo(UnixTimeSpan other) => Ticks.CompareTo(other.Ticks);
|
||||
Boolean IEquatable<UnixTimeSpan>.Equals(UnixTimeSpan other) => Ticks == other.Ticks;
|
||||
}
|
|
@ -1,26 +0,0 @@
|
|||
namespace InnovEnergy.Lib.Time.Unix;
|
||||
|
||||
public readonly partial struct UnixTimeSpan
|
||||
{
|
||||
private UnixTimeSpan(UInt32 ticks) => Ticks = ticks;
|
||||
|
||||
public static UnixTimeSpan FromTicks(UInt32 ticks) => new UnixTimeSpan(ticks);
|
||||
|
||||
public static UnixTimeSpan FromTimeSpan(TimeSpan timeSpan)
|
||||
{
|
||||
var ticks = (UInt32) timeSpan.TotalSeconds;
|
||||
return FromTicks(ticks);
|
||||
}
|
||||
|
||||
public static UnixTimeSpan FromSeconds(UInt32 s) => FromTicks (s);
|
||||
public static UnixTimeSpan FromMinutes(UInt32 m) => FromSeconds(m * 60);
|
||||
public static UnixTimeSpan FromHours (UInt32 h) => FromMinutes(h * 60);
|
||||
public static UnixTimeSpan FromDays (UInt32 d) => FromHours (d * 24);
|
||||
public static UnixTimeSpan FromWeeks (UInt32 w) => FromDays (w * 7);
|
||||
|
||||
public static UnixTimeSpan FromSeconds(Int32 s) => FromSeconds((UInt32) s);
|
||||
public static UnixTimeSpan FromMinutes(Int32 m) => FromMinutes((UInt32) m);
|
||||
public static UnixTimeSpan FromHours (Int32 h) => FromHours ((UInt32) h);
|
||||
public static UnixTimeSpan FromDays (Int32 d) => FromDays ((UInt32) d);
|
||||
public static UnixTimeSpan FromWeeks (Int32 w) => FromWeeks ((UInt32) w);
|
||||
}
|
|
@ -1,9 +0,0 @@
|
|||
namespace InnovEnergy.Lib.Time.Unix;
|
||||
|
||||
public readonly partial struct UnixTimeSpan
|
||||
{
|
||||
public TimeSpan ToTimeSpan() => TimeSpan.FromSeconds(Ticks);
|
||||
|
||||
public static implicit operator TimeSpan(UnixTimeSpan unixTimeSpan) => unixTimeSpan.ToTimeSpan();
|
||||
public static implicit operator UnixTimeSpan(TimeSpan timeSpan) => FromTimeSpan(timeSpan);
|
||||
}
|
|
@ -1,29 +0,0 @@
|
|||
namespace InnovEnergy.Lib.Time.Unix;
|
||||
|
||||
public readonly partial struct UnixTimeSpan
|
||||
{
|
||||
public static Boolean operator < (UnixTimeSpan l, UnixTimeSpan r) => l.Ticks < r.Ticks;
|
||||
public static Boolean operator > (UnixTimeSpan l, UnixTimeSpan r) => l.Ticks > r.Ticks;
|
||||
public static Boolean operator <= (UnixTimeSpan l, UnixTimeSpan r) => l.Ticks <= r.Ticks;
|
||||
public static Boolean operator >= (UnixTimeSpan l, UnixTimeSpan r) => l.Ticks >= r.Ticks;
|
||||
public static Boolean operator == (UnixTimeSpan l, UnixTimeSpan r) => l.Ticks == r.Ticks;
|
||||
public static Boolean operator != (UnixTimeSpan l, UnixTimeSpan r) => l.Ticks != r.Ticks;
|
||||
|
||||
public static UnixTimeSpan operator +(UnixTimeSpan a, UnixTimeSpan b) => new UnixTimeSpan(a.Ticks + b.Ticks);
|
||||
public static UnixTimeSpan operator -(UnixTimeSpan a, UnixTimeSpan b) => new UnixTimeSpan(a.Ticks - b.Ticks);
|
||||
|
||||
public static UnixTimeSpan operator *(UnixTimeSpan a, UInt32 b) => new UnixTimeSpan(a.Ticks * b);
|
||||
public static UnixTimeSpan operator *(UnixTimeSpan a, Int32 b) => new UnixTimeSpan(a.Ticks * (UInt32) b);
|
||||
|
||||
public static UnixTimeSpan operator *(UInt32 a, UnixTimeSpan b) => new UnixTimeSpan(a * b.Ticks);
|
||||
public static UnixTimeSpan operator *(Int32 a, UnixTimeSpan b) => new UnixTimeSpan((UInt32) a * b.Ticks);
|
||||
|
||||
public static UnixTimeSpan operator /(UnixTimeSpan a, UInt32 b) => new UnixTimeSpan(a.Ticks / b);
|
||||
public static UnixTimeSpan operator /(UnixTimeSpan a, Int32 b) => new UnixTimeSpan(a.Ticks / (UInt32)b);
|
||||
public static UInt32 operator /(UnixTimeSpan a, UnixTimeSpan b) => a.Ticks / b.Ticks;
|
||||
|
||||
public static UnixTimeSpan operator %(UnixTimeSpan a, UInt32 b) => new UnixTimeSpan(a.Ticks % b);
|
||||
public static UnixTimeSpan operator %(UnixTimeSpan a, Int32 b) => new UnixTimeSpan(a.Ticks % (UInt32)b);
|
||||
public static UInt32 operator %(UnixTimeSpan a, UnixTimeSpan b) => a.Ticks % b.Ticks;
|
||||
|
||||
}
|
|
@ -1,50 +0,0 @@
|
|||
using System.Text;
|
||||
|
||||
namespace InnovEnergy.Lib.Time.Unix;
|
||||
|
||||
public readonly partial struct UnixTimeSpan
|
||||
{
|
||||
public override String ToString()
|
||||
{
|
||||
var sb = new StringBuilder();
|
||||
var dt = ToTimeSpan();
|
||||
|
||||
var weeks = dt.Days / 7;
|
||||
var days = dt.Days % 7;
|
||||
|
||||
if (weeks > 0)
|
||||
{
|
||||
sb.Append(weeks);
|
||||
sb.Append("w ");
|
||||
}
|
||||
if (days > 0)
|
||||
{
|
||||
sb.Append(days);
|
||||
sb.Append("d ");
|
||||
}
|
||||
if (dt.Hours > 0)
|
||||
{
|
||||
sb.Append(dt.Hours);
|
||||
sb.Append("h ");
|
||||
}
|
||||
if (dt.Minutes > 0)
|
||||
{
|
||||
sb.Append(dt.Minutes);
|
||||
sb.Append("m ");
|
||||
}
|
||||
if (dt.Seconds > 0)
|
||||
{
|
||||
sb.Append(dt.Seconds);
|
||||
sb.Append("s");
|
||||
}
|
||||
|
||||
return sb.ToString().Trim();
|
||||
}
|
||||
|
||||
public override Boolean Equals(Object? obj) => obj is UnixTime other && Ticks == other.Ticks;
|
||||
|
||||
public override Int32 GetHashCode() => (Int32) (Ticks & 0x7F_FF_FF_FF);
|
||||
|
||||
public static UnixTimeSpan Forever { get; } = FromTicks(UInt32.MaxValue) / 1.Weeks() * 1.Weeks();
|
||||
|
||||
}
|
|
@ -1,8 +0,0 @@
|
|||
namespace InnovEnergy.Lib.Time.Unix;
|
||||
|
||||
public readonly partial struct UnixTimeSpan
|
||||
{
|
||||
public UInt32 Ticks { get; }
|
||||
|
||||
|
||||
}
|
|
@ -1,16 +0,0 @@
|
|||
namespace InnovEnergy.Lib.Time.Unix;
|
||||
|
||||
public static class UnixTimeSpanExtensions
|
||||
{
|
||||
public static UnixTimeSpan Seconds(this Int32 s) => UnixTimeSpan.FromSeconds(s);
|
||||
public static UnixTimeSpan Minutes(this Int32 m) => UnixTimeSpan.FromMinutes(m);
|
||||
public static UnixTimeSpan Hours (this Int32 h) => UnixTimeSpan.FromHours (h);
|
||||
public static UnixTimeSpan Days (this Int32 d) => UnixTimeSpan.FromDays (d);
|
||||
public static UnixTimeSpan Weeks (this Int32 w) => UnixTimeSpan.FromWeeks (w);
|
||||
|
||||
public static UnixTimeSpan Seconds(this UInt32 s) => UnixTimeSpan.FromSeconds(s);
|
||||
public static UnixTimeSpan Minutes(this UInt32 m) => UnixTimeSpan.FromMinutes(m);
|
||||
public static UnixTimeSpan Hours (this UInt32 h) => UnixTimeSpan.FromHours (h);
|
||||
public static UnixTimeSpan Days (this UInt32 d) => UnixTimeSpan.FromDays (d);
|
||||
public static UnixTimeSpan Weeks (this UInt32 w) => UnixTimeSpan.FromWeeks (w);
|
||||
}
|
|
@ -8,7 +8,6 @@
|
|||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="../Utils/Utils.csproj" />
|
||||
<ProjectReference Include="../Time/Time.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<!-- <Target Name="PreBuild" BeforeTargets="PreBuildEvent">-->
|
||||
|
|
|
@ -5,6 +5,12 @@ namespace InnovEnergy.Lib.Utils;
|
|||
public static class AsyncEnumerableEx
|
||||
{
|
||||
|
||||
public static IAsyncEnumerable<R> SelectMany<T, R>(this IAsyncEnumerable<T> ts, Func<T, IEnumerable<R>> map)
|
||||
{
|
||||
return ts.SelectMany<T, R>(t => map(t).ToAsyncEnumerable());
|
||||
}
|
||||
|
||||
|
||||
public static async IAsyncEnumerable<T> Throttle<T>(this IAsyncEnumerable<T> ts,
|
||||
TimeSpan dueTime,
|
||||
[EnumeratorCancellation] CancellationToken cancel = default)
|
||||
|
|
|
@ -0,0 +1,38 @@
|
|||
namespace InnovEnergy.Lib.Utils;
|
||||
|
||||
public static class DateTimeUtils
|
||||
{
|
||||
public static DateTime Epoch { get; } = new DateTime
|
||||
(
|
||||
year: 1970,
|
||||
month: 1,
|
||||
day: 1,
|
||||
hour: 0,
|
||||
minute: 0,
|
||||
second: 0,
|
||||
DateTimeKind.Utc
|
||||
);
|
||||
|
||||
public static Int64 ToUnixTime(this DateTime dateTime)
|
||||
{
|
||||
var timeSinceEpoch = dateTime.ToUniversalTime() - Epoch;
|
||||
return timeSinceEpoch.Ticks / TimeSpan.TicksPerSecond;
|
||||
}
|
||||
|
||||
public static DateTime DateTimeFromUnixTime(this IConvertible unixTime)
|
||||
{
|
||||
var epochTicks = Epoch.Ticks + unixTime.ConvertTo<Double>() * TimeSpan.TicksPerSecond;
|
||||
|
||||
return new DateTime(epochTicks.ConvertTo<Int64>(), DateTimeKind.Utc);
|
||||
}
|
||||
|
||||
public static DateTime Round(this DateTime date, TimeSpan interval)
|
||||
{
|
||||
var i = interval.Ticks;
|
||||
var t = date.Ticks;
|
||||
|
||||
var intervalTicks = (t + i / 2 + 1) / i * i;
|
||||
|
||||
return new DateTime(intervalTicks, date.Kind);
|
||||
}
|
||||
}
|
|
@ -6,7 +6,7 @@ public static class GraphTraversal
|
|||
{
|
||||
public static IEnumerable<T> TraverseDepthFirstPreOrder<T>(T root,
|
||||
Func<T, IEnumerable<T>> getChildren,
|
||||
IEqualityComparer<T>? comparer = null)
|
||||
IEqualityComparer<T>? comparer = null)
|
||||
{
|
||||
return Traverse(root, TreeTraversal.TraverseDepthFirstPreOrder, getChildren, comparer);
|
||||
}
|
||||
|
@ -14,7 +14,7 @@ IEqualityComparer<T>? comparer = null)
|
|||
|
||||
public static IEnumerable<T> TraverseDepthFirstPostOrder<T>(T root,
|
||||
Func<T, IEnumerable<T>> getChildren,
|
||||
IEqualityComparer<T>? comparer = null)
|
||||
IEqualityComparer<T>? comparer = null)
|
||||
{
|
||||
return Traverse(root, TreeTraversal.TraverseDepthFirstPostOrder, getChildren, comparer);
|
||||
}
|
||||
|
@ -28,7 +28,7 @@ IEqualityComparer<T>? comparer = null)
|
|||
|
||||
public static IEnumerable<T> TraverseDepthFirstPreOrder<T>(IEnumerable<T> sources,
|
||||
Func<T, IEnumerable<T>> getChildren,
|
||||
IEqualityComparer<T>? comparer = null)
|
||||
IEqualityComparer<T>? comparer = null)
|
||||
{
|
||||
return Traverse(sources, TreeTraversal.TraverseDepthFirstPreOrder, getChildren, comparer);
|
||||
}
|
||||
|
@ -36,14 +36,14 @@ IEqualityComparer<T>? comparer = null)
|
|||
|
||||
public static IEnumerable<T> TraverseDepthFirstPostOrder<T>(IEnumerable<T> sources,
|
||||
Func<T, IEnumerable<T>> getChildren,
|
||||
IEqualityComparer<T>? comparer = null)
|
||||
IEqualityComparer<T>? comparer = null)
|
||||
{
|
||||
return Traverse(sources, TreeTraversal.TraverseDepthFirstPostOrder, getChildren, comparer);
|
||||
}
|
||||
|
||||
public static IEnumerable<T> TraverseBreadthFirst<T>(IEnumerable<T> sources,
|
||||
Func<T, IEnumerable<T>> getChildren,
|
||||
IEqualityComparer<T>? comparer = null)
|
||||
IEqualityComparer<T>? comparer = null)
|
||||
{
|
||||
return Traverse(sources, TreeTraversal.TraverseBreadthFirst, getChildren, comparer);
|
||||
}
|
||||
|
@ -52,7 +52,7 @@ IEqualityComparer<T>? comparer = null)
|
|||
private static IEnumerable<T> Traverse<T>(T root,
|
||||
Func<T , Func<T, IEnumerable<T>>,IEnumerable<T>> traversor,
|
||||
Func<T, IEnumerable<T>> getChildren,
|
||||
IEqualityComparer<T>? comparer = null)
|
||||
IEqualityComparer<T>? comparer = null)
|
||||
{
|
||||
var getUniqueChildren = GetUniqueChildren(getChildren, root, comparer);
|
||||
return traversor(root, getUniqueChildren);
|
||||
|
@ -98,15 +98,15 @@ IEqualityComparer<T>? comparer = null)
|
|||
}
|
||||
|
||||
private static Func<T, IEnumerable<T>> GetUniqueChildren<T>(Func<T, IEnumerable<T>> getChildren,
|
||||
T root,
|
||||
IEqualityComparer<T>? comparer)
|
||||
T root,
|
||||
IEqualityComparer<T>? comparer)
|
||||
{
|
||||
return GetUniqueChildren(getChildren, root.AsSingleEnumerable(), comparer);
|
||||
}
|
||||
|
||||
private static Func<T, IEnumerable<T>> GetUniqueChildren<T>(Func<T, IEnumerable<T>> getChildren,
|
||||
IEnumerable<T> sources,
|
||||
IEqualityComparer<T>? comparer)
|
||||
IEnumerable<T> sources,
|
||||
IEqualityComparer<T>? comparer)
|
||||
{
|
||||
var set = new HashSet<T>(sources, comparer ?? EqualityComparer<T>.Default);
|
||||
return n => getChildren(n).Where(set.Add);
|
||||
|
|
|
@ -2,20 +2,7 @@ namespace InnovEnergy.Lib.Utils;
|
|||
|
||||
public static class NullableUtils
|
||||
{
|
||||
public static T? Nullable<T>(this T t) where T : struct => t;
|
||||
// ReSharper disable once ReturnTypeCanBeNotNullable
|
||||
public static T? AsNullable<T>(this T t) => t;
|
||||
|
||||
public static IEnumerable<T> Enumerable<T>(this T? t) where T : struct
|
||||
{
|
||||
if (t.HasValue)
|
||||
yield return t.Value;
|
||||
}
|
||||
|
||||
|
||||
public static T ThrowIfNull<T>(this T? t, String message) where T:struct
|
||||
{
|
||||
if (!t.HasValue)
|
||||
throw new NullReferenceException(message);
|
||||
|
||||
return t.Value;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
using System.Diagnostics.CodeAnalysis;
|
||||
|
||||
namespace InnovEnergy.Lib.Utils;
|
||||
|
||||
public static class NullableUtilsClass
|
||||
{
|
||||
public static IEnumerable<T> ToEnumerable<T>(this T? t) where T : class
|
||||
{
|
||||
if (t is not null)
|
||||
yield return t;
|
||||
}
|
||||
|
||||
public static T ThrowIfNull<T>(this T? t) where T : class => ThrowIfNull(t, null);
|
||||
|
||||
public static T ThrowIfNull<T>(this T? t, String? message) where T : class
|
||||
{
|
||||
if (t is null)
|
||||
throw new NullReferenceException(message);
|
||||
|
||||
return t;
|
||||
}
|
||||
|
||||
public static Boolean IsNull<T>([NotNullWhen(returnValue: false)] this T? t) where T : class => t is null;
|
||||
|
||||
public static T? As<T>(this Object t) where T : class => t as T;
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
using System.Diagnostics.CodeAnalysis;
|
||||
|
||||
namespace InnovEnergy.Lib.Utils;
|
||||
|
||||
public static class NullableUtilsStruct
|
||||
{
|
||||
public static IEnumerable<T> ToEnumerable<T>(this T? t) where T : struct
|
||||
{
|
||||
if (t.HasValue)
|
||||
yield return t.Value;
|
||||
}
|
||||
|
||||
public static T ThrowIfNull<T>(this T? t) where T : struct => ThrowIfNull(t, null);
|
||||
|
||||
public static T ThrowIfNull<T>(this T? t, String? message) where T : struct
|
||||
{
|
||||
if (!t.HasValue)
|
||||
throw new NullReferenceException(message);
|
||||
|
||||
return t.Value;
|
||||
}
|
||||
|
||||
public static Boolean IsNull<T>([NotNullWhen(returnValue: false)] this T? t) where T : struct => t.HasValue;
|
||||
}
|
|
@ -0,0 +1,104 @@
|
|||
namespace InnovEnergy.Lib.Utils;
|
||||
|
||||
|
||||
// TODO: discriminated union
|
||||
public abstract record Result<T>
|
||||
{
|
||||
public sealed record Success(T Value) : Result<T>;
|
||||
public sealed record Failure(String Error) : Result<T>;
|
||||
|
||||
public Boolean IsError => this is Failure;
|
||||
public Boolean IsOk => this is Success;
|
||||
|
||||
public static implicit operator Result<T>(T t) => new Success(t);
|
||||
public static implicit operator Result<T>(String e) => new Failure(e);
|
||||
}
|
||||
|
||||
public abstract record Result<T, E>
|
||||
{
|
||||
public sealed record Success(T Value) : Result<T, E>;
|
||||
public sealed record Failure(E Error) : Result<T, E>;
|
||||
|
||||
public Boolean IsError => this is Failure;
|
||||
public Boolean IsOk => this is Success;
|
||||
|
||||
public static implicit operator Result<T, E>(T t) => new Success(t);
|
||||
public static implicit operator Result<T, E>(E e) => new Failure(e);
|
||||
|
||||
public R Map<R>(Func<T, R> onSuccess, Func<E, R> onFailure) => this switch
|
||||
{
|
||||
Success s => onSuccess(s.Value),
|
||||
Failure f => onFailure(f.Error),
|
||||
_ => throw new ArgumentOutOfRangeException()
|
||||
};
|
||||
|
||||
public Result<R, E> OnSuccess<R>(Func<T, R> onOk) => this switch
|
||||
{
|
||||
Success s => onOk(s.Value),
|
||||
Failure f => f.Error,
|
||||
_ => throw new ArgumentOutOfRangeException()
|
||||
};
|
||||
|
||||
public Result<T, R> OnFailure<R>(Func<E, R> onError) => this switch
|
||||
{
|
||||
Success s => s.Value,
|
||||
Failure f => onError(f.Error),
|
||||
_ => throw new ArgumentOutOfRangeException()
|
||||
};
|
||||
}
|
||||
|
||||
public static class Result
|
||||
{
|
||||
public static Result<T, Exception> Try<T>(Func<T> func)
|
||||
{
|
||||
try
|
||||
{
|
||||
return func();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
return e;
|
||||
}
|
||||
}
|
||||
|
||||
public static String? GetError<T>(this Result<T> r)
|
||||
{
|
||||
return r is Result<T>.Failure err
|
||||
? err.Error
|
||||
: null;
|
||||
}
|
||||
}
|
||||
|
||||
public static class ResultClass
|
||||
{
|
||||
public static T? GetValue<T>(this Result<T> r) where T : class
|
||||
{
|
||||
return r is Result<T>.Success ok
|
||||
? ok.Value
|
||||
: null;
|
||||
}
|
||||
|
||||
public static E? GetError<T, E>(this Result<T, E> r) where E : class
|
||||
{
|
||||
return r is Result<T, E>.Failure err
|
||||
? err.Error
|
||||
: null;
|
||||
}
|
||||
}
|
||||
|
||||
public static class ResultStruct
|
||||
{
|
||||
public static T? GetValue<T>(this Result<T> r) where T : struct
|
||||
{
|
||||
return r is Result<T>.Success ok
|
||||
? ok.Value
|
||||
: null;
|
||||
}
|
||||
|
||||
public static E? GetError<T, E>(this Result<T, E> r) where E : struct
|
||||
{
|
||||
return r is Result<T,E>.Failure err
|
||||
? err.Error
|
||||
: null;
|
||||
}
|
||||
}
|
|
@ -376,5 +376,10 @@ public static class StringUtils
|
|||
return $"{prefix}{target.TrimStart(prefix)}";
|
||||
}
|
||||
|
||||
public static String EnsureEndsWith(this String target, String postfix)
|
||||
{
|
||||
return $"{target.TrimEnd(postfix)}{postfix}";
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -6,9 +6,10 @@ using static System.Runtime.CompilerServices.MethodImplOptions;
|
|||
|
||||
namespace InnovEnergy.Lib.Utils;
|
||||
|
||||
|
||||
public static class Utils
|
||||
{
|
||||
public static Boolean IsNull<T>([NotNullWhen(returnValue: false)] this T t) => t is null;
|
||||
|
||||
|
||||
public static IEnumerable<String> GetEnumStrings<T>(this T e) where T : Enum
|
||||
{
|
||||
|
@ -169,9 +170,5 @@ public static class Utils
|
|||
CopyFilesRecursively(dir, target.CreateSubdirectory(dir.Name));
|
||||
}
|
||||
|
||||
|
||||
public static String ExecutingProcessName => Process.GetCurrentProcess().ProcessName;
|
||||
|
||||
|
||||
|
||||
}
|
|
@ -1,8 +1,4 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<Configurations>Debug;Release;Release-Server</Configurations>
|
||||
<Platforms>AnyCPU;linux-arm</Platforms>
|
||||
</PropertyGroup>
|
||||
<Import Project="../InnovEnergy.Lib.props" />
|
||||
|
||||
<PropertyGroup>
|
||||
|
@ -12,6 +8,7 @@
|
|||
<ItemGroup>
|
||||
<PackageReference Include="CliWrap" Version="3.6.0" />
|
||||
<PackageReference Include="DecimalMath.DecimalEx" Version="1.0.2" />
|
||||
<PackageReference Include="System.Linq.Async" Version="6.0.1" />
|
||||
<PackageReference Include="System.Reactive.Linq" Version="5.0.0" />
|
||||
</ItemGroup>
|
||||
|
||||
|
|
|
@ -1,9 +0,0 @@
|
|||
namespace InnovEnergy.Lib.Utils.WIP;
|
||||
|
||||
|
||||
// TODO: discriminated union
|
||||
public abstract record Result
|
||||
{
|
||||
public sealed record Ok(Object Result) : Result;
|
||||
public sealed record Error(String Message) : Result;
|
||||
}
|
|
@ -1,5 +1,4 @@
|
|||
using System.Text.Json.Nodes;
|
||||
using InnovEnergy.Lib.Time.Unix;
|
||||
using InnovEnergy.Lib.Utils;
|
||||
|
||||
// ReSharper disable StringLiteralTypo
|
||||
|
@ -10,7 +9,7 @@ public readonly partial record struct Installation(VrmAccount VrmAccount, JsonNo
|
|||
{
|
||||
|
||||
public UInt64 IdSite => Json.GetUInt64("idSite");
|
||||
public UnixTime Created => Json.GetUInt32("syscreated").Apply(UnixTime.FromTicks);
|
||||
public UInt32 Created => Json.GetUInt32("syscreated");
|
||||
|
||||
// Settings
|
||||
|
||||
|
|
|
@ -17,7 +17,6 @@
|
|||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="../../Utils/Utils.csproj" />
|
||||
<ProjectReference Include="../../Time/Time.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
|
|
@ -13,7 +13,6 @@ public static class HttpExtensions
|
|||
return headers
|
||||
.AllKeys
|
||||
.EmptyIfNull()
|
||||
.Where(k => k != null)
|
||||
.Select(k => new HttpHeader(k!, headers[k]!));
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue