remove API

This commit is contained in:
ig 2023-02-23 15:33:26 +01:00
parent cec22d07d8
commit 384d7c9596
90 changed files with 0 additions and 2304 deletions

View File

@ -1,32 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<Import Project="../InnovEnergy.app.props" />
<PropertyGroup>
<RootNamespace>InnovEnergy.API</RootNamespace>
<StartupObject>InnovEnergy.API.Program</StartupObject>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="../../lib/Utils/Utils.csproj" />
<ProjectReference Include="../../lib/VictronVRM/VictronVRM.csproj" />
<ProjectReference Include="../../lib/WebServer/WebServer.csproj" />
<ProjectReference Include="../OpenVpnCertificatesServer/OpenVpnCertificatesServer.csproj" />
<ProjectReference Include="../../lib/Victron/VictronVRM/VictronVRM.csproj" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
<PackageReference Include="sqlite-net-pcl" Version="1.8.116" />
</ItemGroup>
<!-- <Target Name="sass" BeforeTargets="PreBuildEvent">-->
<!-- <Exec Command="find $(MSBuildProjectDirectory) -name '*.scss' | sed 's//.scss$//' | xargs -I{} $(MSBuildProjectDirectory)/../../tools/sass &#45;&#45;embed-source-map {}.scss {}.css" />-->
<!-- </Target>-->
</Project>

View File

@ -1,66 +0,0 @@
using Flurl;
using InnovEnergy.API.DataModel;
namespace InnovEnergy.API;
public static class Api
{
public static Result CreateUser(QueryParamCollection queryParams, LoginState loginState)
{
var parentPath = queryParams.FirstOrDefault("path") as String;
var userName = queryParams.FirstOrDefault("userName") as String;
var userType = queryParams.FirstOrDefault("userType") as String;
if (userName != null && Program.Data.Root.FindDescendantUser(userName) != null)
return Result.Failure("there is already another user with that name");
return loginState.CreateUser(parentPath, userName, userType);
}
public static Result EditUser(QueryParamCollection queryParams, LoginState loginState)
{
var userPath = queryParams.FirstOrDefault("path") as String;
var userType = queryParams.FirstOrDefault("userType") as String;
return loginState.EditUser(userPath, userType);
}
public static Result RenameInstallation(QueryParamCollection queryParams, LoginState loginState)
{
var userPath = queryParams.FirstOrDefault("path") as String;
var userType = queryParams.FirstOrDefault("name") as String;
return loginState.RenameInstallation(userPath, userType);
}
public static Result DeleteFolder(QueryParamCollection queryParams, LoginState loginState)
{
var path = queryParams.FirstOrDefault("path") as String;
return loginState.DeleteFolder(path);
}
public static Result DeleteInstallation(QueryParamCollection queryParams, LoginState loginState)
{
var path = queryParams.FirstOrDefault("path") as String;
return loginState.DeleteInstallation(path);
}
public static Result DeleteUser(QueryParamCollection queryParams, LoginState loginState)
{
var path = queryParams.FirstOrDefault("path") as String;
return loginState.DeleteUser(path);
}
// public static Result Rename(QueryParamCollection queryParams, LoginState loginState)
// {
// var path = queryParams.FirstOrDefault("path") as String;
// var name = queryParams.FirstOrDefault("name") as String;
//
// return loginState.Delete(path);
// }
}

View File

@ -1,27 +0,0 @@
namespace InnovEnergy.API.DataModel;
public static class DataExtensions
{
public static Folder GetOrCreateFolder(this Data data, IEnumerable<String> path)
{
var parent = data.Root;
var stack = new Stack<String>(path.Reverse());
while (stack.Count > 0)
{
var childFolderName = stack.Pop();
var childFolder = parent.Folders.FirstOrDefault(f => f.Name == childFolderName);
if (childFolder is null)
{
childFolder = new Folder { Name = childFolderName };
parent.Add(childFolder);
}
parent = childFolder;
}
return parent;
}
}

View File

@ -1,83 +0,0 @@
using InnovEnergy.Lib.Utils;
using Newtonsoft.Json;
using Newtonsoft.Json.Serialization;
namespace InnovEnergy.API.DataModel;
public partial record Data
{
private static readonly JsonSerializerSettings PersistenceJsonSettings = new JsonSerializerSettings
{
Formatting = Formatting.Indented,
NullValueHandling = NullValueHandling.Include,
ContractResolver = new CamelCasePropertyNamesContractResolver(),
TypeNameHandling = TypeNameHandling.Auto
};
public static readonly JsonSerializerSettings WireFormatJsonSettings = new JsonSerializerSettings
{
Formatting = Formatting.Indented,
NullValueHandling = NullValueHandling.Ignore,
ContractResolver = new CamelCasePropertyNamesContractResolver(),
TypeNameHandling = TypeNameHandling.None
};
public static Data Load() => GetLastVersion().Apply(Load);
public static String LoadJson() => GetLastVersion().Apply(LoadJson);
public static Data Load(Int32 sequenceNb)
{
var json = LoadJson(sequenceNb);
return JsonConvert.DeserializeObject<Data>(json, PersistenceJsonSettings)!;
}
public static String LoadJson(Int32 sequenceNb)
{
var jsonFile = System.IO.Path.Combine(Program.RootDir, sequenceNb + ".json");
Console.WriteLine($"loaded {jsonFile}");
return jsonFile.Apply(File.ReadAllText);
}
public void Save(String editAction, String user)
{
var version = Edit.Version + 1;
Edit = new Edit(editAction, user, version);
var path = System.IO.Path.Combine(Program.RootDir, version + ".json");
var json = SerializeJson();
File.WriteAllText(path, json);
}
public String SerializeJson()
{
return JsonConvert.SerializeObject(this, PersistenceJsonSettings);
}
private static String Base64Hash(DataElement element)
{
return element
.GetHashCode()
.Apply(BitConverter.GetBytes)
.Apply(Convert.ToBase64String)
.Apply(TrimEq);
}
private static String TrimEq(String h) => h.TrimEnd('=');
private static Int32 GetLastVersion()
{
return Directory
.EnumerateFiles(Program.RootDir, "*.json")
.Select(System.IO.Path.GetFileNameWithoutExtension)
.Where(f => f!.All(Char.IsDigit))
.OrderBy(f => f)
.Last()
.Apply(Int32.Parse!);
}
//public override String ToString() => JsonConvert.SerializeObject(this, WireFormatJsonSettings);
}

View File

@ -1,29 +0,0 @@
namespace InnovEnergy.API.DataModel;
public partial record Data
{
public Edit Edit { get; set; }
public Folder Root { get; set; } = null!;
public Data(Folder root, Edit edit)
{
Root = root;
Edit = edit;
}
public static Data Origin
{
get
{
var root = new Folder { Name = "All Installations" };
var admin = new User { Name = "admin", UserType = UserType.Admin };
root.Add(admin);
return new Data(root, new Edit("ORIGIN", admin.Name, 0));
}
}
// https://vrmapi.victronenergy.com/v2/users/55450/addsite
// {"installation_identifier":"ertertertertertert","description":"___TEST"}
}

View File

@ -1,17 +0,0 @@
namespace InnovEnergy.API.DataModel;
public static class DataElementExtensions
{
public static IEnumerable<DataElement> GetChildren(this DataElement de)
{
return de switch
{
Folder f => f.Folders.Concat<DataElement>(f.Installations).Concat(f.Users),
Installation i => i.Users,
_ => Enumerable.Empty<DataElement>()
};
}
public static Path RelativePath(this DataElement root) => new Path(null, root);
}

View File

@ -1,24 +0,0 @@
using Newtonsoft.Json;
namespace InnovEnergy.API.DataModel;
public abstract record DataElement : IComparable<DataElement>
{
[JsonProperty(Order = Int32.MinValue + 0)] public String Name { get; set; } = "<no name>";
[JsonProperty(Order = Int32.MinValue + 1)] public String Type { get; set; }
protected DataElement()
{
Type = GetType().Name;
}
public override String ToString() => $"{Type.ToLower()} '{Name}'";
public Int32 CompareTo(DataElement? other)
{
if (ReferenceEquals(this, other)) return 0;
if (ReferenceEquals(null, other)) return 1;
return String.Compare(Name, other.Name, StringComparison.InvariantCultureIgnoreCase);
}
}

View File

@ -1,21 +0,0 @@
using System.Globalization;
namespace InnovEnergy.API.DataModel;
public record Edit
{
private static readonly String DateTimePattern = CultureInfo.CurrentCulture.DateTimeFormat.UniversalSortableDateTimePattern;
public String Action { get; set; } = "";
public String User { get; set; } = "";
public String TimeStamp { get; set; } = "";
public Int32 Version { get; set; }
public Edit(String action, String user, Int32 version)
{
Action = action;
User = user;
Version = version;
TimeStamp = DateTime.Now.ToString(DateTimePattern);
}
}

View File

@ -1,23 +0,0 @@
using System.Diagnostics.CodeAnalysis;
using InnovEnergy.Lib.Utils;
namespace InnovEnergy.API.DataModel;
public partial record Folder
{
public virtual Boolean Equals(Folder? other)
{
if (ReferenceEquals(null, other)) return false;
if (ReferenceEquals(this, other)) return true;
return base.Equals(other) &&
Folders.SequenceEqual(other.Folders) &&
Installations.SequenceEqual(other.Installations);
}
[SuppressMessage("ReSharper", "NonReadonlyMemberInGetHashCode")]
public override Int32 GetHashCode() => HashCode.Combine(base.GetHashCode(),
Folders.SequenceHash(),
Installations.SequenceHash());
}

View File

@ -1,105 +0,0 @@
namespace InnovEnergy.API.DataModel;
public static class FolderExtensions
{
public static IEnumerable<Path> DescendantUserParents(this Folder folder)
{
foreach (var path in folder.GetDescendantFolders())
{
yield return path;
var f = path.Folder()!;
foreach (var installation in f.Installations)
yield return new Path(path, installation);
}
}
public static IEnumerable<Path> DescendantFolders(this Folder folder) => folder.GetDescendantFolders();
public static IEnumerable<Path> DescendantInstallations(this Folder folder)
{
return from path in folder.DescendantFolders()
let f = path.Element as Folder
from installation in f.Installations
select new Path(path, installation);
}
public static IEnumerable<Path> DescendantUsers(this Folder folder)
{
IEnumerable<User> GetUsers(Folder f) => f
.Installations
.SelectMany(i => i.Users)
.Concat(f.Users);
return from path in folder.DescendantFolders()
from user in GetUsers(path.Folder())
select new Path(path, user);
}
public static Path? FindDescendantUser(this Folder folder, String userName)
{
return folder
.DescendantUsers()
.FirstOrDefault(f => f.Element.Name == userName);
}
private static IEnumerable<Path> GetDescendantFolders(this Folder folder, Path? parent = null)
{
var path = new Path(parent, folder);
yield return path;
var descendantFolders = from f in folder.Folders
from descendant in f.GetDescendantFolders(path)
select descendant;
foreach (var descendant in descendantFolders)
yield return descendant;
}
public static Boolean Remove(this Folder folder, Installation installation)
{
return folder.Installations.Remove(installation);
}
public static void Add(this Folder folder, Installation installation)
{
folder.Installations.Add(installation);
}
public static Boolean Remove(this Folder folder, Folder child)
{
return folder.Folders.Remove(child);
}
public static void Add(this Folder folder, Folder child)
{
folder.Folders.Add(child);
}
public static VrmInstallation GetOrCreateVrmInstallation(this Folder folder, String uniqueId)
{
var vrmInstallation = folder
.Installations
.OfType<VrmInstallation>()
.FirstOrDefault(i => i.UniqueId == uniqueId);
if (vrmInstallation is not null)
return vrmInstallation; // installation exist, return it
vrmInstallation = new VrmInstallation();
folder.Installations.Add(vrmInstallation);
return vrmInstallation;
}
public static Boolean IsEmpty(this Folder folder) => !folder.Folders.Any() && !folder.Installations.Any();
}

View File

@ -1,7 +0,0 @@
namespace InnovEnergy.API.DataModel;
public partial record Folder : UserParent
{
public List<Folder> Folders { get; set; } = new List<Folder>();
public List<Installation> Installations { get; set; } = new List<Installation>();
}

View File

@ -1,24 +0,0 @@
using System.Diagnostics.CodeAnalysis;
using InnovEnergy.Lib.Utils;
namespace InnovEnergy.API.DataModel;
public abstract partial record Installation
{
public virtual Boolean Equals(Installation? other)
{
if (ReferenceEquals(null, other)) return false;
if (ReferenceEquals(this, other)) return true;
return base.Equals(other) &&
VpnIp == other.VpnIp &&
IeSerial == other.IeSerial &&
Tags.SequenceEqual(other.Tags);
}
[SuppressMessage("ReSharper", "NonReadonlyMemberInGetHashCode")]
public override Int32 GetHashCode()
{
return HashCode.Combine(base.GetHashCode(), VpnIp, IeSerial, Tags.SequenceHash());
}
}

View File

@ -1,8 +0,0 @@
namespace InnovEnergy.API.DataModel;
public abstract partial record Installation : UserParent
{
public String? VpnIp { get; set; }
public String? IeSerial { get; set; }
public IReadOnlyList<String> Tags { get; set; } = Array.Empty<String>();
}

View File

@ -1,159 +0,0 @@
using static InnovEnergy.API.Result;
namespace InnovEnergy.API.DataModel;
public static class PathExtensions
{
public static Boolean IsRoot(this Path path) => path.Parent is null;
public static Installation? Installation(this Path? path) => path?.Element as Installation;
public static Folder? Folder (this Path? path) => path?.Element as Folder;
public static User? User (this Path? path) => path?.Element as User;
public static UserParent? UserParent (this Path? path) => path?.Element as UserParent;
public static Boolean IsInstallation(this Path? path) => path?.Element is Installation;
public static Boolean IsFolder (this Path? path) => path?.Element is Folder;
public static Boolean IsUser (this Path? path) => path?.Element is User;
public static Boolean Exists(this Path? path) => path?.Element is not null;
public static IEnumerable<Path> Children(this Path? path) => from child in path?.Element.GetChildren()
select new Path(path, child);
public static Result MoveTo(this Path sourcePath, Path targetPath)
{
var add = targetPath.AddChild(sourcePath.Element);
if (add.Succeeded)
{
var delete = sourcePath.Delete();
if (delete.Succeeded)
return Success($"moved {sourcePath} to {targetPath}");
var revert = targetPath.Delete();
if (revert.Failed)
throw new Exception($"failed to move {sourcePath} to {targetPath}");
}
return Failure($"failed to move {sourcePath} to {targetPath}");
}
public static Result Delete(this Path path)
{
var child = path.Element;
var parent = path.Parent?.Element;
if (parent is Folder folder)
{
if (child is Folder f)
{
if (!f.IsEmpty())
return Failure($"Cannot delete folder '{f.Name}'.\nFolder is not empty.");
if (folder.Remove(f))
return Success($"Deleted folder {path}");
}
if (child is User u)
{
if (folder.Remove(u))
return Success($"Deleted user {path}");
}
if (child is Installation i)
{
if (!i.IsEmpty())
return Failure($"Cannot delete installation '{i.Name}'.\nInstallation has active users.");
if (folder.Remove(i))
return Success($"deleted installation {path}");
}
}
else if (parent is Installation installation && child is User user)
{
installation.Remove(user);
return Success($"deleted user {path}");
}
return Failure($"cannot delete {path}");
}
public static Result AddChild(this Path path, DataElement child)
{
var parent = path.Element;
if (parent.GetChildren().Any(c => c.Name == child.Name))
return Failure($"{path} already has an element with name {child.Name}");
if (parent is Folder folder)
{
if (child is Folder f)
{
folder.Add(f);
return Success($"added folder {child.Name} to folder {path}");
}
if (child is User u)
{
folder.Add(u);
return Success($"added user {child.Name} to folder {path}");
}
if (child is Installation i)
{
folder.Add(i);
return Success($"added installation {child.Name} to folder {path}");
}
}
else if (parent is Installation installation && child is User user)
{
installation.Add(user);
return Success($"added user {child.Name} to installation {path}");
}
return Failure($"cannot add {child} to {path}");
}
public static Path? GetDescendant(this Path path, params String[] stringPath)
{
return path.GetDescendant((IEnumerable<String>)stringPath);
}
public static Path? GetDescendant(this Path path, IEnumerable<String> stringPath)
{
foreach (var childName in stringPath)
{
var child = path
.Element
.GetChildren()
.SingleOrDefault(c => c.Name == childName);
if (child is null) return null;
path = new Path(path, child);
}
return path;
}
// public static Path? GetDescendant(this Path path, String stringPath)
// {
// while (!stringPath.IsNullOrWhiteSpace())
// {
// var childName = stringPath.UntilFirst('|');
//
// var child = path
// .Head
// .GetChildren()
// .SingleOrDefault(c => c.Name == childName);
//
// if (child is null) return null;
//
// stringPath = stringPath.AfterFirst('|');
// path = new Path(path, child);
// }
//
// return path;
// }
}

View File

@ -1,18 +0,0 @@
namespace InnovEnergy.API.DataModel;
public record Path(Path? Parent, DataElement Element)
{
public override String ToString()
{
var path = Element.Name;
var parent = Parent;
while (parent is not null)
{
path = parent.Element.Name + "|" + path;
parent = parent.Parent;
}
return $"|{path}";
}
}

View File

@ -1,8 +0,0 @@
namespace InnovEnergy.API.DataModel;
public static class UserExtensions
{
public static Boolean CanEditUsers(this User user) => user.UserType == UserType.Admin;
public static Boolean CanEditFolders(this User user) => user.UserType != UserType.Viewer;
public static Boolean CanEditInstallations(this User user) => user.UserType != UserType.Viewer;
}

View File

@ -1,6 +0,0 @@
namespace InnovEnergy.API.DataModel;
public record User : DataElement
{
public UserType UserType { get;set; }
}

View File

@ -1,20 +0,0 @@
using InnovEnergy.Lib.Utils;
namespace InnovEnergy.API.DataModel;
public abstract partial record UserParent
{
public virtual Boolean Equals(UserParent? other)
{
if (ReferenceEquals(null, other)) return false;
if (ReferenceEquals(this, other)) return true;
return base.Equals(other) && Users.SequenceEqual(other.Users);
}
public override Int32 GetHashCode()
{
// ReSharper disable once NonReadonlyMemberInGetHashCode
return HashCode.Combine(base.GetHashCode(), Users.SequenceHash());
}
}

View File

@ -1,19 +0,0 @@
namespace InnovEnergy.API.DataModel;
public static class UserParentExtensions
{
public static Boolean Remove(this UserParent parent, User user)
{
return parent.Users.Remove(user);
}
public static void Add(this UserParent parent, User user)
{
parent.Users.Add(user);
}
public static Boolean IsEmpty(this UserParent parent)
{
return !parent.Users.Any();
}
}

View File

@ -1,6 +0,0 @@
namespace InnovEnergy.API.DataModel;
public abstract partial record UserParent : DataElement
{
public List<User> Users { get; set; } = new List<User>();
}

View File

@ -1,13 +0,0 @@
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
namespace InnovEnergy.API.DataModel;
[JsonConverter(typeof(StringEnumConverter))]
public enum UserType
{
Unknown ,
Viewer ,
Editor ,
Admin
}

View File

@ -1,12 +0,0 @@
namespace InnovEnergy.API.DataModel;
public record VrmInstallation : Installation
{
public String? UniqueId { get; set; }
public UInt64 VrmId { get; set; }
public String? MachineSerial { get; set; }
public String? SystemType { get; set; }
public String? FirmwareVersion { get; set; }
public Boolean? Online { get; set; }
public String? MachineName { get; set; }
}

View File

@ -1,18 +0,0 @@
namespace InnovEnergy.API;
public static class Extensions
{
public const String Installation = ".inst";
public const String Folder = ".folder";
public const String Viewer = ".viewer";
public const String Admin = ".admin";
public const String Editor = ".editor";
public static Boolean IsInstallation(this String path) => path.EndsWith(Installation);
public static Boolean IsFolder (this String path) => path.EndsWith(Folder);
public static Boolean IsViewer (this String path) => path.EndsWith(Viewer);
public static Boolean IsEditor (this String path) => path.EndsWith(Editor);
public static Boolean IsAdmin (this String path) => path.EndsWith(Admin);
public static Boolean IsUser (this String path) => path.IsViewer() || path.IsEditor() || path.IsAdmin();
}

View File

@ -1,7 +0,0 @@
namespace InnovEnergy.API;
public enum InstallationType
{
InnovEnergy,
Victron,
}

View File

@ -1,259 +0,0 @@
using InnovEnergy.API.DataModel;
using static InnovEnergy.API.Result;
using Path = InnovEnergy.API.DataModel.Path;
namespace InnovEnergy.API;
public static class LoginStateExtensions
{
// TODO: sync VRM
public static Boolean CanEdit(this LoginState uc, Path path) => uc.CanEdit(path.Element);
public static Boolean CanEdit(this LoginState uc, DataElement de)
{
var user = uc.LoginUser;
return de is Folder && user.CanEditFolders() ||
de is User && user.CanEditUsers() ||
de is Installation && user.CanEditInstallations();
}
public static Result Move(this LoginState ctx, String sourcePath, String targetPath)
{
var source = ctx.ParsePath(sourcePath);
if (source is null)
return Failure($"cannot find {sourcePath}");
if (!ctx.CanEdit(source))
return Failure($"operation not allowed for {ctx.LoginUser}");
var target = ctx.ParsePath(targetPath);
if (target is null)
return Failure($"cannot find folder {targetPath}");
return source.MoveTo(target);
}
public static Result DeleteInstallation(this LoginState ctx, String? pathToDelete)
{
var path = ctx.ParsePath(pathToDelete);
if (path?.Installation() is null)
return Failure($"cannot find {pathToDelete}");
if (!ctx.CanEdit(path))
return Failure($"operation not allowed for {ctx.LoginUser}");
return path.Delete();
}
public static Result RenameInstallation(this LoginState ctx, String? installationPath, String? newName)
{
var path = ctx.ParsePath(installationPath);
var installation = path?.Installation();
if (path is null || installation is null)
return Failure($"cannot find {installationPath}");
if (newName is null)
return Failure("no name supplied");
if (!ctx.CanEdit(path))
return Failure($"operation not allowed for {ctx.LoginUser}");
installation.Name = newName;
return path.Delete();
}
public static Result DeleteFolder(this LoginState ctx, String? pathToDelete)
{
var path = ctx.ParsePath(pathToDelete);
if (path?.Folder() is null)
return Failure($"cannot find {pathToDelete}");
if (!ctx.CanEdit(path))
return Failure($"operation not allowed for {ctx.LoginUser}");
return path.Delete();
}
public static Result DeleteUser(this LoginState ctx, String? pathToDelete)
{
var path = ctx.ParsePath(pathToDelete);
if (path?.User() is null)
return Failure($"cannot find {pathToDelete}");
if (!ctx.CanEdit(path))
return Failure($"operation not allowed for {ctx.LoginUser}");
return path.Delete();
}
public static Result Rename(this LoginState ctx, String pathToRename, String newName)
{
var path = ctx.ParsePath(pathToRename);
if (path is null)
return Failure($"cannot find {pathToRename}");
if (!ctx.CanEdit(path) || path.IsUser())
return Failure("operation not permitted");
if (String.IsNullOrWhiteSpace(newName))
return Failure($"{newName} is not a valid name");
path.Element.Name = newName;
return Success($"renamed {pathToRename} to {newName}");
}
// TODO: prevent folder cycles!
// public Result AddNewFolder(String parentFolderPath, String folderName)
// {
// if (!User.CanEditFolders())
// return Failure($"operation not allowed for {User}");
//
// var parent = ParsePath(parentFolderPath);
//
// if (parent is null)
// return Failure($"cannot find folder {parentFolderPath}");
//
// return parent.AddChild(new Folder { Name = folderName });
// }
// TODO: VRM
// public Result AddNewInstallation(Int32 parentFolderId, String installationName)
// {
// if (!User.CanEditInstallations())
// throw new ApiException($"operation not allowed for {User}");
//
// var parentPath = HomeFolder.FindDescendantFolder(parentFolderId);
// var parentFolder = parentPath?.Folder();
//
// if (parentFolder is null)
// return new Failure($"cannot find folder {parentFolderId}");
//
// var newInstallation = new Installation { Name = installationName };
// parentFolder.Add(newInstallation);
//
// return new Success($"added new {newInstallation} to {parentPath}");
// }
public static Result CreateUser(this LoginState loginState, String? parentPath, String? userName, String? userType)
{
const String allowedSpecialChars = "_-.@";
if (!loginState.LoginUser.CanEditUsers())
return Failure($"operation not allowed for {loginState.LoginUser}");
if (userName is null || userName.Length < 3)
return Failure("username must consist of at least 3 characters");
if (!userName.All(c => Char.IsLetter(c) || Char.IsDigit(c) || allowedSpecialChars.Contains(c)))
{
return Failure("Illegal character in username.\n" +
"The username can contain letters, digits and the following the following characters:\n" +
allowedSpecialChars);
}
var path = loginState.ParsePath(parentPath);
if (path is null)
return Failure($"cannot find parent {parentPath}");
var type = ParseUserType(userType);
if (type == UserType.Unknown)
return Failure($"unknown user type {type}");
var newUser = new User
{
Name = userName,
UserType = type
};
return path.AddChild(newUser);
}
public static Result EditUser(this LoginState loginState, String? userPath, String? userType)
{
if (!loginState.LoginUser.CanEditUsers())
return Failure($"operation not permitted for {loginState.LoginUser}");
var user = loginState.ParsePath(userPath).User();
if (user == loginState.LoginUser)
return Failure($"operation not permitted for {loginState.LoginUser}");
if (user is null)
return Failure($"cannot find user {userPath}");
var oldType = user.UserType;
var newType = ParseUserType(userType);
if (newType == UserType.Unknown)
return Failure($"unknown user type {newType}");
user.UserType = newType;
return Success($"Changed user type of user {userPath} from {oldType} to {newType}");
}
private static UserType ParseUserType(String? userType)
{
return userType switch
{
"Viewer" => UserType.Viewer,
"Editor" => UserType.Editor,
"Admin" => UserType.Admin,
_ => UserType.Unknown
};
}
// public Result ChangeUserType(Int32 userId, UserType userType)
// {
// if (!User.CanEditUsers() || userId == User.Id)
// return Failure($"operation not allowed for {User}");
//
// var userToEdit = HomeFolder.FindDescendantUser(userId)?.User();
//
// if (userToEdit is null)
// return Failure($"cannot find user {userId}");
//
// var oldUserType = userToEdit.UserType;
// userToEdit.UserType = userType;
//
// return Success($"changed type of user {userToEdit} from {oldUserType} to {userType}");
// }
private static Path? ParsePath(this LoginState uc, String? path)
{
if (path == null)
return null;
var splitPath = path
.Split("|", StringSplitOptions.TrimEntries | StringSplitOptions.RemoveEmptyEntries)
.Skip(1);
return uc
.HomeFolder
.RelativePath()
.GetDescendant(splitPath);
}
}

View File

@ -1,30 +0,0 @@
using InnovEnergy.API.DataModel;
namespace InnovEnergy.API;
public class LoginState
{
public static readonly Random Rng = new Random();
public User LoginUser { get; }
public Folder HomeFolder { get; }
public String Token { get; }
public String? Error { get; set; }
public Int32 DataVersion { get; set; }
public LoginState(User loginUser, Folder homeFolder, Int32 dataVersion)
{
LoginUser = loginUser;
HomeFolder = homeFolder;
DataVersion = dataVersion;
Token = GenerateToken();
}
private static String GenerateToken()
{
var buffer = new Byte[16];
Rng.NextBytes(buffer);
return Convert.ToBase64String(buffer);
}
}

View File

@ -1,25 +0,0 @@
using System.Runtime.CompilerServices;
using static System.Runtime.CompilerServices.MethodImplOptions;
namespace InnovEnergy.API;
public static class PathExtensions
{
[MethodImpl(AggressiveInlining)]
public static String GetFileNameWithoutExtension(this String path) => Path.GetFileNameWithoutExtension(path);
[MethodImpl(AggressiveInlining)]
public static String GetFileName(this String path) => Path.GetFileName(path);
[MethodImpl(AggressiveInlining)]
public static String GetExtension(this String path) => Path.GetExtension(path);
[MethodImpl(AggressiveInlining)]
public static IEnumerable<String> GetDirectories(this String path) => Directory.EnumerateDirectories(path);
[MethodImpl(AggressiveInlining)]
public static IEnumerable<String> GetFiles(this String path) => Directory.EnumerateFiles(path);
}

View File

@ -1,202 +0,0 @@
using Flurl;
using InnovEnergy.API.DataModel;
using InnovEnergy.Lib.WebServer;
using InnovEnergy.Lib.Utils;
using Newtonsoft.Json;
using static System.Text.Encoding;
using static InnovEnergy.Lib.WebServer.Default;
namespace InnovEnergy.API;
public static class Program
{
public static String RootDir { get; private set; } = "/home/eef/sync/work/Code/innovenergy/server/WebMonitoring/src";
public static Data Data { get; set; }
public static Dictionary<String, LoginState> LoggedInUsers { get; } = new Dictionary<String, LoginState>();
public static void Main(String[] args)
{
RootDir = args.FirstOrDefault() ?? RootDir;
Console.WriteLine("start");
#pragma warning disable 4014
SyncWithVrm();
#pragma warning restore 4014
Data = Data.Load();
WebServer.ServeOnLocalHost(8080, Serve);
Console.WriteLine("stop");
}
private static async Task SyncWithVrm()
{
Console.WriteLine("Starting VRM sync");
var vrmLink = await VrmLink.Login();
while (true)
{
try
{
var data = Data.Load();
var json = data.SerializeJson();
await vrmLink.SyncWithVrm(data);
var changed = json != data.SerializeJson();
if (changed)
{
data.Save("Synced from VRM", "system");
var edit = data.Edit;
Console.WriteLine($"{edit.TimeStamp} [{edit.Version}] {edit.Action}");
Data = data;
}
await Task.Delay(TimeSpan.FromMinutes(10));
}
catch (Exception e)
{
Console.WriteLine("Failed to sync with VRM:\n" + e);
}
}
}
public static HttpResponse Serve(HttpRequest request)
{
var pathSegments = request.Url.PathSegments;
var p0 = pathSegments.ElementAtOrDefault(0);
Console.WriteLine(p0);
return p0 switch
{
"api" => ServeApi(request),
_ => ServeAssets(request)
};
}
private static HttpResponse Login(QueryParamCollection query)
{
var userName = query.FirstOrDefault("username") as String;
var password = query.FirstOrDefault("password") as String;
// TODO: password check
if (String.IsNullOrEmpty(userName))
return HttpForbidden;
var userPath = Data.Root.FindDescendantUser(userName);
var user = userPath?.User();
var homeFolder = userPath?.Parent.Folder();
if (user is null || homeFolder is null)
return HttpForbidden;
var loginState = new LoginState(user, homeFolder, Data.Edit.Version);
LoggedInUsers[loginState.Token] = loginState; // TODO: remove stale tokens
return CreateJsonResponse(loginState);
}
private static HttpResponse ServeApi(HttpRequest request)
{
var url = request.Url;
var query = url.QueryParams;
var action = query.FirstOrDefault("action") as String;
Console.WriteLine(action);
if (action == "login")
return Login(query);
if (query.FirstOrDefault("token") is not String token ||
!LoggedInUsers.TryGetValue(token, out var loginState))
return HttpForbidden;
var result = action switch
{
"createUser" => Api.CreateUser(query, loginState),
"editUser" => Api.EditUser(query, loginState),
"renameInstallation" => Api.RenameInstallation(query, loginState),
// "deleteUser" => Api.DeleteUser(query, loginState),
// "deleteFolder" => Api.DeleteFolder(query, loginState),
// "deleteInstallation" => Api.DeleteInstallation(query, loginState),
//"rename" => Api.Delete(query, loginState),
_ => Result.Failure("unsupported api call")
};
return result
.WriteToDisk(loginState.LoginUser)
.CreateResponse(loginState);
}
private static HttpResponse ServeAssets(HttpRequest request)
{
var localPath = RootDir + request.Url.Path;
if (request.Url.PathSegments.Count == 0)
localPath = RootDir + "/index.html";
Console.WriteLine(request.Url + " => " + localPath + " | " + InferContentType.FromExtension(localPath));
if (!File.Exists(localPath))
{
Console.WriteLine("404");
return HttpNotFound;
}
return new HttpResponse
{
Content = File.ReadAllBytes(localPath), // TODO: cache?
ContentType = InferContentType.FromExtension(localPath)
};
}
private static Result WriteToDisk(this Result result, User loggedInUser)
{
if (result.Succeeded)
{
Data.Save(result.Message, loggedInUser.Name);
}
return result;
}
private static HttpResponse CreateResponse(this Result result, LoginState loginState)
{
loginState.DataVersion = Data.Edit.Version; // important!
loginState.Error = result.Succeeded ? null : result.Message;
return CreateJsonResponse(loginState);
}
private static HttpResponse CreateJsonResponse<T>(T payload)
{
var json = JsonConvert.SerializeObject(payload, Data.WireFormatJsonSettings);
return new HttpResponse
{
Content = json.Apply(UTF8.GetBytes),
ContentType = ContentType.ApplicationJson,
Headers = new[] { new HttpHeader("Access-Control-Allow-Origin", "*") }
};
}
}

View File

@ -1,17 +0,0 @@
namespace InnovEnergy.API;
public class Result
{
public String Message { get; }
public Boolean Succeeded { get; }
public Boolean Failed => !Succeeded;
public static Result Success(String message = "") => new Result(message, succeeded: true);
public static Result Failure(String message = "") => new Result(message, succeeded: false);
private Result(String message, Boolean succeeded)
{
Message = message;
Succeeded = succeeded;
}
}

View File

@ -1,146 +0,0 @@
using System.Text.RegularExpressions;
using InnovEnergy.API.DataModel;
using InnovEnergy.Lib.Utils;
using InnovEnergy.Lib.Victron.VictronVRM;
namespace InnovEnergy.API;
public class VrmLink : IDisposable
{
private static readonly Regex RxSerial = new Regex(@"\s*\(\s*20\d\d-\d\d\d\d\d(\.\d)?\s*\)\s*", RegexOptions.Compiled | RegexOptions.Singleline);
private Vrm Vrm { get; }
private VrmLink(Vrm vrm)
{
Vrm = vrm;
}
public static async Task<VrmLink> Login()
{
const String vrmUser = "victron@innov.energy";
const String vrmPwd = "NnoVctr201002";
var vrm = await Vrm.Login(vrmUser, vrmPwd);
return new VrmLink(vrm);
}
public async Task SyncWithVrm(Data data)
{
var installationDetails = Vrm.GetInstallationDetailsAsync();
// var vpnIpLookup = Vpn.CreateVpnIpLookup();
// var vpnOnlineLookup = Vpn.CreateVpnOnlineLookup();
var vpnIpLookup = (String s) => "127.0.0.1";
var vpnOnlineLookup = (String s) => true;
var vrmInstallationsById = data
.Root
.DescendantInstallations()
.Where(d => (d.Element as VrmInstallation)?.UniqueId != null)
.ToDictionary(d => d.Element.CastTo<VrmInstallation>().UniqueId!);
List<User> DeleteExistingInstallation(InstallationDetails details)
{
vrmInstallationsById.TryGetValue(details.Identifier, out var existing);
if (existing is null)
return new List<User>();
// if it already exists, delete it, but keep its users
var installation = existing.Installation()!;
var users = installation.Users;
installation.Users = new List<User>();
existing.Delete();
return users;
}
// SYNC
await foreach (var i in installationDetails)
{
if (!i.IsActive) continue;
var (name, path, ieSerial) = ParseVrmName(i);
var users = DeleteExistingInstallation(i);
var installation = new VrmInstallation
{
Name = name,
Users = users,
IeSerial = ieSerial,
VrmId = i.IdSite,
UniqueId = i.Identifier,
FirmwareVersion = i.FirmwareVersion,
SystemType = i.SystemType,
MachineSerial = i.MachineSerial,
MachineName = i.MachineName, // type: VenusGx, CCGX, etc.
Tags = i.Tags,
VpnIp = vpnIpLookup(i.MachineSerial),
Online = vpnOnlineLookup(i.MachineSerial),
};
if (i.MachineName is not null)
await Vrm.AddTags(i.IdSite, i.MachineName);
var folder = data.GetOrCreateFolder(path);
folder.Add(installation);
}
// SORT
foreach (var folder in data.Root.DescendantFolders().Select(d => d.Element).OfType<Folder>())
{
folder.Folders.Sort();
folder.Installations.Sort();
folder.Users.Sort();
var grouped = folder.Installations.OfType<VrmInstallation>().GroupBy(i=>i.Name);
foreach (var g in grouped.Where(g => g.Count() > 1))
foreach (var (vrmInstallation, n) in g.OrderBy(i => i.UniqueId).Select((i, n) => (i, n)))
{
vrmInstallation.Name += $" ({n + 1})";
}
foreach (var installation in folder.Installations)
installation.Users.Sort();
}
}
private static (String name, IReadOnlyList<String> path, String? serial) ParseVrmName(InstallationDetails installationDetails)
{
var fullName = installationDetails.Name;
var match = RxSerial.Match(fullName); // extract IeSerial from _entire_ fullname
var serial = match.Success
? match.Value
: null;
fullName = RxSerial.Replace(fullName, "");
var split = fullName.Split('|', StringSplitOptions.TrimEntries | StringSplitOptions.RemoveEmptyEntries);
var path = split.Length > 1
? split.Skip(1).Reverse().ToArray(split.Length - 1)
: new[] { "ie" };
var name = split.Length >= 1
? split[0]
: installationDetails.Identifier;
return (name, path, serial);
}
public void Dispose() => Vrm.Dispose();
}

Binary file not shown.

View File

@ -1,468 +0,0 @@
{
"runtimeTarget": {
"name": ".NETCoreApp,Version=v6.0",
"signature": ""
},
"compilationOptions": {},
"targets": {
".NETCoreApp,Version=v6.0": {
"API/1.0.0": {
"dependencies": {
"Newtonsoft.Json": "13.0.1",
"OpenVpnCertificatesServer": "1.0.0",
"Utils": "1.0.0",
"VictronVRM": "1.0.0",
"WebServer": "1.0.0",
"sqlite-net-pcl": "1.8.116"
},
"runtime": {
"API.dll": {}
}
},
"BouncyCastle/1.8.9": {
"runtime": {
"lib/BouncyCastle.Crypto.dll": {
"assemblyVersion": "1.8.9.0",
"fileVersion": "1.8.20343.1"
}
}
},
"CliWrap/3.3.1": {
"runtime": {
"lib/netcoreapp3.0/CliWrap.dll": {
"assemblyVersion": "3.3.1.0",
"fileVersion": "3.3.1.0"
}
}
},
"Flurl/3.0.4": {
"runtime": {
"lib/netstandard2.0/Flurl.dll": {
"assemblyVersion": "3.0.4.0",
"fileVersion": "3.0.4.0"
}
}
},
"Flurl.Http/3.2.2": {
"dependencies": {
"Flurl": "3.0.4",
"Newtonsoft.Json": "13.0.1",
"System.Text.Encoding.CodePages": "4.5.1"
},
"runtime": {
"lib/netstandard2.0/Flurl.Http.dll": {
"assemblyVersion": "3.2.2.0",
"fileVersion": "3.2.2.0"
}
}
},
"Microsoft.NETCore.Platforms/2.1.2": {},
"Newtonsoft.Json/13.0.1": {
"runtime": {
"lib/netstandard2.0/Newtonsoft.Json.dll": {
"assemblyVersion": "13.0.0.0",
"fileVersion": "13.0.1.25517"
}
}
},
"SharpZipLib/1.3.3": {
"runtime": {
"lib/netstandard2.1/ICSharpCode.SharpZipLib.dll": {
"assemblyVersion": "1.3.3.11",
"fileVersion": "1.3.3.11"
}
}
},
"sqlite-net-pcl/1.8.116": {
"dependencies": {
"SQLitePCLRaw.bundle_green": "2.0.4"
},
"runtime": {
"lib/netstandard2.0/SQLite-net.dll": {
"assemblyVersion": "1.8.116.0",
"fileVersion": "1.8.116.0"
}
}
},
"SQLitePCLRaw.bundle_green/2.0.4": {
"dependencies": {
"SQLitePCLRaw.core": "2.0.4",
"SQLitePCLRaw.lib.e_sqlite3": "2.0.4",
"SQLitePCLRaw.provider.dynamic_cdecl": "2.0.4"
},
"runtime": {
"lib/netcoreapp3.1/SQLitePCLRaw.batteries_v2.dll": {
"assemblyVersion": "2.0.4.976",
"fileVersion": "2.0.4.976"
},
"lib/netcoreapp3.1/SQLitePCLRaw.nativelibrary.dll": {
"assemblyVersion": "2.0.4.976",
"fileVersion": "2.0.4.976"
}
}
},
"SQLitePCLRaw.core/2.0.4": {
"dependencies": {
"System.Memory": "4.5.3"
},
"runtime": {
"lib/netstandard2.0/SQLitePCLRaw.core.dll": {
"assemblyVersion": "2.0.4.976",
"fileVersion": "2.0.4.976"
}
}
},
"SQLitePCLRaw.lib.e_sqlite3/2.0.4": {
"runtimeTargets": {
"runtimes/alpine-x64/native/libe_sqlite3.so": {
"rid": "alpine-x64",
"assetType": "native",
"fileVersion": "0.0.0.0"
},
"runtimes/linux-arm/native/libe_sqlite3.so": {
"rid": "linux-arm",
"assetType": "native",
"fileVersion": "0.0.0.0"
},
"runtimes/linux-arm64/native/libe_sqlite3.so": {
"rid": "linux-arm64",
"assetType": "native",
"fileVersion": "0.0.0.0"
},
"runtimes/linux-armel/native/libe_sqlite3.so": {
"rid": "linux-armel",
"assetType": "native",
"fileVersion": "0.0.0.0"
},
"runtimes/linux-mips64/native/libe_sqlite3.so": {
"rid": "linux-mips64",
"assetType": "native",
"fileVersion": "0.0.0.0"
},
"runtimes/linux-musl-x64/native/libe_sqlite3.so": {
"rid": "linux-musl-x64",
"assetType": "native",
"fileVersion": "0.0.0.0"
},
"runtimes/linux-x64/native/libe_sqlite3.so": {
"rid": "linux-x64",
"assetType": "native",
"fileVersion": "0.0.0.0"
},
"runtimes/linux-x86/native/libe_sqlite3.so": {
"rid": "linux-x86",
"assetType": "native",
"fileVersion": "0.0.0.0"
},
"runtimes/osx-x64/native/libe_sqlite3.dylib": {
"rid": "osx-x64",
"assetType": "native",
"fileVersion": "0.0.0.0"
},
"runtimes/win-arm/native/e_sqlite3.dll": {
"rid": "win-arm",
"assetType": "native",
"fileVersion": "0.0.0.0"
},
"runtimes/win-arm64/native/e_sqlite3.dll": {
"rid": "win-arm64",
"assetType": "native",
"fileVersion": "0.0.0.0"
},
"runtimes/win-x64/native/e_sqlite3.dll": {
"rid": "win-x64",
"assetType": "native",
"fileVersion": "0.0.0.0"
},
"runtimes/win-x86/native/e_sqlite3.dll": {
"rid": "win-x86",
"assetType": "native",
"fileVersion": "0.0.0.0"
}
}
},
"SQLitePCLRaw.provider.dynamic_cdecl/2.0.4": {
"dependencies": {
"SQLitePCLRaw.core": "2.0.4"
},
"runtime": {
"lib/netstandard2.0/SQLitePCLRaw.provider.dynamic_cdecl.dll": {
"assemblyVersion": "2.0.4.976",
"fileVersion": "2.0.4.976"
}
}
},
"System.Memory/4.5.3": {},
"System.Reactive/5.0.0": {
"runtime": {
"lib/net5.0/System.Reactive.dll": {
"assemblyVersion": "5.0.0.0",
"fileVersion": "5.0.0.1"
}
}
},
"System.Reactive.Linq/5.0.0": {
"dependencies": {
"System.Reactive": "5.0.0",
"System.Threading.Tasks.Extensions": "4.5.4"
},
"runtime": {
"lib/netstandard2.0/System.Reactive.Linq.dll": {
"assemblyVersion": "3.0.6000.0",
"fileVersion": "0.0.0.0"
}
}
},
"System.Runtime.CompilerServices.Unsafe/6.0.0": {},
"System.Text.Encoding.CodePages/4.5.1": {
"dependencies": {
"Microsoft.NETCore.Platforms": "2.1.2",
"System.Runtime.CompilerServices.Unsafe": "6.0.0"
}
},
"System.Text.Encodings.Web/6.0.0": {
"dependencies": {
"System.Runtime.CompilerServices.Unsafe": "6.0.0"
}
},
"System.Text.Json/6.0.2": {
"dependencies": {
"System.Runtime.CompilerServices.Unsafe": "6.0.0",
"System.Text.Encodings.Web": "6.0.0"
},
"runtime": {
"lib/net6.0/System.Text.Json.dll": {
"assemblyVersion": "6.0.0.0",
"fileVersion": "6.0.222.6406"
}
}
},
"System.Threading.Tasks.Extensions/4.5.4": {},
"OpenVpnCertificatesServer/1.0.0": {
"dependencies": {
"BouncyCastle": "1.8.9",
"Flurl.Http": "3.2.2",
"SharpZipLib": "1.3.3",
"Utils": "1.0.0",
"VictronVRM": "1.0.0"
},
"runtime": {
"OpenVpnCertificatesServer.dll": {}
}
},
"SysTools/1.0.0": {
"dependencies": {
"System.Reactive.Linq": "5.0.0"
},
"runtime": {
"SysTools.dll": {}
}
},
"Utils/1.0.0": {
"dependencies": {
"CliWrap": "3.3.1",
"System.Reactive.Linq": "5.0.0"
},
"runtime": {
"Utils.dll": {}
}
},
"VictronVRM/1.0.0": {
"dependencies": {
"Flurl.Http": "3.2.2",
"Newtonsoft.Json": "13.0.1",
"SysTools": "1.0.0",
"System.Reactive.Linq": "5.0.0",
"System.Text.Json": "6.0.2",
"Utils": "1.0.0"
},
"runtime": {
"VictronVRM.dll": {}
}
},
"WebServer/1.0.0": {
"dependencies": {
"Flurl": "3.0.4",
"Flurl.Http": "3.2.2",
"System.Reactive.Linq": "5.0.0",
"Utils": "1.0.0"
},
"runtime": {
"WebServer.dll": {}
}
}
}
},
"libraries": {
"API/1.0.0": {
"type": "project",
"serviceable": false,
"sha512": ""
},
"BouncyCastle/1.8.9": {
"type": "package",
"serviceable": true,
"sha512": "sha512-axnBgvdD5n+FnEG6efk/tfKuMFru7R/EoISH9zjh319yb3HD24TEHSAbNN/lTRT2ulOGRxDgOsCjkuk08iwWPg==",
"path": "bouncycastle/1.8.9",
"hashPath": "bouncycastle.1.8.9.nupkg.sha512"
},
"CliWrap/3.3.1": {
"type": "package",
"serviceable": true,
"sha512": "sha512-yFJBBbDCSJ9ZgllaJub07K04EYf54V4jZ2Cm6Sg3KrGfiy27J4ed/os7UqqN7SXoIVL5ru442nPXe0sbsx2wVg==",
"path": "cliwrap/3.3.1",
"hashPath": "cliwrap.3.3.1.nupkg.sha512"
},
"Flurl/3.0.4": {
"type": "package",
"serviceable": true,
"sha512": "sha512-2bgCzOs3TGwRkfcijCiH+7o9Pz4pyVnt4yyLX2vD3wlMSekpmGhqe2zA4988qSMmPa6AqeekX13CY4FvsjsDJQ==",
"path": "flurl/3.0.4",
"hashPath": "flurl.3.0.4.nupkg.sha512"
},
"Flurl.Http/3.2.2": {
"type": "package",
"serviceable": true,
"sha512": "sha512-zVen69D8Qr1uZN4ua0ZnOMuDZol66w04AnwOSCyE5Kqy5GGbAtk0m7bKXaU+FJJ9R7ByVIKAG/kpGbGMGdt2/Q==",
"path": "flurl.http/3.2.2",
"hashPath": "flurl.http.3.2.2.nupkg.sha512"
},
"Microsoft.NETCore.Platforms/2.1.2": {
"type": "package",
"serviceable": true,
"sha512": "sha512-mOJy3M0UN+LUG21dLGMxaWZEP6xYpQEpLuvuEQBaownaX4YuhH6NmNUlN9si+vNkAS6dwJ//N1O4DmLf2CikVg==",
"path": "microsoft.netcore.platforms/2.1.2",
"hashPath": "microsoft.netcore.platforms.2.1.2.nupkg.sha512"
},
"Newtonsoft.Json/13.0.1": {
"type": "package",
"serviceable": true,
"sha512": "sha512-ppPFpBcvxdsfUonNcvITKqLl3bqxWbDCZIzDWHzjpdAHRFfZe0Dw9HmA0+za13IdyrgJwpkDTDA9fHaxOrt20A==",
"path": "newtonsoft.json/13.0.1",
"hashPath": "newtonsoft.json.13.0.1.nupkg.sha512"
},
"SharpZipLib/1.3.3": {
"type": "package",
"serviceable": true,
"sha512": "sha512-N8+hwhsKZm25tDJfWpBSW7EGhH/R7EMuiX+KJ4C4u+fCWVc1lJ5zg1u3S1RPPVYgTqhx/C3hxrqUpi6RwK5+Tg==",
"path": "sharpziplib/1.3.3",
"hashPath": "sharpziplib.1.3.3.nupkg.sha512"
},
"sqlite-net-pcl/1.8.116": {
"type": "package",
"serviceable": true,
"sha512": "sha512-W0NuwAOVVAR9LP4eZwNBIrim1p3EN7t8iNfSHXEhtzKAd4YyItekoQ8NyWYs4faVSrN2KZr/P5u4hycCjKKexg==",
"path": "sqlite-net-pcl/1.8.116",
"hashPath": "sqlite-net-pcl.1.8.116.nupkg.sha512"
},
"SQLitePCLRaw.bundle_green/2.0.4": {
"type": "package",
"serviceable": true,
"sha512": "sha512-ubFgOHDmtTcq2LU7Ss10yHnFVMm2rFVr65Ggi+Mh514KjGx4pal98P2zSvZtWf3wbtJw6G1InBgeozBtnpEfKQ==",
"path": "sqlitepclraw.bundle_green/2.0.4",
"hashPath": "sqlitepclraw.bundle_green.2.0.4.nupkg.sha512"
},
"SQLitePCLRaw.core/2.0.4": {
"type": "package",
"serviceable": true,
"sha512": "sha512-4XlDZpDAsboMD6qZQcz9AaKblKDUTVHF+8f3lvbP7QjoqSRr2Xc0Lm34IK2pjRIYnyFLhI3yOJ5YWfOiCid2yg==",
"path": "sqlitepclraw.core/2.0.4",
"hashPath": "sqlitepclraw.core.2.0.4.nupkg.sha512"
},
"SQLitePCLRaw.lib.e_sqlite3/2.0.4": {
"type": "package",
"serviceable": true,
"sha512": "sha512-oetvmtDZOE4Nnrtxd8Trapl9geBiu0rDCUXff46qGYjnUwzaU1mZ3OHnfR402tl32rx8gBWg3n5OBRaPJRbsGw==",
"path": "sqlitepclraw.lib.e_sqlite3/2.0.4",
"hashPath": "sqlitepclraw.lib.e_sqlite3.2.0.4.nupkg.sha512"
},
"SQLitePCLRaw.provider.dynamic_cdecl/2.0.4": {
"type": "package",
"serviceable": true,
"sha512": "sha512-AY6+vv/4ji1mCkLrS6HP/88rHT9YFKRyg3LUj8RyIk6imJMUFdQDiP8rK8gq0a/0FbqspLjK1t7rtKcr7FXRYA==",
"path": "sqlitepclraw.provider.dynamic_cdecl/2.0.4",
"hashPath": "sqlitepclraw.provider.dynamic_cdecl.2.0.4.nupkg.sha512"
},
"System.Memory/4.5.3": {
"type": "package",
"serviceable": true,
"sha512": "sha512-3oDzvc/zzetpTKWMShs1AADwZjQ/36HnsufHRPcOjyRAAMLDlu2iD33MBI2opxnezcVUtXyqDXXjoFMOU9c7SA==",
"path": "system.memory/4.5.3",
"hashPath": "system.memory.4.5.3.nupkg.sha512"
},
"System.Reactive/5.0.0": {
"type": "package",
"serviceable": true,
"sha512": "sha512-erBZjkQHWL9jpasCE/0qKAryzVBJFxGHVBAvgRN1bzM0q2s1S4oYREEEL0Vb+1kA/6BKb5FjUZMp5VXmy+gzkQ==",
"path": "system.reactive/5.0.0",
"hashPath": "system.reactive.5.0.0.nupkg.sha512"
},
"System.Reactive.Linq/5.0.0": {
"type": "package",
"serviceable": true,
"sha512": "sha512-IB4/qlV4T1WhZvM11RVoFUSZXPow9VWVeQ1uDkSKgz6bAO+gCf65H/vjrYlwyXmojSSxvfHndF9qdH43P/IuAw==",
"path": "system.reactive.linq/5.0.0",
"hashPath": "system.reactive.linq.5.0.0.nupkg.sha512"
},
"System.Runtime.CompilerServices.Unsafe/6.0.0": {
"type": "package",
"serviceable": true,
"sha512": "sha512-/iUeP3tq1S0XdNNoMz5C9twLSrM/TH+qElHkXWaPvuNOt+99G75NrV0OS2EqHx5wMN7popYjpc8oTjC1y16DLg==",
"path": "system.runtime.compilerservices.unsafe/6.0.0",
"hashPath": "system.runtime.compilerservices.unsafe.6.0.0.nupkg.sha512"
},
"System.Text.Encoding.CodePages/4.5.1": {
"type": "package",
"serviceable": true,
"sha512": "sha512-4J2JQXbftjPMppIHJ7IC+VXQ9XfEagN92vZZNoG12i+zReYlim5dMoXFC1Zzg7tsnKDM7JPo5bYfFK4Jheq44w==",
"path": "system.text.encoding.codepages/4.5.1",
"hashPath": "system.text.encoding.codepages.4.5.1.nupkg.sha512"
},
"System.Text.Encodings.Web/6.0.0": {
"type": "package",
"serviceable": true,
"sha512": "sha512-Vg8eB5Tawm1IFqj4TVK1czJX89rhFxJo9ELqc/Eiq0eXy13RK00eubyU6TJE6y+GQXjyV5gSfiewDUZjQgSE0w==",
"path": "system.text.encodings.web/6.0.0",
"hashPath": "system.text.encodings.web.6.0.0.nupkg.sha512"
},
"System.Text.Json/6.0.2": {
"type": "package",
"serviceable": true,
"sha512": "sha512-0nE2gwXLn3PTBOPwORLqwuYvWB+Beomt9ZBX+6LmogMNKUvfD1SoDb/ycB1vBntT94rGaB/SvxEyeLu14H6aEg==",
"path": "system.text.json/6.0.2",
"hashPath": "system.text.json.6.0.2.nupkg.sha512"
},
"System.Threading.Tasks.Extensions/4.5.4": {
"type": "package",
"serviceable": true,
"sha512": "sha512-zteT+G8xuGu6mS+mzDzYXbzS7rd3K6Fjb9RiZlYlJPam2/hU7JCBZBVEcywNuR+oZ1ncTvc/cq0faRr3P01OVg==",
"path": "system.threading.tasks.extensions/4.5.4",
"hashPath": "system.threading.tasks.extensions.4.5.4.nupkg.sha512"
},
"OpenVpnCertificatesServer/1.0.0": {
"type": "project",
"serviceable": false,
"sha512": ""
},
"SysTools/1.0.0": {
"type": "project",
"serviceable": false,
"sha512": ""
},
"Utils/1.0.0": {
"type": "project",
"serviceable": false,
"sha512": ""
},
"VictronVRM/1.0.0": {
"type": "project",
"serviceable": false,
"sha512": ""
},
"WebServer/1.0.0": {
"type": "project",
"serviceable": false,
"sha512": ""
}
}
}

View File

@ -1,13 +0,0 @@
{
"runtimeOptions": {
"tfm": "net6.0",
"framework": {
"name": "Microsoft.NETCore.App",
"version": "6.0.0"
},
"configProperties": {
"System.Globalization.Invariant": true,
"System.Globalization.PredefinedCulturesOnly": true
}
}
}

View File

@ -1,272 +0,0 @@
{
"runtimeTarget": {
"name": ".NETCoreApp,Version=v6.0",
"signature": ""
},
"compilationOptions": {},
"targets": {
".NETCoreApp,Version=v6.0": {
"OpenVpnCertificatesServer/1.0.0": {
"dependencies": {
"BouncyCastle": "1.8.9",
"Flurl.Http": "3.2.2",
"SharpZipLib": "1.3.3",
"Utils": "1.0.0",
"VictronVRM": "1.0.0"
},
"runtime": {
"OpenVpnCertificatesServer.dll": {}
}
},
"BouncyCastle/1.8.9": {
"runtime": {
"lib/BouncyCastle.Crypto.dll": {
"assemblyVersion": "1.8.9.0",
"fileVersion": "1.8.20343.1"
}
}
},
"CliWrap/3.3.1": {
"runtime": {
"lib/netcoreapp3.0/CliWrap.dll": {
"assemblyVersion": "3.3.1.0",
"fileVersion": "3.3.1.0"
}
}
},
"Flurl/3.0.4": {
"runtime": {
"lib/netstandard2.0/Flurl.dll": {
"assemblyVersion": "3.0.4.0",
"fileVersion": "3.0.4.0"
}
}
},
"Flurl.Http/3.2.2": {
"dependencies": {
"Flurl": "3.0.4",
"Newtonsoft.Json": "12.0.3",
"System.Text.Encoding.CodePages": "4.5.1"
},
"runtime": {
"lib/netstandard2.0/Flurl.Http.dll": {
"assemblyVersion": "3.2.2.0",
"fileVersion": "3.2.2.0"
}
}
},
"Microsoft.NETCore.Platforms/2.1.2": {},
"Newtonsoft.Json/12.0.3": {
"runtime": {
"lib/netstandard2.0/Newtonsoft.Json.dll": {
"assemblyVersion": "12.0.0.0",
"fileVersion": "12.0.3.23909"
}
}
},
"SharpZipLib/1.3.3": {
"runtime": {
"lib/netstandard2.1/ICSharpCode.SharpZipLib.dll": {
"assemblyVersion": "1.3.3.11",
"fileVersion": "1.3.3.11"
}
}
},
"System.Reactive/5.0.0": {
"runtime": {
"lib/net5.0/System.Reactive.dll": {
"assemblyVersion": "5.0.0.0",
"fileVersion": "5.0.0.1"
}
}
},
"System.Reactive.Linq/5.0.0": {
"dependencies": {
"System.Reactive": "5.0.0",
"System.Threading.Tasks.Extensions": "4.5.4"
},
"runtime": {
"lib/netstandard2.0/System.Reactive.Linq.dll": {
"assemblyVersion": "3.0.6000.0",
"fileVersion": "0.0.0.0"
}
}
},
"System.Runtime.CompilerServices.Unsafe/6.0.0": {},
"System.Text.Encoding.CodePages/4.5.1": {
"dependencies": {
"Microsoft.NETCore.Platforms": "2.1.2",
"System.Runtime.CompilerServices.Unsafe": "6.0.0"
}
},
"System.Text.Encodings.Web/6.0.0": {
"dependencies": {
"System.Runtime.CompilerServices.Unsafe": "6.0.0"
}
},
"System.Text.Json/6.0.2": {
"dependencies": {
"System.Runtime.CompilerServices.Unsafe": "6.0.0",
"System.Text.Encodings.Web": "6.0.0"
},
"runtime": {
"lib/net6.0/System.Text.Json.dll": {
"assemblyVersion": "6.0.0.0",
"fileVersion": "6.0.222.6406"
}
}
},
"System.Threading.Tasks.Extensions/4.5.4": {},
"SysTools/1.0.0": {
"dependencies": {
"System.Reactive.Linq": "5.0.0"
},
"runtime": {
"SysTools.dll": {}
}
},
"Utils/1.0.0": {
"dependencies": {
"CliWrap": "3.3.1",
"System.Reactive.Linq": "5.0.0"
},
"runtime": {
"Utils.dll": {}
}
},
"VictronVRM/1.0.0": {
"dependencies": {
"Flurl.Http": "3.2.2",
"Newtonsoft.Json": "12.0.3",
"SysTools": "1.0.0",
"System.Reactive.Linq": "5.0.0",
"System.Text.Json": "6.0.2",
"Utils": "1.0.0"
},
"runtime": {
"VictronVRM.dll": {}
}
}
}
},
"libraries": {
"OpenVpnCertificatesServer/1.0.0": {
"type": "project",
"serviceable": false,
"sha512": ""
},
"BouncyCastle/1.8.9": {
"type": "package",
"serviceable": true,
"sha512": "sha512-axnBgvdD5n+FnEG6efk/tfKuMFru7R/EoISH9zjh319yb3HD24TEHSAbNN/lTRT2ulOGRxDgOsCjkuk08iwWPg==",
"path": "bouncycastle/1.8.9",
"hashPath": "bouncycastle.1.8.9.nupkg.sha512"
},
"CliWrap/3.3.1": {
"type": "package",
"serviceable": true,
"sha512": "sha512-yFJBBbDCSJ9ZgllaJub07K04EYf54V4jZ2Cm6Sg3KrGfiy27J4ed/os7UqqN7SXoIVL5ru442nPXe0sbsx2wVg==",
"path": "cliwrap/3.3.1",
"hashPath": "cliwrap.3.3.1.nupkg.sha512"
},
"Flurl/3.0.4": {
"type": "package",
"serviceable": true,
"sha512": "sha512-2bgCzOs3TGwRkfcijCiH+7o9Pz4pyVnt4yyLX2vD3wlMSekpmGhqe2zA4988qSMmPa6AqeekX13CY4FvsjsDJQ==",
"path": "flurl/3.0.4",
"hashPath": "flurl.3.0.4.nupkg.sha512"
},
"Flurl.Http/3.2.2": {
"type": "package",
"serviceable": true,
"sha512": "sha512-zVen69D8Qr1uZN4ua0ZnOMuDZol66w04AnwOSCyE5Kqy5GGbAtk0m7bKXaU+FJJ9R7ByVIKAG/kpGbGMGdt2/Q==",
"path": "flurl.http/3.2.2",
"hashPath": "flurl.http.3.2.2.nupkg.sha512"
},
"Microsoft.NETCore.Platforms/2.1.2": {
"type": "package",
"serviceable": true,
"sha512": "sha512-mOJy3M0UN+LUG21dLGMxaWZEP6xYpQEpLuvuEQBaownaX4YuhH6NmNUlN9si+vNkAS6dwJ//N1O4DmLf2CikVg==",
"path": "microsoft.netcore.platforms/2.1.2",
"hashPath": "microsoft.netcore.platforms.2.1.2.nupkg.sha512"
},
"Newtonsoft.Json/12.0.3": {
"type": "package",
"serviceable": true,
"sha512": "sha512-6mgjfnRB4jKMlzHSl+VD+oUc1IebOZabkbyWj2RiTgWwYPPuaK1H97G1sHqGwPlS5npiF5Q0OrxN1wni2n5QWg==",
"path": "newtonsoft.json/12.0.3",
"hashPath": "newtonsoft.json.12.0.3.nupkg.sha512"
},
"SharpZipLib/1.3.3": {
"type": "package",
"serviceable": true,
"sha512": "sha512-N8+hwhsKZm25tDJfWpBSW7EGhH/R7EMuiX+KJ4C4u+fCWVc1lJ5zg1u3S1RPPVYgTqhx/C3hxrqUpi6RwK5+Tg==",
"path": "sharpziplib/1.3.3",
"hashPath": "sharpziplib.1.3.3.nupkg.sha512"
},
"System.Reactive/5.0.0": {
"type": "package",
"serviceable": true,
"sha512": "sha512-erBZjkQHWL9jpasCE/0qKAryzVBJFxGHVBAvgRN1bzM0q2s1S4oYREEEL0Vb+1kA/6BKb5FjUZMp5VXmy+gzkQ==",
"path": "system.reactive/5.0.0",
"hashPath": "system.reactive.5.0.0.nupkg.sha512"
},
"System.Reactive.Linq/5.0.0": {
"type": "package",
"serviceable": true,
"sha512": "sha512-IB4/qlV4T1WhZvM11RVoFUSZXPow9VWVeQ1uDkSKgz6bAO+gCf65H/vjrYlwyXmojSSxvfHndF9qdH43P/IuAw==",
"path": "system.reactive.linq/5.0.0",
"hashPath": "system.reactive.linq.5.0.0.nupkg.sha512"
},
"System.Runtime.CompilerServices.Unsafe/6.0.0": {
"type": "package",
"serviceable": true,
"sha512": "sha512-/iUeP3tq1S0XdNNoMz5C9twLSrM/TH+qElHkXWaPvuNOt+99G75NrV0OS2EqHx5wMN7popYjpc8oTjC1y16DLg==",
"path": "system.runtime.compilerservices.unsafe/6.0.0",
"hashPath": "system.runtime.compilerservices.unsafe.6.0.0.nupkg.sha512"
},
"System.Text.Encoding.CodePages/4.5.1": {
"type": "package",
"serviceable": true,
"sha512": "sha512-4J2JQXbftjPMppIHJ7IC+VXQ9XfEagN92vZZNoG12i+zReYlim5dMoXFC1Zzg7tsnKDM7JPo5bYfFK4Jheq44w==",
"path": "system.text.encoding.codepages/4.5.1",
"hashPath": "system.text.encoding.codepages.4.5.1.nupkg.sha512"
},
"System.Text.Encodings.Web/6.0.0": {
"type": "package",
"serviceable": true,
"sha512": "sha512-Vg8eB5Tawm1IFqj4TVK1czJX89rhFxJo9ELqc/Eiq0eXy13RK00eubyU6TJE6y+GQXjyV5gSfiewDUZjQgSE0w==",
"path": "system.text.encodings.web/6.0.0",
"hashPath": "system.text.encodings.web.6.0.0.nupkg.sha512"
},
"System.Text.Json/6.0.2": {
"type": "package",
"serviceable": true,
"sha512": "sha512-0nE2gwXLn3PTBOPwORLqwuYvWB+Beomt9ZBX+6LmogMNKUvfD1SoDb/ycB1vBntT94rGaB/SvxEyeLu14H6aEg==",
"path": "system.text.json/6.0.2",
"hashPath": "system.text.json.6.0.2.nupkg.sha512"
},
"System.Threading.Tasks.Extensions/4.5.4": {
"type": "package",
"serviceable": true,
"sha512": "sha512-zteT+G8xuGu6mS+mzDzYXbzS7rd3K6Fjb9RiZlYlJPam2/hU7JCBZBVEcywNuR+oZ1ncTvc/cq0faRr3P01OVg==",
"path": "system.threading.tasks.extensions/4.5.4",
"hashPath": "system.threading.tasks.extensions.4.5.4.nupkg.sha512"
},
"SysTools/1.0.0": {
"type": "project",
"serviceable": false,
"sha512": ""
},
"Utils/1.0.0": {
"type": "project",
"serviceable": false,
"sha512": ""
},
"VictronVRM/1.0.0": {
"type": "project",
"serviceable": false,
"sha512": ""
}
}
}

View File

@ -1,13 +0,0 @@
{
"runtimeOptions": {
"tfm": "net6.0",
"framework": {
"name": "Microsoft.NETCore.App",
"version": "6.0.0"
},
"configProperties": {
"System.Globalization.Invariant": true,
"System.Globalization.PredefinedCulturesOnly": true
}
}
}

View File

@ -1,11 +0,0 @@
#!/bin/bash
# stop on errors
set -e
printf "\n################################### publish ###################################\n\n"
dotnet publish API.csproj -c Release -r linux-x64
printf "\n################################### sync ###################################\n\n"
rsync -av bin/Release/netcoreapp5.0/linux-x64/publish/ ig@salidomo.innovenergy.ch:/home/ig/api

View File

@ -1,2 +0,0 @@
<?xml version="1.0" encoding="utf-8" standalone="no"?>
<Project ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" />

View File

@ -1,4 +0,0 @@
// <autogenerated />
using System;
using System.Reflection;
[assembly: global::System.Runtime.Versioning.TargetFrameworkAttribute(".NETCoreApp,Version=v6.0", FrameworkDisplayName = "")]

View File

@ -1,23 +0,0 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
using System;
using System.Reflection;
[assembly: System.Reflection.AssemblyMetadata("IsTrimmable", "True")]
[assembly: System.Reflection.AssemblyCompanyAttribute("InnovEnergy")]
[assembly: System.Reflection.AssemblyConfigurationAttribute("Debug")]
[assembly: System.Reflection.AssemblyFileVersionAttribute("1.0.0.0")]
[assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0")]
[assembly: System.Reflection.AssemblyProductAttribute("API")]
[assembly: System.Reflection.AssemblyTitleAttribute("API")]
[assembly: System.Reflection.AssemblyVersionAttribute("1.0.0.0")]
// Generated by the MSBuild WriteCodeFragment class.

View File

@ -1 +0,0 @@
b5bcdcd7d18bd3a9ee59e18ad3d0832e4b2db0fa

View File

@ -1,8 +0,0 @@
// <auto-generated/>
global using global::System;
global using global::System.Collections.Generic;
global using global::System.IO;
global using global::System.Linq;
global using global::System.Net.Http;
global using global::System.Threading;
global using global::System.Threading.Tasks;

View File

@ -1 +0,0 @@
26c942d0f9a2a9c4f1830357e31a4e7567969887

View File

@ -1,56 +0,0 @@
/home/kim/code/innovenergy/new/csharp/app/API/bin/Debug/net6.0/OpenVpnCertificatesServer.deps.json
/home/kim/code/innovenergy/new/csharp/app/API/bin/Debug/net6.0/OpenVpnCertificatesServer.runtimeconfig.json
/home/kim/code/innovenergy/new/csharp/app/API/bin/Debug/net6.0/OpenVpnCertificatesServer
/home/kim/code/innovenergy/new/csharp/app/API/bin/Debug/net6.0/API
/home/kim/code/innovenergy/new/csharp/app/API/bin/Debug/net6.0/API.deps.json
/home/kim/code/innovenergy/new/csharp/app/API/bin/Debug/net6.0/API.runtimeconfig.json
/home/kim/code/innovenergy/new/csharp/app/API/bin/Debug/net6.0/API.dll
/home/kim/code/innovenergy/new/csharp/app/API/bin/Debug/net6.0/ref/API.dll
/home/kim/code/innovenergy/new/csharp/app/API/bin/Debug/net6.0/API.pdb
/home/kim/code/innovenergy/new/csharp/app/API/bin/Debug/net6.0/BouncyCastle.Crypto.dll
/home/kim/code/innovenergy/new/csharp/app/API/bin/Debug/net6.0/CliWrap.dll
/home/kim/code/innovenergy/new/csharp/app/API/bin/Debug/net6.0/Flurl.dll
/home/kim/code/innovenergy/new/csharp/app/API/bin/Debug/net6.0/Flurl.Http.dll
/home/kim/code/innovenergy/new/csharp/app/API/bin/Debug/net6.0/Newtonsoft.Json.dll
/home/kim/code/innovenergy/new/csharp/app/API/bin/Debug/net6.0/ICSharpCode.SharpZipLib.dll
/home/kim/code/innovenergy/new/csharp/app/API/bin/Debug/net6.0/SQLite-net.dll
/home/kim/code/innovenergy/new/csharp/app/API/bin/Debug/net6.0/SQLitePCLRaw.batteries_v2.dll
/home/kim/code/innovenergy/new/csharp/app/API/bin/Debug/net6.0/SQLitePCLRaw.nativelibrary.dll
/home/kim/code/innovenergy/new/csharp/app/API/bin/Debug/net6.0/SQLitePCLRaw.core.dll
/home/kim/code/innovenergy/new/csharp/app/API/bin/Debug/net6.0/SQLitePCLRaw.provider.dynamic_cdecl.dll
/home/kim/code/innovenergy/new/csharp/app/API/bin/Debug/net6.0/System.Reactive.dll
/home/kim/code/innovenergy/new/csharp/app/API/bin/Debug/net6.0/System.Reactive.Linq.dll
/home/kim/code/innovenergy/new/csharp/app/API/bin/Debug/net6.0/System.Text.Json.dll
/home/kim/code/innovenergy/new/csharp/app/API/bin/Debug/net6.0/runtimes/alpine-x64/native/libe_sqlite3.so
/home/kim/code/innovenergy/new/csharp/app/API/bin/Debug/net6.0/runtimes/linux-arm/native/libe_sqlite3.so
/home/kim/code/innovenergy/new/csharp/app/API/bin/Debug/net6.0/runtimes/linux-arm64/native/libe_sqlite3.so
/home/kim/code/innovenergy/new/csharp/app/API/bin/Debug/net6.0/runtimes/linux-armel/native/libe_sqlite3.so
/home/kim/code/innovenergy/new/csharp/app/API/bin/Debug/net6.0/runtimes/linux-mips64/native/libe_sqlite3.so
/home/kim/code/innovenergy/new/csharp/app/API/bin/Debug/net6.0/runtimes/linux-musl-x64/native/libe_sqlite3.so
/home/kim/code/innovenergy/new/csharp/app/API/bin/Debug/net6.0/runtimes/linux-x64/native/libe_sqlite3.so
/home/kim/code/innovenergy/new/csharp/app/API/bin/Debug/net6.0/runtimes/linux-x86/native/libe_sqlite3.so
/home/kim/code/innovenergy/new/csharp/app/API/bin/Debug/net6.0/runtimes/osx-x64/native/libe_sqlite3.dylib
/home/kim/code/innovenergy/new/csharp/app/API/bin/Debug/net6.0/runtimes/win-arm/native/e_sqlite3.dll
/home/kim/code/innovenergy/new/csharp/app/API/bin/Debug/net6.0/runtimes/win-arm64/native/e_sqlite3.dll
/home/kim/code/innovenergy/new/csharp/app/API/bin/Debug/net6.0/runtimes/win-x64/native/e_sqlite3.dll
/home/kim/code/innovenergy/new/csharp/app/API/bin/Debug/net6.0/runtimes/win-x86/native/e_sqlite3.dll
/home/kim/code/innovenergy/new/csharp/app/API/bin/Debug/net6.0/OpenVpnCertificatesServer.dll
/home/kim/code/innovenergy/new/csharp/app/API/bin/Debug/net6.0/SysTools.dll
/home/kim/code/innovenergy/new/csharp/app/API/bin/Debug/net6.0/Utils.dll
/home/kim/code/innovenergy/new/csharp/app/API/bin/Debug/net6.0/VictronVRM.dll
/home/kim/code/innovenergy/new/csharp/app/API/bin/Debug/net6.0/WebServer.dll
/home/kim/code/innovenergy/new/csharp/app/API/bin/Debug/net6.0/Utils.pdb
/home/kim/code/innovenergy/new/csharp/app/API/bin/Debug/net6.0/VictronVRM.pdb
/home/kim/code/innovenergy/new/csharp/app/API/bin/Debug/net6.0/WebServer.pdb
/home/kim/code/innovenergy/new/csharp/app/API/bin/Debug/net6.0/OpenVpnCertificatesServer.pdb
/home/kim/code/innovenergy/new/csharp/app/API/bin/Debug/net6.0/SysTools.pdb
/home/kim/code/innovenergy/new/csharp/app/API/obj/Debug/net6.0/API.csproj.AssemblyReference.cache
/home/kim/code/innovenergy/new/csharp/app/API/obj/Debug/net6.0/API.GeneratedMSBuildEditorConfig.editorconfig
/home/kim/code/innovenergy/new/csharp/app/API/obj/Debug/net6.0/API.AssemblyInfoInputs.cache
/home/kim/code/innovenergy/new/csharp/app/API/obj/Debug/net6.0/API.AssemblyInfo.cs
/home/kim/code/innovenergy/new/csharp/app/API/obj/Debug/net6.0/API.csproj.CoreCompileInputs.cache
/home/kim/code/innovenergy/new/csharp/app/API/obj/Debug/net6.0/API.csproj.CopyComplete
/home/kim/code/innovenergy/new/csharp/app/API/obj/Debug/net6.0/API.dll
/home/kim/code/innovenergy/new/csharp/app/API/obj/Debug/net6.0/ref/API.dll
/home/kim/code/innovenergy/new/csharp/app/API/obj/Debug/net6.0/API.pdb
/home/kim/code/innovenergy/new/csharp/app/API/obj/Debug/net6.0/API.genruntimeconfig.cache

View File

@ -1 +0,0 @@
bfb409d9f9fd81349684431d00d084f9c26aa8cf