rework to Azaion.Suite, show tabs with annotator and dataset explorer

This commit is contained in:
Alex Bezdieniezhnykh
2024-11-23 08:53:12 +02:00
parent 490e90f239
commit 3b40bd601e
40 changed files with 374 additions and 284 deletions
+60 -9
View File
@@ -1,16 +1,21 @@
using System.Reflection;
using System.IO;
using System.Net.Http;
using System.Reflection;
using System.Windows;
using System.Windows.Input;
using System.Windows.Threading;
using Azaion.Annotator;
using Azaion.Annotator.DTO;
using Azaion.Annotator.Extensions;
using Azaion.Common;
using Azaion.Common.DTO;
using Azaion.Common.DTO.Config;
using Azaion.Common.Extensions;
using Azaion.Common.Services;
using Azaion.Suite.Services;
using Azaion.Suite.Services.DTO;
using Azaion.Dataset;
using Azaion.Suite.Services.DTO;
using CommandLine;
using LibVLCSharp.Shared;
using MediatR;
using Microsoft.Extensions.Configuration;
@@ -18,16 +23,53 @@ using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Newtonsoft.Json;
using Serilog;
namespace Azaion.Suite;
public partial class App : Application
public partial class App
{
private readonly IHost _host;
private readonly ILogger<App> _logger;
private readonly IMediator _mediator;
private static readonly List<string> EncryptedResources =
[
"Azaion.Annotator.dll",
"Azaion.Dataset.dll"
];
private static readonly IResourceLoader? ResourceLoader;
static App()
{
var result = Parser.Default.ParseArguments<SuiteCommandLineOptions>(Environment.GetCommandLineArgs());
if (result.Errors.Any())
return;
var configStr = File.ReadAllText(Constants.CONFIG_PATH);
var apiConfig = JsonConvert.DeserializeObject<AppConfig>(configStr)!.ApiConfig;
var api = new AzaionApiClient(new HttpClient
{
BaseAddress = new Uri(apiConfig.Url),
Timeout = TimeSpan.FromSeconds(apiConfig.TimeoutSeconds)
});
var email = result.Value.Email;
var password = result.Value.Password;
api.Login(email, password);
ResourceLoader = new ResourceLoader(email, password, api, new HardwareService());
foreach (var resource in EncryptedResources)
{
var stream = ResourceLoader.Load(resource).GetAwaiter().GetResult();
Assembly.Load(stream.ToArray());
}
new ConfigUpdater().CheckConfig();
}
public App()
{
Log.Logger = new LoggerConfiguration()
@@ -42,21 +84,30 @@ public partial class App : Application
_host = Host.CreateDefaultBuilder()
.ConfigureAppConfiguration((context, config) => config
.AddCommandLine(Environment.GetCommandLineArgs())
.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true))
.AddJsonFile(Constants.CONFIG_PATH, optional: true, reloadOnChange: true))
.ConfigureServices((context, services) =>
{
services.AddSingleton<Loader>();
services.AddSingleton<MainSuite>();
services.AddSingleton<IHardwareService, HardwareService>();
services.AddSingleton<IResourceLoader, ResourceLoader>();
services.AddSingleton<IResourceLoader>(ResourceLoader!);
services.Configure<AppConfig>(context.Configuration);
services.ConfigureSection<ApiConfig>(context.Configuration);
services.ConfigureSection<DirectoriesConfig>(context.Configuration);
services.ConfigureSection<AnnotationConfig>(context.Configuration);
services.ConfigureSection<WindowConfig>(context.Configuration);
services.ConfigureSection<AIRecognitionConfig>(context.Configuration);
services.ConfigureSection<ThumbnailConfig>(context.Configuration);
services.Configure<ApiConfig>(context.Configuration.GetSection(nameof(ApiConfig)));
services.AddSingleton<IConfigUpdater, ConfigUpdater>();
services.AddSingleton<Annotator.Annotator>();
services.AddSingleton<DatasetExplorer>();
services.AddSingleton<HelpWindow>();
services.AddSingleton<IAIDetector, YOLODetector>();
services.AddMediatR(c => c.RegisterServicesFromAssembly(Assembly.GetExecutingAssembly()));
services.AddMediatR(c => c.RegisterServicesFromAssemblies(
typeof(Annotator.Annotator).Assembly,
typeof(DatasetExplorer).Assembly));
services.AddSingleton<LibVLC>(_ => new LibVLC());
services.AddSingleton<FormState>();
services.AddSingleton<MediaPlayer>(sp =>
@@ -93,7 +144,7 @@ public partial class App : Application
{
EventManager.RegisterClassHandler(typeof(UIElement), UIElement.KeyDownEvent, new RoutedEventHandler(GlobalClick));
await _host.StartAsync();
_host.Services.GetRequiredService<Loader>().Show();
_host.Services.GetRequiredService<MainSuite>().Show();
base.OnStartup(e);
}
+4 -7
View File
@@ -10,6 +10,9 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="CommandLineParser" Version="2.9.1" />
<PackageReference Include="LibVLCSharp" Version="3.9.1" />
<PackageReference Include="LibVLCSharp.WPF" Version="3.9.1" />
<PackageReference Include="MediatR" Version="12.4.1" />
<PackageReference Include="Microsoft.Extensions.Hosting" Version="8.0.0" />
<PackageReference Include="Microsoft.Extensions.Hosting.Abstractions" Version="8.0.0" />
@@ -19,13 +22,7 @@
<PackageReference Include="Serilog.Settings.Configuration" Version="8.0.4" />
<PackageReference Include="Serilog.Sinks.Console" Version="6.0.0" />
<PackageReference Include="Serilog.Sinks.File" Version="6.0.0" />
</ItemGroup>
<ItemGroup>
<None Remove="appsettings.json" />
<Content Include="appsettings.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<PackageReference Include="VideoLAN.LibVLC.Windows" Version="3.0.21" />
</ItemGroup>
<ItemGroup>
-29
View File
@@ -1,29 +0,0 @@
using System.IO;
using System.Reflection;
using System.Runtime.Loader;
using Azaion.Suite.Services.DTO;
using Microsoft.Extensions.Options;
namespace Azaion.Suite;
public class DynamicAssemblyLoader(IOptions<LocalFilesConfig> localFilesConfig) : AssemblyLoadContext
{
private static readonly Dictionary<string?, Assembly> LoadedAssemblies = new();
static DynamicAssemblyLoader()
{
LoadedAssemblies = Default.Assemblies.ToDictionary(a => a.GetName().Name, a => a);
}
protected override Assembly Load(AssemblyName assemblyName)
{
var assembly = LoadedAssemblies.GetValueOrDefault(assemblyName.Name);
if (assembly != null)
return assembly;
var currentLocation = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location)!;
var asm = Assembly.LoadFile(Path.Combine(currentLocation, localFilesConfig.Value.DllPath, $"{assemblyName.Name!}.dll"));
return asm;
}
}
-10
View File
@@ -1,10 +0,0 @@
namespace Azaion.Suite;
public class HardwareInfo
{
public string CPU { get; set; } = null!;
public string GPU { get; set; } = null!;
public string Memory { get; set; } = null!;
public string Hash { get; set; } = null!;
}
-126
View File
@@ -1,126 +0,0 @@
<Window x:Class="Azaion.Suite.Loader"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
WindowStyle="None"
AllowsTransparency="True"
Background="Transparent"
WindowStartupLocation="CenterScreen"
Title="Azaion Annotator Security"
Height="280" Width="350">
<Border Width="350"
Height="280"
Background="DarkGray"
CornerRadius="15"
MouseMove="MainMouseMove">
<Border.Effect>
<DropShadowEffect BlurRadius="15"
Direction ="-90"
RenderingBias ="Quality"
ShadowDepth ="2"
Color ="Gray" />
</Border.Effect>
<StackPanel Orientation="Vertical"
Margin="20">
<Canvas>
<Button Padding="5" ToolTip="Закрити" Background="DarkGray" BorderBrush="DarkGray" Canvas.Left="290" Cursor="Hand"
Name="CloseBtn"
Click="CloseClick">
<Path Stretch="Fill" Fill="LightGray" Data="M5.29289 5.29289C5.68342 4.90237 6.31658 4.90237 6.70711 5.29289L12 10.5858L17.2929 5.29289C17.6834 4.90237 18.3166
4.90237 18.7071 5.29289C19.0976 5.68342 19.0976 6.31658 18.7071 6.70711L13.4142 12L18.7071 17.2929C19.0976 17.6834 19.0976 18.3166 18.7071 18.7071C18.3166
19.0976 17.6834 19.0976 17.2929 18.7071L12 13.4142L6.70711 18.7071C6.31658 19.0976 5.68342 19.0976 5.29289 18.7071C4.90237 18.3166 4.90237 17.6834 5.29289
17.2929L10.5858 12L5.29289 6.70711C4.90237 6.31658 4.90237 5.68342 5.29289 5.29289Z" />
<Button.Style>
<Style TargetType="{x:Type Button}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
<Border Background="{TemplateBinding Background}" BorderThickness="1">
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Button.Style>
</Button>
</Canvas>
<TextBlock Text="Вхід"
FontSize="25"
HorizontalAlignment="Center"
VerticalAlignment="Top"
FontWeight="Bold"
/>
<Grid VerticalAlignment="Center">
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<TextBlock Text="Email"
Grid.Row="0"
Margin="0, 20, 0, 5"
HorizontalAlignment="Left"/>
<TextBox
Name="TbEmail"
Grid.Row="1"
Padding="0,5"
Width="300"
FontSize="16"
Background="DarkGray"
BorderBrush="DimGray"
BorderThickness="0,0,0,1"
HorizontalAlignment="Left"
Text="admin@azaion.com"/>
<TextBlock Text="Пароль"
Grid.Row="2"
Margin="0, 20, 0, 5"
HorizontalAlignment="Left"/>
<PasswordBox Grid.Row="3"
Name="TbPassword"
Password="Az@1on1000Odm$n"
FontSize="16"
Background="DarkGray"
BorderBrush="DimGray"
Padding="0,5"
Width="300"
BorderThickness="0,0,0,1"
HorizontalAlignment="Left"/>
</Grid>
<Button x:Name="LoginBtn"
Content="Вхід"
Foreground="White"
Background="DimGray"
Margin="0,25"
Height="35"
Width="280"
Cursor="Hand"
Click="RunClick">
<Button.Style>
<Style TargetType="Button">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
<Border x:Name="LoginBorder" Background="{TemplateBinding Background}"
CornerRadius="16">
<ContentPresenter HorizontalAlignment="Center"
VerticalAlignment="Center"/>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Background" Value="LightGray" TargetName="LoginBorder" />
<Setter Property="TextBlock.Foreground" Value="Black" TargetName="LoginBorder" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Button.Style>
</Button>
</StackPanel>
</Border>
</Window>
-58
View File
@@ -1,58 +0,0 @@
using System.IO;
using System.Reflection;
using System.Runtime.Loader;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using Azaion.Suite.Services.DTO;
using Microsoft.Extensions.Options;
namespace Azaion.Suite;
public partial class Loader : Window
{
private readonly IResourceLoader _resourceLoader;
private readonly IOptions<LocalFilesConfig> _localFilesConfig;
public Loader(IResourceLoader resourceLoader, IOptions<LocalFilesConfig> localFilesConfig)
{
_resourceLoader = resourceLoader;
_localFilesConfig = localFilesConfig;
InitializeComponent();
}
private async void RunClick(object sender, RoutedEventArgs e)
{
var stream = new MemoryStream();
await _resourceLoader.LoadAnnotator(TbEmail.Text, TbPassword.Password, stream);
stream.Seek(0, SeekOrigin.Begin);
var loader = new AssemblyLoadContext("DynamicContext", isCollectible: true);
var annotatorAssembly = loader.LoadFromStream(stream);
var appType = annotatorAssembly.GetType("Azaion.Annotator.App");
var appInstance = Activator.CreateInstance(appType);
var runMethod = appType.GetMethod("Run", BindingFlags.Public | BindingFlags.Instance);
if (runMethod != null)
{
runMethod.Invoke(appInstance, null);
}
// var entryPoint = annotatorAssembly.EntryPoint;
// if (entryPoint == null)
// return;
//
// var o = annotatorAssembly.CreateInstance(entryPoint.Name);
// entryPoint.Invoke(o, null);
}
private void CloseClick(object sender, RoutedEventArgs e) => Close();
private void MainMouseMove(object sender, MouseEventArgs e)
{
if (e.OriginalSource is Button || e.OriginalSource is TextBox)
return;
if (e.LeftButton == MouseButtonState.Pressed)
DragMove();
}
}
+5 -2
View File
@@ -3,10 +3,13 @@
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:Azaion.Suite"
mc:Ignorable="d"
Title="MainSuite" Height="450" Width="800">
<Grid>
<TabControl Name="MainTabControl"
TabStripPlacement="Left"
Margin="0, 0, 0, 10"
Background="Black">
</TabControl>
</Grid>
</Window>
+19 -2
View File
@@ -1,19 +1,25 @@
using System.IO;
using System.Windows;
using System.Windows.Controls;
using Azaion.Annotator.Extensions;
using Azaion.Common.DTO.Config;
using Azaion.Dataset;
using Microsoft.Extensions.Options;
namespace Azaion.Suite;
public partial class MainSuite : Window
public partial class MainSuite
{
private readonly AppConfig _appConfig;
private readonly IConfigUpdater _configUpdater;
private readonly Annotator.Annotator _annotator;
private readonly DatasetExplorer _datasetExplorer;
public MainSuite(IOptions<AppConfig> appConfig, IConfigUpdater configUpdater)
public MainSuite(IOptions<AppConfig> appConfig, IConfigUpdater configUpdater, Annotator.Annotator annotator, DatasetExplorer datasetExplorer)
{
_configUpdater = configUpdater;
_annotator = annotator;
_datasetExplorer = datasetExplorer;
_appConfig = appConfig.Value;
InitializeComponent();
Loaded += OnLoaded;
@@ -41,6 +47,17 @@ public partial class MainSuite : Window
if (_appConfig.WindowConfig.FullScreen)
WindowState = WindowState.Maximized;
MainTabControl.Items.Add(new TabItem
{
Header = "Annotator",
Content = _annotator.Content
});
MainTabControl.Items.Add(new TabItem
{
Header = "Dataset Explorer",
Content = _datasetExplorer.Content
});
}
private async Task SaveUserSettings()
-38
View File
@@ -1,38 +0,0 @@
using System.IO;
using System.Reflection;
using Azaion.Suite.Services;
using Azaion.Suite.Services.DTO;
using Microsoft.Extensions.Options;
namespace Azaion.Suite;
public interface IResourceLoader
{
Task LoadAnnotator(string email, string password, Stream outStream, CancellationToken cancellationToken = default);
Assembly LoadAssembly(string name, CancellationToken cancellationToken = default);
}
public class ResourceLoader(AzaionApiClient azaionApi, IHardwareService hardwareService, IOptions<LocalFilesConfig> localFilesConfig) : IResourceLoader
{
public async Task LoadAnnotator(string email, string password, Stream outStream, CancellationToken cancellationToken = default)
{
var hardwareInfo = await hardwareService.GetHardware();
azaionApi.Login(email, password);
var key = Security.MakeEncryptionKey(email, password, hardwareInfo.Hash);
var encryptedStream = await azaionApi.GetResource(password, hardwareInfo, ResourceEnum.AnnotatorDll);
await encryptedStream.DecryptTo(outStream, key, cancellationToken);
//return Assembly.Load(stream.ToArray());
}
public Assembly LoadAssembly(string name, CancellationToken cancellationToken = default)
{
var dllValues = name.Split(",");
var dllName = $"{dllValues[0]}.dll";
var currentLocation = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location)!;
var asm = Assembly.LoadFile(Path.Combine(currentLocation, localFilesConfig.Value.DllPath, dllName));
return asm;
}
}
-85
View File
@@ -1,85 +0,0 @@
using System.IO;
using System.Net;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Security;
using System.Text;
using Azaion.Suite.Services.DTO;
using Newtonsoft.Json;
namespace Azaion.Suite.Services;
public class AzaionApiClient(HttpClient httpClient)
{
const string JSON_MEDIA = "application/json";
private string Email { get; set; } = null!;
private SecureString Password { get; set; } = new();
private string JwtToken { get; set; } = null!;
public void Login(string email, string password)
{
if (string.IsNullOrWhiteSpace(email) || string.IsNullOrWhiteSpace(password))
throw new Exception("Email or password is empty!");
Email = email;
Password = password.ToSecureString();
}
public async Task<Stream> GetResource(string password, HardwareInfo hardware, ResourceEnum resourceEnum)
{
var response = await Send(httpClient, new HttpRequestMessage(HttpMethod.Post, "/resources/get")
{
Content = new StringContent(JsonConvert.SerializeObject(new { password, hardware, resourceEnum }), Encoding.UTF8, JSON_MEDIA)
});
return await response.Content.ReadAsStreamAsync();
}
private async Task<string> Authorize()
{
if (string.IsNullOrEmpty(Email) || Password.Length == 0)
throw new Exception("Email or password is empty! Please do Login first!");
var payload = new
{
email = Email,
password = Password.ToRealString()
};
var response = await httpClient.PostAsync(
"login",
new StringContent(JsonConvert.SerializeObject(payload), Encoding.UTF8, JSON_MEDIA));
if (!response.IsSuccessStatusCode)
throw new Exception($"Login failed: {response.StatusCode}");
var responseData = await response.Content.ReadAsStringAsync();
var result = JsonConvert.DeserializeObject<LoginResponse>(responseData);
if (string.IsNullOrEmpty(result?.Token))
throw new Exception("JWT Token not found in response");
return result.Token;
}
private async Task<HttpResponseMessage> Send(HttpClient client, HttpRequestMessage request)
{
if (string.IsNullOrEmpty(JwtToken))
JwtToken = await Authorize();
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", JwtToken);
var response = await client.SendAsync(request);
if (response.StatusCode == HttpStatusCode.Unauthorized)
{
JwtToken = await Authorize();
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", JwtToken);
response = await client.SendAsync(request);
}
if (response.IsSuccessStatusCode)
return response;
var result = await response.Content.ReadAsStringAsync();
throw new Exception($"Failed: {response.StatusCode}! Result: {result}");
}
}
@@ -1,9 +0,0 @@
namespace Azaion.Suite.Services.DTO;
public enum ResourceEnum
{
None = 0,
AnnotatorDll = 10,
AIModelRKNN = 20,
AIModelONNX = 30,
}
-107
View File
@@ -1,107 +0,0 @@
using System.Diagnostics;
using System.Net.NetworkInformation;
using System.Security.Cryptography;
using System.Text;
namespace Azaion.Suite.Services;
public interface IHardwareService
{
Task<HardwareInfo> GetHardware();
}
public class HardwareService : IHardwareService
{
private const string WIN32_GET_HARDWARE_COMMAND =
"wmic OS get TotalVisibleMemorySize /Value && " +
"wmic CPU get Name /Value && " +
"wmic path Win32_VideoController get Name /Value";
private const string UNIX_GET_HARDWARE_COMMAND =
"/bin/bash -c \"free -g | grep Mem: | awk '{print $2}' && " +
"lscpu | grep 'Model name:' | cut -d':' -f2 && " +
"lspci | grep VGA | cut -d':' -f3\"";
public async Task<HardwareInfo> GetHardware()
{
try
{
var output = await RunCommand(Environment.OSVersion.Platform == PlatformID.Win32NT
? WIN32_GET_HARDWARE_COMMAND
: UNIX_GET_HARDWARE_COMMAND);
var lines = output
.Replace("TotalVisibleMemorySize=", "")
.Replace("Name=", "")
.Replace(" ", " ")
.Trim()
.Split(['\n', '\r'], StringSplitOptions.RemoveEmptyEntries);
var memoryStr = "Unknown RAM";
if (lines.Length > 0)
{
memoryStr = lines[0];
if (int.TryParse(memoryStr, out var memKb))
memoryStr = $"{Math.Round(memKb / 1024.0 / 1024.0)} Gb";
}
var hardwareInfo = new HardwareInfo
{
Memory = memoryStr,
CPU = lines.Length > 1 && string.IsNullOrEmpty(lines[1])
? "Unknown RAM"
: lines[1],
GPU = lines.Length > 2 && string.IsNullOrEmpty(lines[2])
? "Unknown GPU"
: lines[2]
};
hardwareInfo.Hash = ToHash($"Azaion_{MacAddress()}_{hardwareInfo.CPU}_{hardwareInfo.GPU}");
return hardwareInfo;
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
throw;
}
}
private string MacAddress()
{
var macAddress = NetworkInterface
.GetAllNetworkInterfaces()
.Where(nic => nic.OperationalStatus == OperationalStatus.Up)
.Select(nic => nic.GetPhysicalAddress().ToString())
.FirstOrDefault();
return macAddress ?? string.Empty;
}
private async Task<string> RunCommand(string command)
{
try
{
using var process = new Process();
process.StartInfo.FileName = Environment.OSVersion.Platform == PlatformID.Unix ? "/bin/bash" : "cmd.exe";
process.StartInfo.Arguments = Environment.OSVersion.Platform == PlatformID.Unix
? $"-c \"{command}\""
: $"/c {command}";
process.StartInfo.RedirectStandardOutput = true;
process.StartInfo.UseShellExecute = false;
process.StartInfo.CreateNoWindow = true;
process.Start();
var result = await process.StandardOutput.ReadToEndAsync();
await process.WaitForExitAsync();
return result.Trim();
}
catch
{
return string.Empty;
}
}
private static string ToHash(string str) =>
Convert.ToBase64String(SHA384.HashData(Encoding.UTF8.GetBytes(str)));
}
-83
View File
@@ -1,83 +0,0 @@
using System.IO;
using System.Runtime.InteropServices;
using System.Security;
using System.Security.Cryptography;
using System.Text;
namespace Azaion.Suite.Services;
public static class Security
{
private const int BUFFER_SIZE = 524288; // 512 KB buffer size
public static string ToHash(this string str) =>
Convert.ToBase64String(SHA384.HashData(Encoding.UTF8.GetBytes(str)));
public static string MakeEncryptionKey(string email, string password, string? hardwareHash) =>
$"{email}-{password}-{hardwareHash}-#%@AzaionKey@%#---".ToHash();
public static SecureString ToSecureString(this string str)
{
var secureString = new SecureString();
foreach (var c in str.ToCharArray())
secureString.AppendChar(c);
return secureString;
}
public static string? ToRealString(this SecureString value)
{
var valuePtr = IntPtr.Zero;
try
{
valuePtr = Marshal.SecureStringToGlobalAllocUnicode(value);
return Marshal.PtrToStringUni(valuePtr);
}
finally
{
Marshal.ZeroFreeGlobalAllocUnicode(valuePtr);
}
}
public static async Task EncryptTo(this Stream stream, Stream toStream, string key, CancellationToken cancellationToken = default)
{
if (stream is { CanRead: false }) throw new ArgumentNullException(nameof(stream));
if (key is not { Length: > 0 }) throw new ArgumentNullException(nameof(key));
using var aes = Aes.Create();
aes.Key = SHA256.HashData(Encoding.UTF8.GetBytes(key));
aes.GenerateIV();
using var encryptor = aes.CreateEncryptor(aes.Key, aes.IV);
await using var cs = new CryptoStream(toStream, encryptor, CryptoStreamMode.Write, leaveOpen: true);
// Prepend IV to the encrypted data
await toStream.WriteAsync(aes.IV.AsMemory(0, aes.IV.Length), cancellationToken);
var buffer = new byte[BUFFER_SIZE];
int bytesRead;
while ((bytesRead = await stream.ReadAsync(buffer, cancellationToken)) > 0)
await cs.WriteAsync(buffer.AsMemory(0, bytesRead), cancellationToken);
}
public static async Task DecryptTo(this Stream encryptedStream, Stream toStream, string key, CancellationToken cancellationToken = default)
{
using var aes = Aes.Create();
aes.Key = SHA256.HashData(Encoding.UTF8.GetBytes(key));
// Read the IV from the start of the input stream
var iv = new byte[aes.BlockSize / 8];
_ = await encryptedStream.ReadAsync(iv, cancellationToken);
aes.IV = iv;
using var decryptor = aes.CreateDecryptor(aes.Key, aes.IV);
await using var cryptoStream = new CryptoStream(encryptedStream, decryptor, CryptoStreamMode.Read, leaveOpen: true);
// Read and write in chunks
var buffer = new byte[BUFFER_SIZE];
int bytesRead;
while ((bytesRead = await cryptoStream.ReadAsync(buffer, cancellationToken)) > 0)
await toStream.WriteAsync(buffer.AsMemory(0, bytesRead), cancellationToken);
}
}
+12
View File
@@ -0,0 +1,12 @@
using CommandLine;
namespace Azaion.Suite.Services.DTO;
public class SuiteCommandLineOptions
{
[Option('e', "email", Required = true, HelpText = "The email for authorization.")]
public string Email { get; set; } = null!;
[Option('p', "password", Required = true, HelpText = "The password for authorization.")]
public string Password { get; set; } = null!;
}
-10
View File
@@ -1,10 +0,0 @@
{
"ApiConfig": {
"Url": "https://api.azaion.com",
"TimeoutSeconds": 20,
"RetryCount": 3
},
"LocalFilesConfig": {
"DllPath": "AzaionSuite"
}
}
+57
View File
@@ -0,0 +1,57 @@
{
"ApiConfig": {
"Url": "https://api.azaion.com",
"TimeoutSeconds": 20,
"RetryCount": 3
},
"DirectoriesConfig": {
"VideosDirectory" : "E:\\Azaion1\\Videos",
"LabelsDirectory" : "E:\\labels",
"ImagesDirectory" : "E:\\images",
"ResultsDirectory" : "E:\\results",
"ThumbnailsDirectory" : "E:\\thumbnails",
"DllCacheDirectory" : "Cache"
},
"AnnotationConfig" : {
"AnnotationClasses": [
{ "Id": 0, "Name": "Броньована техніка", "ShortName": "Бронь" },
{ "Id": 1, "Name": "Вантажівка", "ShortName": "Вантаж" },
{ "Id": 2, "Name": "Машина легкова", "ShortName": "Машина" },
{ "Id": 3, "Name": "Артилерія", "ShortName": "Арта" },
{ "Id": 4, "Name": "Тінь від техніки", "ShortName": "Тінь" },
{ "Id": 5, "Name": "Окопи", "ShortName": "Окопи" },
{ "Id": 6, "Name": "Військовий", "ShortName": "Військов" },
{ "Id": 7, "Name": "Накати", "ShortName": "Накати" },
{ "Id": 8, "Name": "Танк з захистом", "ShortName": "Танк захист" },
{ "Id": 9, "Name": "Дим", "ShortName": "Дим" },
{ "Id": 10, "Name": "Літак", "ShortName": "Літак" }
],
"LastSelectedExplorerClass": 1,
"VideoFormats": ["mov", "mp4"],
"ImageFormats": ["jpg", "jpeg", "png", "bmp", "gif"]
},
"WindowConfig": {
"WindowSize": "1920,1080",
"WindowLocation": "50,50",
"FullScreen": true,
"LeftPanelWidth": 220,
"RightPanelWidth": 220,
"ShowHelpOnStart": false
},
"AIRecognitionConfig": {
"FrameRecognitionSeconds" : 2,
"TrackingDistanceConfidence" : 0.15,
"TrackingProbabilityIncrease" : 15,
"TrackingIntersectionThreshold" : 0.8
},
"ThumbnailConfig": {
"Size" : "240,135",
"Border" : 10
}
}