Merge remote-tracking branch 'origin/main'
This commit is contained in:
commit
965a85ba81
|
@ -13,7 +13,7 @@
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="System.Linq.Async" Version="5.0.0" />
|
<PackageReference Include="System.Linq.Async" Version="6.0.1" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
|
|
@ -134,7 +134,7 @@ public static class Program
|
||||||
var company = x.LastOrDefault()?.Split('(').FirstOrDefault()?.Trim() ?? "";
|
var company = x.LastOrDefault()?.Split('(').FirstOrDefault()?.Trim() ?? "";
|
||||||
var sn = x.LastOrDefault()?.Split('(').LastOrDefault()?.Trim("() ".ToCharArray()) ?? "";
|
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[]
|
var line = new[]
|
||||||
{
|
{
|
||||||
|
|
|
@ -18,7 +18,6 @@
|
||||||
<ProjectReference Include="../../Lib/Devices/Trumpf/SystemControl/SystemControl.csproj" />
|
<ProjectReference Include="../../Lib/Devices/Trumpf/SystemControl/SystemControl.csproj" />
|
||||||
<ProjectReference Include="../../Lib/Devices/Trumpf/TruConvertAc/TruConvertAc.csproj" />
|
<ProjectReference Include="../../Lib/Devices/Trumpf/TruConvertAc/TruConvertAc.csproj" />
|
||||||
<ProjectReference Include="../../Lib/Devices/Trumpf/TruConvertDc/TruConvertDc.csproj" />
|
<ProjectReference Include="../../Lib/Devices/Trumpf/TruConvertDc/TruConvertDc.csproj" />
|
||||||
<ProjectReference Include="../../Lib/Time/Time.csproj" />
|
|
||||||
<ProjectReference Include="../../Lib/Units/Units.csproj" />
|
<ProjectReference Include="../../Lib/Units/Units.csproj" />
|
||||||
<ProjectReference Include="../../Lib/Utils/Utils.csproj" />
|
<ProjectReference Include="../../Lib/Utils/Utils.csproj" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
|
@ -3,11 +3,10 @@ Description=Battery48TL_TCP_Bridge
|
||||||
|
|
||||||
[Service]
|
[Service]
|
||||||
Type=simple
|
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
|
ExecStart=socat -x -d -d TCP-LISTEN:6855 GOPEN:/dev/ttyUSB0,rawer,b115200,cs8,parenb=1,parodd=1
|
||||||
Restart=always
|
Restart=always
|
||||||
RestartSec=500ms
|
RestartSec=500ms
|
||||||
|
StartLimitInterval=0
|
||||||
|
|
||||||
[Install]
|
[Install]
|
||||||
WantedBy=multi-user.target
|
WantedBy=multi-user.target
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
using InnovEnergy.Lib.Time.Unix;
|
using InnovEnergy.Lib.Utils;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
|
|
||||||
namespace InnovEnergy.App.SaliMax;
|
namespace InnovEnergy.App.SaliMax;
|
||||||
|
@ -37,7 +37,7 @@ public class CustomLogger : ILogger
|
||||||
File.AppendAllText(_LogFilePath, logMessage + Environment.NewLine);
|
File.AppendAllText(_LogFilePath, logMessage + Environment.NewLine);
|
||||||
_CurrentFileSizeBytes += logMessage.Length;
|
_CurrentFileSizeBytes += logMessage.Length;
|
||||||
|
|
||||||
Console.WriteLine(logMessage);
|
//Console.WriteLine(logMessage);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void RotateLogFile()
|
private void RotateLogFile()
|
||||||
|
@ -56,7 +56,7 @@ public class CustomLogger : ILogger
|
||||||
File.Delete(logFiles.First());
|
File.Delete(logFiles.First());
|
||||||
|
|
||||||
// Rename the current log file with a timestamp
|
// 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);
|
File.Move(_LogFilePath, logFileBackupPath);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,9 +6,9 @@ public static class Logger
|
||||||
{
|
{
|
||||||
// Specify the maximum log file size in bytes (e.g., 1 MB)
|
// 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 MaxFileSizeBytes = 1024 * 21; // TODO: move to settings
|
||||||
private const Int32 MaxLogFileCount = 1000; // TODO: move to settings
|
private const Int32 MaxLogFileCount = 5000; // TODO: move to settings
|
||||||
private const String LogFilePath = "LogDirectory/log.txt"; // TODO: move to settings
|
private const String LogFilePath = "LogDirectory/log.csv"; // TODO: move to settings
|
||||||
|
|
||||||
// ReSharper disable once InconsistentNaming
|
// ReSharper disable once InconsistentNaming
|
||||||
private static readonly ILogger _logger = new CustomLogger(LogFilePath, MaxFileSizeBytes, MaxLogFileCount);
|
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;
|
||||||
using InnovEnergy.Lib.Devices.Trumpf.TruConvertDc.Control;
|
using InnovEnergy.Lib.Devices.Trumpf.TruConvertDc.Control;
|
||||||
using InnovEnergy.Lib.Protocols.Modbus.Channels;
|
using InnovEnergy.Lib.Protocols.Modbus.Channels;
|
||||||
using InnovEnergy.Lib.Time.Unix;
|
|
||||||
using InnovEnergy.Lib.Units;
|
using InnovEnergy.Lib.Units;
|
||||||
using InnovEnergy.Lib.Utils;
|
using InnovEnergy.Lib.Utils;
|
||||||
using static InnovEnergy.Lib.Devices.Trumpf.SystemControl.DataTypes.SystemConfig;
|
using static InnovEnergy.Lib.Devices.Trumpf.SystemControl.DataTypes.SystemConfig;
|
||||||
|
|
||||||
|
|
||||||
#pragma warning disable IL2026
|
#pragma warning disable IL2026
|
||||||
|
|
||||||
namespace InnovEnergy.App.SaliMax;
|
namespace InnovEnergy.App.SaliMax;
|
||||||
|
|
||||||
internal static class Program
|
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;
|
private static readonly IReadOnlyList<Byte> BatteryNodes;
|
||||||
|
|
||||||
|
@ -148,9 +148,9 @@ internal static class Program
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
await Observable
|
await Observable
|
||||||
.Interval(UpdateInterval.ToTimeSpan())
|
.Interval(UpdateInterval)
|
||||||
.Select(_ => RunIteration())
|
.Select(_ => RunIteration())
|
||||||
.SelectMany(r => UploadCsv(r, UnixTime.Now.RoundTo(UpdateInterval)))
|
.SelectMany(r => UploadCsv(r, DateTime.UtcNow))
|
||||||
.SelectError()
|
.SelectError()
|
||||||
.ToTask();
|
.ToTask();
|
||||||
}
|
}
|
||||||
|
@ -172,13 +172,14 @@ internal static class Program
|
||||||
var record = ReadStatus();
|
var record = ReadStatus();
|
||||||
|
|
||||||
// If control Special Error return true, we must stop the system.(break;)
|
// 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
|
//stop the system
|
||||||
//return
|
//return
|
||||||
specialErrorOccured.Item2.WriteLine();
|
alarmCondition.LogInfo();
|
||||||
}
|
}
|
||||||
|
|
||||||
record.ControlConstants();
|
record.ControlConstants();
|
||||||
|
@ -186,7 +187,7 @@ internal static class Program
|
||||||
|
|
||||||
$"{record.StateMachine.State}: {record.StateMachine.Message}".LogInfo();
|
$"{record.StateMachine.State}: {record.StateMachine.Message}".LogInfo();
|
||||||
|
|
||||||
var essControl = record.ControlEss().LogInfo();
|
var essControl = record.ControlEss().WriteLine().LogInfo();
|
||||||
|
|
||||||
record.EssControl = essControl;
|
record.EssControl = essControl;
|
||||||
|
|
||||||
|
@ -212,36 +213,13 @@ internal static class Program
|
||||||
// ReSharper disable once FunctionNeverReturns
|
// 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.
|
{ K2ConnectIslandBusToGridBus: false, K2IslandBusIsConnectedToGridBus: true } => " Contradiction: R0 is opening the K2 but the K2 is still close ",
|
||||||
var isSpecialErrorOccured = false;
|
{ K1GridBusIsConnectedToGrid : false, K2IslandBusIsConnectedToGridBus: true } => " Contradiction: K1 is open but the K2 is still close ",
|
||||||
var errorMessage = "No Error";
|
{ FiError: true, K2IslandBusIsConnectedToGridBus: true } => " Contradiction: Fi error occured but the K2 is still close ",
|
||||||
|
_ => null
|
||||||
// 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);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void ControlConstants(this StatusRecord r)
|
private static void ControlConstants(this StatusRecord r)
|
||||||
{
|
{
|
||||||
|
@ -335,7 +313,7 @@ internal static class Program
|
||||||
sc.ResetAlarmsAndWarnings = true;
|
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;
|
var s3Config = status.Config.S3;
|
||||||
if (s3Config is null)
|
if (s3Config is null)
|
||||||
|
|
|
@ -2,7 +2,7 @@ namespace InnovEnergy.App.SaliMax.SystemConfig;
|
||||||
|
|
||||||
public class AcDcConfig
|
public class AcDcConfig
|
||||||
{
|
{
|
||||||
public required Double MaxDcLinkVoltage { get; set; }
|
public required Double MaxDcLinkVoltage { get; init; }
|
||||||
public required Double MinDcLinkVoltage { get; set; }
|
public required Double MinDcLinkVoltage { get; init; }
|
||||||
public required Double ReferenceDcLinkVoltage { get; set; }
|
public required Double ReferenceDcLinkVoltage { get; init; }
|
||||||
}
|
}
|
|
@ -1,5 +1,4 @@
|
||||||
using System.Text.Json;
|
using System.Text.Json;
|
||||||
using InnovEnergy.Lib.Time.Unix;
|
|
||||||
using InnovEnergy.Lib.Utils;
|
using InnovEnergy.Lib.Utils;
|
||||||
using static System.Text.Json.JsonSerializer;
|
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 MaxBatteryDischargingCurrent { get; set; }
|
||||||
public required Double MaxDcPower { get; set; }
|
public required Double MaxDcPower { get; set; }
|
||||||
|
|
||||||
|
|
||||||
public required Double MaxChargeBatteryVoltage { get; set; }
|
public required Double MaxChargeBatteryVoltage { get; set; }
|
||||||
public required Double MinDischargeBatteryVoltage { 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,
|
MaxChargeBatteryVoltage = 57,
|
||||||
MinDischargeBatteryVoltage = 0,
|
MinDischargeBatteryVoltage = 0,
|
||||||
|
|
||||||
Devices = new ()
|
Devices = new ()
|
||||||
{
|
{
|
||||||
TruConvertAcIp = new() { Host = "localhost", Port = 5001},
|
TruConvertAcIp = new() { Host = "localhost", Port = 5001},
|
||||||
|
|
|
@ -2,7 +2,7 @@ namespace InnovEnergy.App.SaliMax.SystemConfig;
|
||||||
|
|
||||||
public class DcDcConfig
|
public class DcDcConfig
|
||||||
{
|
{
|
||||||
public required Double LowerDcLinkVoltage { get; set; }
|
public required Double LowerDcLinkVoltage { get; init; }
|
||||||
public required Double ReferenceDcLinkVoltage { get; set; }
|
public required Double ReferenceDcLinkVoltage { get; init; }
|
||||||
public required Double UpperDcLinkVoltage { get; set; }
|
public required Double UpperDcLinkVoltage { get; init; }
|
||||||
}
|
}
|
|
@ -2,6 +2,6 @@ namespace InnovEnergy.App.SaliMax.SystemConfig;
|
||||||
|
|
||||||
public class DevicesConfig
|
public class DevicesConfig
|
||||||
{
|
{
|
||||||
public required AcDcConfig AcDc { get; set; }
|
public required AcDcConfig AcDc { get; init; }
|
||||||
public required DcDcConfig DcDc { get; set; }
|
public required DcDcConfig DcDc { get; init; }
|
||||||
}
|
}
|
|
@ -72,7 +72,7 @@ public static class Topology
|
||||||
var h = g;
|
var h = g;
|
||||||
var i = status.PvOnDc?.Dc.Power.Value;
|
var i = status.PvOnDc?.Dc.Power.Value;
|
||||||
var k = status.DcDc.Dc.Link.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 j = status.LoadOnDc?.Power.Value;
|
||||||
var d = status.AcGridToAcIsland?.Power.Active;
|
var d = status.AcGridToAcIsland?.Power.Active;
|
||||||
var c = status.LoadOnAcGrid?.Power.Active;
|
var c = status.LoadOnAcGrid?.Power.Active;
|
||||||
|
@ -260,9 +260,9 @@ public static class Topology
|
||||||
.Apply(TextBlock.AlignLeft)
|
.Apply(TextBlock.AlignLeft)
|
||||||
.TitleBox("AC/DC");
|
.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");
|
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();
|
var dc48Voltage = status.DcDc.Dc.Battery.Voltage.ToDisplayString();
|
||||||
|
|
||||||
|
@ -293,7 +293,7 @@ public static class Topology
|
||||||
.AlignLeft(dc48Voltage)
|
.AlignLeft(dc48Voltage)
|
||||||
.TitleBox("DC/DC");
|
.TitleBox("DC/DC");
|
||||||
|
|
||||||
var busFlow = Flow.Horizontal(l);
|
var busFlow = Flow.Horizontal(p);
|
||||||
|
|
||||||
return TextBlock.AlignCenterVertical(busBox, busFlow);
|
return TextBlock.AlignCenterVertical(busBox, busFlow);
|
||||||
}
|
}
|
||||||
|
@ -371,6 +371,7 @@ public static class Topology
|
||||||
return batteryAvgBox; // TODO: individualBatteries hidden atm
|
return batteryAvgBox; // TODO: individualBatteries hidden atm
|
||||||
|
|
||||||
|
|
||||||
|
#pragma warning disable CS0162
|
||||||
var batteryBoxes = bat
|
var batteryBoxes = bat
|
||||||
.Devices
|
.Devices
|
||||||
.Select(CreateBatteryBox)
|
.Select(CreateBatteryBox)
|
||||||
|
@ -386,6 +387,8 @@ public static class Topology
|
||||||
batteryAvgBox ,
|
batteryAvgBox ,
|
||||||
individualBatteries
|
individualBatteries
|
||||||
);
|
);
|
||||||
|
|
||||||
|
#pragma warning enable CS0162
|
||||||
}
|
}
|
||||||
|
|
||||||
private static TextBlock CreateAveragedBatteryBox(Battery48TlRecords? bat)
|
private static TextBlock CreateAveragedBatteryBox(Battery48TlRecords? bat)
|
||||||
|
@ -394,8 +397,9 @@ public static class Topology
|
||||||
return TextBlock.AlignLeft("no battery").Box();
|
return TextBlock.AlignLeft("no battery").Box();
|
||||||
|
|
||||||
var voltage = bat.Dc.Voltage.ToDisplayString();
|
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 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 temp = bat.Temperature.ToDisplayString();
|
||||||
var heatingPower = bat.HeatingPower.ToDisplayString();
|
var heatingPower = bat.HeatingPower.ToDisplayString();
|
||||||
var alarms = bat.Alarms.Count + " Alarms";
|
var alarms = bat.Alarms.Count + " Alarms";
|
||||||
|
@ -408,6 +412,7 @@ public static class Topology
|
||||||
voltage,
|
voltage,
|
||||||
soc,
|
soc,
|
||||||
current,
|
current,
|
||||||
|
busCurrent,
|
||||||
temp,
|
temp,
|
||||||
heatingPower,
|
heatingPower,
|
||||||
warnings,
|
warnings,
|
||||||
|
@ -447,7 +452,7 @@ public static class Topology
|
||||||
battery.Soc.ToDisplayString(),
|
battery.Soc.ToDisplayString(),
|
||||||
battery.Dc.Current.ToDisplayString() + " C/D",
|
battery.Dc.Current.ToDisplayString() + " C/D",
|
||||||
battery.Temperatures.Cells.Average.ToDisplayString(),
|
battery.Temperatures.Cells.Average.ToDisplayString(),
|
||||||
battery.BusCurrent.ToDisplayString() + " T",
|
battery.BusCurrent.ToDisplayString() ,
|
||||||
batteryWarnings,
|
batteryWarnings,
|
||||||
batteryAlarms,
|
batteryAlarms,
|
||||||
battery.HeatingCurrent.ToDisplayString() + " H"
|
battery.HeatingCurrent.ToDisplayString() + " H"
|
||||||
|
|
|
@ -1,12 +1,8 @@
|
||||||
using CliWrap;
|
using CliWrap;
|
||||||
using CliWrap.Buffered;
|
|
||||||
using HandlebarsDotNet;
|
using HandlebarsDotNet;
|
||||||
using InnovEnergy.App.VrmGrabber.Database;
|
using InnovEnergy.App.VrmGrabber.Database;
|
||||||
using InnovEnergy.App.VrmGrabber.DataTypes;
|
|
||||||
using InnovEnergy.Lib.Utils;
|
using InnovEnergy.Lib.Utils;
|
||||||
using InnovEnergy.Lib.Victron.VictronVRM;
|
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using FILE=System.IO.File;
|
|
||||||
using VrmInstallation = InnovEnergy.Lib.Victron.VictronVRM.Installation;
|
using VrmInstallation = InnovEnergy.Lib.Victron.VictronVRM.Installation;
|
||||||
|
|
||||||
namespace InnovEnergy.App.VrmGrabber;
|
namespace InnovEnergy.App.VrmGrabber;
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
using InnovEnergy.Lib.Victron.VictronVRM;
|
|
||||||
using SQLite;
|
using SQLite;
|
||||||
|
|
||||||
namespace InnovEnergy.App.VrmGrabber.DataTypes;
|
namespace InnovEnergy.App.VrmGrabber.DataTypes;
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
using InnovEnergy.App.VrmGrabber.DataTypes;
|
using InnovEnergy.App.VrmGrabber.DataTypes;
|
||||||
|
|
||||||
|
|
||||||
namespace InnovEnergy.App.VrmGrabber.Database;
|
namespace InnovEnergy.App.VrmGrabber.Database;
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -7,7 +7,6 @@ using CliWrap.Buffered;
|
||||||
using InnovEnergy.App.RemoteSupportConsole;
|
using InnovEnergy.App.RemoteSupportConsole;
|
||||||
using InnovEnergy.Lib.Utils;
|
using InnovEnergy.Lib.Utils;
|
||||||
using InnovEnergy.Lib.Victron.VictronVRM;
|
using InnovEnergy.Lib.Victron.VictronVRM;
|
||||||
using Newtonsoft.Json;
|
|
||||||
using SQLite;
|
using SQLite;
|
||||||
using static System.Text.Json.JsonSerializer;
|
using static System.Text.Json.JsonSerializer;
|
||||||
using static InnovEnergy.App.VrmGrabber.Database.Systemd;
|
using static InnovEnergy.App.VrmGrabber.Database.Systemd;
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
using InnovEnergy.App.VrmGrabber.DataTypes;
|
using InnovEnergy.App.VrmGrabber.DataTypes;
|
||||||
|
|
||||||
|
|
||||||
namespace InnovEnergy.App.VrmGrabber.Database;
|
namespace InnovEnergy.App.VrmGrabber.Database;
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,8 +1,11 @@
|
||||||
<Project Sdk="Microsoft.NET.Sdk.Web">
|
<Project Sdk="Microsoft.NET.Sdk.Web">
|
||||||
|
|
||||||
|
<Import Project="../InnovEnergy.App.props" />
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<PublishTrimmed>false</PublishTrimmed>
|
<PublishTrimmed>false</PublishTrimmed>
|
||||||
|
<RootNamespace>InnovEnergy.App.VrmGrabber</RootNamespace>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<Import Project="../InnovEnergy.App.props" />
|
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Flurl.Http" Version="3.2.4" />
|
<PackageReference Include="Flurl.Http" Version="3.2.4" />
|
||||||
|
@ -30,12 +33,12 @@
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="../../Lib/Utils/Utils.csproj" />
|
<ProjectReference Include="../../Lib/Utils/Utils.csproj" />
|
||||||
<ProjectReference Include="..\..\Lib\Victron\VictronVRM\VictronVRM.csproj" />
|
<ProjectReference Include="../../Lib/Victron/VictronVRM/VictronVRM.csproj" />
|
||||||
<ProjectReference Include="..\RemoteSupportConsole\RemoteSupportConsole.csproj" />
|
<ProjectReference Include="../RemoteSupportConsole/RemoteSupportConsole.csproj" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<_ContentIncludedByDefault Remove="wwwroot\index.html" />
|
<_ContentIncludedByDefault Remove="wwwroot/index.html" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|
|
@ -10,8 +10,6 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SysTools", "Lib/SysTools/Sy
|
||||||
EndProject
|
EndProject
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WebServer", "Lib/WebServer/WebServer.csproj", "{B2627B9F-41DF-44F7-A0D1-CA71FF4A007A}"
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WebServer", "Lib/WebServer/WebServer.csproj", "{B2627B9F-41DF-44F7-A0D1-CA71FF4A007A}"
|
||||||
EndProject
|
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}"
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EmuMeterDriver", "App/EmuMeterDriver/EmuMeterDriver.csproj", "{F65F33B0-3522-4008-8D1E-47EF8E4C7AC7}"
|
||||||
EndProject
|
EndProject
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BmsTunnel", "App/BmsTunnel/BmsTunnel.csproj", "{40B45363-BE34-420B-8F87-775EE6EE3513}"
|
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
|
EndProject
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "VrmGrabber", "App\VrmGrabber\VrmGrabber.csproj", "{88633C71-D701-49B3-A6DE-9D7CED9046E3}"
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "VrmGrabber", "App\VrmGrabber\VrmGrabber.csproj", "{88633C71-D701-49B3-A6DE-9D7CED9046E3}"
|
||||||
EndProject
|
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}"
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Mailer", "Lib\Mailer\Mailer.csproj", "{73B97F6E-2BDC-40DA-84A7-7FB0264387D6}"
|
||||||
EndProject
|
EndProject
|
||||||
|
|
||||||
|
@ -110,10 +110,6 @@ Global
|
||||||
{B2627B9F-41DF-44F7-A0D1-CA71FF4A007A}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
{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.ActiveCfg = Release|Any CPU
|
||||||
{B2627B9F-41DF-44F7-A0D1-CA71FF4A007A}.Release|Any CPU.Build.0 = 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.ActiveCfg = Debug|Any CPU
|
||||||
{F65F33B0-3522-4008-8D1E-47EF8E4C7AC7}.Debug|Any CPU.Build.0 = 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
|
{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}.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.ActiveCfg = Release|Any CPU
|
||||||
{88633C71-D701-49B3-A6DE-9D7CED9046E3}.Release|Any CPU.Build.0 = 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.ActiveCfg = Debug|Any CPU
|
||||||
{73B97F6E-2BDC-40DA-84A7-7FB0264387D6}.Debug|Any CPU.Build.0 = 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
|
{73B97F6E-2BDC-40DA-84A7-7FB0264387D6}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
@ -218,7 +218,6 @@ Global
|
||||||
GlobalSection(NestedProjects) = preSolution
|
GlobalSection(NestedProjects) = preSolution
|
||||||
{CF4834CB-91B7-4172-AC13-ECDA8613CD17} = {145597B4-3E30-45E6-9F72-4DD43194539A}
|
{CF4834CB-91B7-4172-AC13-ECDA8613CD17} = {145597B4-3E30-45E6-9F72-4DD43194539A}
|
||||||
{B1268C03-66EB-4486-8BFC-B439225D9D54} = {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}
|
{40B45363-BE34-420B-8F87-775EE6EE3513} = {145597B4-3E30-45E6-9F72-4DD43194539A}
|
||||||
{B2627B9F-41DF-44F7-A0D1-CA71FF4A007A} = {AD5B98A8-AB7F-4DA2-B66D-5B4E63E7D854}
|
{B2627B9F-41DF-44F7-A0D1-CA71FF4A007A} = {AD5B98A8-AB7F-4DA2-B66D-5B4E63E7D854}
|
||||||
{F65F33B0-3522-4008-8D1E-47EF8E4C7AC7} = {145597B4-3E30-45E6-9F72-4DD43194539A}
|
{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}
|
{1391165D-51F1-45B4-8B7F-042A20AA0277} = {4931A385-24DC-4E78-BFF4-356F8D6D5183}
|
||||||
{EB56EF94-D8A7-4111-A8E7-A87EF13596DA} = {145597B4-3E30-45E6-9F72-4DD43194539A}
|
{EB56EF94-D8A7-4111-A8E7-A87EF13596DA} = {145597B4-3E30-45E6-9F72-4DD43194539A}
|
||||||
{88633C71-D701-49B3-A6DE-9D7CED9046E3} = {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}
|
{73B97F6E-2BDC-40DA-84A7-7FB0264387D6} = {AD5B98A8-AB7F-4DA2-B66D-5B4E63E7D854}
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
EndGlobal
|
EndGlobal
|
||||||
|
|
|
@ -20,7 +20,7 @@ public partial class Battery48TlRecord
|
||||||
public Boolean Eoc => Leds is { Green: On, Amber: Off, Blue : Off };
|
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 String FwVersion => _FwVersion.ToString("X4");
|
||||||
public Strings Warnings => ParseWarnings().OrderBy(w => w).ToList();
|
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
|
public abstract class BasicTypeSignature : Signature
|
||||||
{
|
{
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
|
@ -176,11 +176,11 @@ public readonly struct Message
|
||||||
|
|
||||||
var raw = reader.ReadSegment((Int32)payloadLength);
|
var raw = reader.ReadSegment((Int32)payloadLength);
|
||||||
|
|
||||||
var br = new DBusBufferReader(raw, reader.SwapEndian);
|
|
||||||
|
|
||||||
if (signature.IsEmpty)
|
if (signature.IsEmpty)
|
||||||
return (raw.ToArray(), true); // no signature, but data available. should probably not happen.
|
return (raw.ToArray(), true); // no signature, but data available. should probably not happen.
|
||||||
|
|
||||||
|
var br = new DBusBufferReader(raw, reader.SwapEndian);
|
||||||
|
|
||||||
// try
|
// try
|
||||||
// {
|
// {
|
||||||
return (signature.Read(br), false);
|
return (signature.Read(br), false);
|
||||||
|
|
|
@ -53,11 +53,11 @@ public static class Replies
|
||||||
|
|
||||||
HeaderType header =
|
HeaderType header =
|
||||||
(
|
(
|
||||||
(Byte)Env.Endianness,
|
(Byte) Env.Endianness,
|
||||||
(Byte)MessageType.MethodReturn,
|
(Byte) MessageType.MethodReturn,
|
||||||
(Byte)HeaderFlags.NoReplyExpected,
|
(Byte) HeaderFlags.NoReplyExpected,
|
||||||
Message.ProtocolVersion,
|
Message.ProtocolVersion,
|
||||||
(UInt32)signature.MeasureSize(payload),
|
(UInt32) signature.MeasureSize(payload),
|
||||||
SerialSource.Next(),
|
SerialSource.Next(),
|
||||||
fields
|
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>
|
<RootNamespace>InnovEnergy.Lib.Time</RootNamespace>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\Utils\Utils.csproj" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
namespace InnovEnergy.Lib.Time.Unix;
|
// namespace InnovEnergy.Lib.Time.Unix;
|
||||||
|
//
|
||||||
public readonly partial struct UnixTime : IComparable<UnixTime>, IEquatable<UnixTime>
|
// public readonly partial struct UnixTime : IComparable<UnixTime>, IEquatable<UnixTime>
|
||||||
{
|
// {
|
||||||
Int32 IComparable<UnixTime>.CompareTo(UnixTime other) => Ticks.CompareTo(other.Ticks);
|
// Int32 IComparable<UnixTime>.CompareTo(UnixTime other) => Ticks.CompareTo(other.Ticks);
|
||||||
Boolean IEquatable<UnixTime>.Equals(UnixTime other) => Ticks == other.Ticks;
|
// Boolean IEquatable<UnixTime>.Equals(UnixTime other) => Ticks == other.Ticks;
|
||||||
}
|
// }
|
|
@ -1,20 +1,19 @@
|
||||||
namespace InnovEnergy.Lib.Time.Unix;
|
// namespace InnovEnergy.Lib.Time.Unix;
|
||||||
|
//
|
||||||
public readonly partial struct UnixTime
|
// public readonly partial struct UnixTime
|
||||||
{
|
// {
|
||||||
private UnixTime(UInt32 ticks) => Ticks = ticks;
|
// public static UnixTime FromTicks(Int32 ticks) => new UnixTime { Ticks = ticks };
|
||||||
|
//
|
||||||
public static UnixTime FromTicks(UInt32 ticks) => new UnixTime(ticks);
|
// public static UnixTime FromUtcDateTime(DateTime dateTime)
|
||||||
public static UnixTime FromTicks(Int32 ticks) => new UnixTime((UInt32) ticks);
|
// {
|
||||||
|
// var timeSinceEpoch = dateTime - DateTime.UnixEpoch;
|
||||||
public static UnixTime FromUtcDateTime(DateTime dateTime)
|
// var ticks = (Int32) timeSinceEpoch.TotalSeconds;
|
||||||
{
|
//
|
||||||
var timeSinceEpoch = dateTime - DateTime.UnixEpoch;
|
// return new UnixTime{ Ticks = ticks};
|
||||||
var ticks = (UInt32) timeSinceEpoch.TotalSeconds;
|
// }
|
||||||
|
//
|
||||||
return new UnixTime(ticks);
|
// public static UnixTime Epoch => new UnixTime { Ticks = 0 };
|
||||||
}
|
// public static UnixTime Now => FromUtcDateTime(DateTime.UtcNow);
|
||||||
|
//
|
||||||
public static UnixTime Epoch => new UnixTime(0);
|
//
|
||||||
public static UnixTime Now => FromUtcDateTime(DateTime.UtcNow);
|
// }
|
||||||
}
|
|
|
@ -1,9 +1,9 @@
|
||||||
namespace InnovEnergy.Lib.Time.Unix;
|
// namespace InnovEnergy.Lib.Time.Unix;
|
||||||
|
//
|
||||||
public readonly partial struct UnixTime
|
// public readonly partial struct UnixTime
|
||||||
{
|
// {
|
||||||
public DateTime ToUtcDateTime() => DateTime.UnixEpoch + TimeSpan.FromSeconds(Ticks);
|
// public DateTime ToUtcDateTime() => DateTime.UnixEpoch + TimeSpan.FromSeconds(Ticks);
|
||||||
|
//
|
||||||
public static implicit operator DateTime(UnixTime unixTimeSpan) => unixTimeSpan.ToUtcDateTime();
|
// public static implicit operator DateTime(UnixTime unixTimeSpan) => unixTimeSpan.ToUtcDateTime();
|
||||||
public static implicit operator UnixTime(DateTime dateTime) => FromUtcDateTime(dateTime);
|
// public static implicit operator UnixTime(DateTime dateTime) => FromUtcDateTime(dateTime);
|
||||||
}
|
// }
|
|
@ -1,20 +1,27 @@
|
||||||
namespace InnovEnergy.Lib.Time.Unix;
|
// using InnovEnergy.Lib.Utils;
|
||||||
|
//
|
||||||
public readonly partial struct UnixTime
|
// namespace InnovEnergy.Lib.Time.Unix;
|
||||||
{
|
//
|
||||||
public static UnixTime operator -(UnixTime a, UnixTimeSpan b) => FromTicks(a.Ticks - b.Ticks);
|
// public readonly partial struct UnixTime
|
||||||
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 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 UInt32 operator /(UnixTime a, UnixTimeSpan b) => a.Ticks / b.Ticks;
|
// public static UnixTime operator +(TimeSpan a, UnixTime b) => FromTicks(GetUnixTicks(a) + b.Ticks);
|
||||||
public static UInt32 operator %(UnixTime a, UnixTimeSpan b) => a.Ticks % b.Ticks;
|
//
|
||||||
|
// public static Double operator /(UnixTime a, TimeSpan b) => a.Ticks.ConvertTo<Double>() / b.Ticks;
|
||||||
public static Boolean operator < (UnixTime l, UnixTime r) => l.Ticks < r.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 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);
|
// 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;
|
// namespace InnovEnergy.Lib.Time.Unix;
|
||||||
|
//
|
||||||
public readonly partial struct UnixTime
|
// public readonly partial struct UnixTime
|
||||||
{
|
// {
|
||||||
public override Boolean Equals(Object? obj) => obj is UnixTime other && Ticks == other.Ticks;
|
// 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 Int32 GetHashCode() => (Int32) (Ticks & 0x7F_FF_FF_FF);
|
||||||
public override String ToString() => Ticks.ToString();
|
// public override String ToString() => Ticks.ToString();
|
||||||
}
|
// }
|
|
@ -1,14 +1,6 @@
|
||||||
|
// namespace InnovEnergy.Lib.Time.Unix;
|
||||||
|
//
|
||||||
// ReSharper disable ArrangeStaticMemberQualifier
|
// public readonly partial struct UnixTime
|
||||||
|
// {
|
||||||
namespace InnovEnergy.Lib.Time.Unix;
|
// public required Int32 Ticks { get; init; }
|
||||||
|
// }
|
||||||
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;
|
|
||||||
}
|
|
|
@ -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>
|
<ItemGroup>
|
||||||
<ProjectReference Include="../Utils/Utils.csproj" />
|
<ProjectReference Include="../Utils/Utils.csproj" />
|
||||||
<ProjectReference Include="../Time/Time.csproj" />
|
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<!-- <Target Name="PreBuild" BeforeTargets="PreBuildEvent">-->
|
<!-- <Target Name="PreBuild" BeforeTargets="PreBuildEvent">-->
|
||||||
|
|
|
@ -5,6 +5,12 @@ namespace InnovEnergy.Lib.Utils;
|
||||||
public static class AsyncEnumerableEx
|
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,
|
public static async IAsyncEnumerable<T> Throttle<T>(this IAsyncEnumerable<T> ts,
|
||||||
TimeSpan dueTime,
|
TimeSpan dueTime,
|
||||||
[EnumeratorCancellation] CancellationToken cancel = default)
|
[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,
|
public static IEnumerable<T> TraverseDepthFirstPreOrder<T>(T root,
|
||||||
Func<T, IEnumerable<T>> getChildren,
|
Func<T, IEnumerable<T>> getChildren,
|
||||||
IEqualityComparer<T>? comparer = null)
|
IEqualityComparer<T>? comparer = null)
|
||||||
{
|
{
|
||||||
return Traverse(root, TreeTraversal.TraverseDepthFirstPreOrder, getChildren, comparer);
|
return Traverse(root, TreeTraversal.TraverseDepthFirstPreOrder, getChildren, comparer);
|
||||||
}
|
}
|
||||||
|
@ -14,7 +14,7 @@ IEqualityComparer<T>? comparer = null)
|
||||||
|
|
||||||
public static IEnumerable<T> TraverseDepthFirstPostOrder<T>(T root,
|
public static IEnumerable<T> TraverseDepthFirstPostOrder<T>(T root,
|
||||||
Func<T, IEnumerable<T>> getChildren,
|
Func<T, IEnumerable<T>> getChildren,
|
||||||
IEqualityComparer<T>? comparer = null)
|
IEqualityComparer<T>? comparer = null)
|
||||||
{
|
{
|
||||||
return Traverse(root, TreeTraversal.TraverseDepthFirstPostOrder, getChildren, comparer);
|
return Traverse(root, TreeTraversal.TraverseDepthFirstPostOrder, getChildren, comparer);
|
||||||
}
|
}
|
||||||
|
@ -28,7 +28,7 @@ IEqualityComparer<T>? comparer = null)
|
||||||
|
|
||||||
public static IEnumerable<T> TraverseDepthFirstPreOrder<T>(IEnumerable<T> sources,
|
public static IEnumerable<T> TraverseDepthFirstPreOrder<T>(IEnumerable<T> sources,
|
||||||
Func<T, IEnumerable<T>> getChildren,
|
Func<T, IEnumerable<T>> getChildren,
|
||||||
IEqualityComparer<T>? comparer = null)
|
IEqualityComparer<T>? comparer = null)
|
||||||
{
|
{
|
||||||
return Traverse(sources, TreeTraversal.TraverseDepthFirstPreOrder, getChildren, comparer);
|
return Traverse(sources, TreeTraversal.TraverseDepthFirstPreOrder, getChildren, comparer);
|
||||||
}
|
}
|
||||||
|
@ -36,14 +36,14 @@ IEqualityComparer<T>? comparer = null)
|
||||||
|
|
||||||
public static IEnumerable<T> TraverseDepthFirstPostOrder<T>(IEnumerable<T> sources,
|
public static IEnumerable<T> TraverseDepthFirstPostOrder<T>(IEnumerable<T> sources,
|
||||||
Func<T, IEnumerable<T>> getChildren,
|
Func<T, IEnumerable<T>> getChildren,
|
||||||
IEqualityComparer<T>? comparer = null)
|
IEqualityComparer<T>? comparer = null)
|
||||||
{
|
{
|
||||||
return Traverse(sources, TreeTraversal.TraverseDepthFirstPostOrder, getChildren, comparer);
|
return Traverse(sources, TreeTraversal.TraverseDepthFirstPostOrder, getChildren, comparer);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static IEnumerable<T> TraverseBreadthFirst<T>(IEnumerable<T> sources,
|
public static IEnumerable<T> TraverseBreadthFirst<T>(IEnumerable<T> sources,
|
||||||
Func<T, IEnumerable<T>> getChildren,
|
Func<T, IEnumerable<T>> getChildren,
|
||||||
IEqualityComparer<T>? comparer = null)
|
IEqualityComparer<T>? comparer = null)
|
||||||
{
|
{
|
||||||
return Traverse(sources, TreeTraversal.TraverseBreadthFirst, getChildren, comparer);
|
return Traverse(sources, TreeTraversal.TraverseBreadthFirst, getChildren, comparer);
|
||||||
}
|
}
|
||||||
|
@ -52,7 +52,7 @@ IEqualityComparer<T>? comparer = null)
|
||||||
private static IEnumerable<T> Traverse<T>(T root,
|
private static IEnumerable<T> Traverse<T>(T root,
|
||||||
Func<T , Func<T, IEnumerable<T>>,IEnumerable<T>> traversor,
|
Func<T , Func<T, IEnumerable<T>>,IEnumerable<T>> traversor,
|
||||||
Func<T, IEnumerable<T>> getChildren,
|
Func<T, IEnumerable<T>> getChildren,
|
||||||
IEqualityComparer<T>? comparer = null)
|
IEqualityComparer<T>? comparer = null)
|
||||||
{
|
{
|
||||||
var getUniqueChildren = GetUniqueChildren(getChildren, root, comparer);
|
var getUniqueChildren = GetUniqueChildren(getChildren, root, comparer);
|
||||||
return traversor(root, getUniqueChildren);
|
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,
|
private static Func<T, IEnumerable<T>> GetUniqueChildren<T>(Func<T, IEnumerable<T>> getChildren,
|
||||||
T root,
|
T root,
|
||||||
IEqualityComparer<T>? comparer)
|
IEqualityComparer<T>? comparer)
|
||||||
{
|
{
|
||||||
return GetUniqueChildren(getChildren, root.AsSingleEnumerable(), comparer);
|
return GetUniqueChildren(getChildren, root.AsSingleEnumerable(), comparer);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Func<T, IEnumerable<T>> GetUniqueChildren<T>(Func<T, IEnumerable<T>> getChildren,
|
private static Func<T, IEnumerable<T>> GetUniqueChildren<T>(Func<T, IEnumerable<T>> getChildren,
|
||||||
IEnumerable<T> sources,
|
IEnumerable<T> sources,
|
||||||
IEqualityComparer<T>? comparer)
|
IEqualityComparer<T>? comparer)
|
||||||
{
|
{
|
||||||
var set = new HashSet<T>(sources, comparer ?? EqualityComparer<T>.Default);
|
var set = new HashSet<T>(sources, comparer ?? EqualityComparer<T>.Default);
|
||||||
return n => getChildren(n).Where(set.Add);
|
return n => getChildren(n).Where(set.Add);
|
||||||
|
|
|
@ -2,20 +2,7 @@ namespace InnovEnergy.Lib.Utils;
|
||||||
|
|
||||||
public static class NullableUtils
|
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)}";
|
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;
|
namespace InnovEnergy.Lib.Utils;
|
||||||
|
|
||||||
|
|
||||||
public static class 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
|
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));
|
CopyFilesRecursively(dir, target.CreateSubdirectory(dir.Name));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public static String ExecutingProcessName => Process.GetCurrentProcess().ProcessName;
|
public static String ExecutingProcessName => Process.GetCurrentProcess().ProcessName;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
|
@ -1,8 +1,4 @@
|
||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
<PropertyGroup>
|
|
||||||
<Configurations>Debug;Release;Release-Server</Configurations>
|
|
||||||
<Platforms>AnyCPU;linux-arm</Platforms>
|
|
||||||
</PropertyGroup>
|
|
||||||
<Import Project="../InnovEnergy.Lib.props" />
|
<Import Project="../InnovEnergy.Lib.props" />
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
|
@ -12,6 +8,7 @@
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="CliWrap" Version="3.6.0" />
|
<PackageReference Include="CliWrap" Version="3.6.0" />
|
||||||
<PackageReference Include="DecimalMath.DecimalEx" Version="1.0.2" />
|
<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" />
|
<PackageReference Include="System.Reactive.Linq" Version="5.0.0" />
|
||||||
</ItemGroup>
|
</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 System.Text.Json.Nodes;
|
||||||
using InnovEnergy.Lib.Time.Unix;
|
|
||||||
using InnovEnergy.Lib.Utils;
|
using InnovEnergy.Lib.Utils;
|
||||||
|
|
||||||
// ReSharper disable StringLiteralTypo
|
// ReSharper disable StringLiteralTypo
|
||||||
|
@ -10,7 +9,7 @@ public readonly partial record struct Installation(VrmAccount VrmAccount, JsonNo
|
||||||
{
|
{
|
||||||
|
|
||||||
public UInt64 IdSite => Json.GetUInt64("idSite");
|
public UInt64 IdSite => Json.GetUInt64("idSite");
|
||||||
public UnixTime Created => Json.GetUInt32("syscreated").Apply(UnixTime.FromTicks);
|
public UInt32 Created => Json.GetUInt32("syscreated");
|
||||||
|
|
||||||
// Settings
|
// Settings
|
||||||
|
|
||||||
|
|
|
@ -17,7 +17,6 @@
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="../../Utils/Utils.csproj" />
|
<ProjectReference Include="../../Utils/Utils.csproj" />
|
||||||
<ProjectReference Include="../../Time/Time.csproj" />
|
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|
|
@ -13,7 +13,6 @@ public static class HttpExtensions
|
||||||
return headers
|
return headers
|
||||||
.AllKeys
|
.AllKeys
|
||||||
.EmptyIfNull()
|
.EmptyIfNull()
|
||||||
.Where(k => k != null)
|
|
||||||
.Select(k => new HttpHeader(k!, headers[k]!));
|
.Select(k => new HttpHeader(k!, headers[k]!));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue