add resource check

incorrect pass / hw handling in a loader
This commit is contained in:
Alex Bezdieniezhnykh
2025-06-15 15:01:55 +03:00
parent c0f8dd792d
commit def7aad833
14 changed files with 193 additions and 16 deletions
+1
View File
@@ -39,6 +39,7 @@ public enum CommandType
None = 0, None = 0,
Ok = 3, Ok = 3,
Login = 10, Login = 10,
CheckResource = 12,
ListRequest = 15, ListRequest = 15,
ListFiles = 18, ListFiles = 18,
Load = 20, Load = 20,
+1
View File
@@ -1,6 +1,7 @@
cdef enum CommandType: cdef enum CommandType:
OK = 3 OK = 3
LOGIN = 10 LOGIN = 10
CHECK_RESOURCE = 12
LIST_REQUEST = 15 LIST_REQUEST = 15
LIST_FILES = 18 LIST_FILES = 18
LOAD = 20 LOAD = 20
+1
View File
@@ -10,6 +10,7 @@ cdef class RemoteCommand:
command_type_names = { command_type_names = {
3: "OK", 3: "OK",
10: "LOGIN", 10: "LOGIN",
12: "CHECK_RESOURCE",
15: "LIST_REQUEST", 15: "LIST_REQUEST",
18: "LIST_FILES", 18: "LIST_FILES",
20: "LOAD", 20: "LOAD",
+1
View File
@@ -16,6 +16,7 @@ cdef class ApiClient:
cdef request(self, str method, str url, object payload, bint is_stream) cdef request(self, str method, str url, object payload, bint is_stream)
cdef list_files(self, str folder, str search_file) cdef list_files(self, str folder, str search_file)
cdef check_resource(self)
cdef load_bytes(self, str filename, str folder) cdef load_bytes(self, str filename, str folder)
cdef upload_file(self, str filename, bytes resource, str folder) cdef upload_file(self, str filename, bytes resource, str folder)
cdef load_big_file_cdn(self, str folder, str big_part) cdef load_big_file_cdn(self, str folder, str big_part)
+8 -3
View File
@@ -47,10 +47,10 @@ cdef class ApiClient:
token = response.json()["token"] token = response.json()["token"]
self.set_token(token) self.set_token(token)
except HTTPError as e: except HTTPError as e:
constants.logerror(response.json())
if response.status_code == HTTPStatus.CONFLICT:
res = response.json() res = response.json()
raise Exception(res['Message']) constants.logerror(str(res))
if response.status_code == HTTPStatus.CONFLICT:
raise Exception(f"Error {res['ErrorCode']}: {res['Message']}")
cdef set_token(self, str token): cdef set_token(self, str token):
@@ -104,6 +104,11 @@ cdef class ApiClient:
constants.log(<str> f'Get files list by {folder}') constants.log(<str> f'Get files list by {folder}')
return response.json() return response.json()
cdef check_resource(self):
cdef str hardware = HardwareService.get_hardware_info()
payload = json.dumps({ "hardware": hardware }, indent=4)
response = self.request('post', f'{self.api_url}/resources/check', payload, is_stream=False)
cdef load_bytes(self, str filename, str folder): cdef load_bytes(self, str filename, str folder):
cdef str hardware = HardwareService.get_hardware_info() cdef str hardware = HardwareService.get_hardware_info()
hw_hash = Security.get_hw_hash(hardware) hw_hash = Security.get_hw_hash(hardware)
+3 -3
View File
@@ -44,6 +44,9 @@ cdef class CommandProcessor:
if command.command_type == CommandType.LOGIN: if command.command_type == CommandType.LOGIN:
self.api_client.set_credentials(Credentials.from_msgpack(command.data)) self.api_client.set_credentials(Credentials.from_msgpack(command.data))
self.remote_handler.send(command.client_id, self.ok_response.serialize()) self.remote_handler.send(command.client_id, self.ok_response.serialize())
elif command.command_type == CommandType.CHECK_RESOURCE:
self.api_client.check_resource()
self.remote_handler.send(command.client_id, RemoteCommand(CommandType.OK).serialize())
elif command.command_type == CommandType.LOAD: elif command.command_type == CommandType.LOAD:
file_data = FileData.from_msgpack(command.data) file_data = FileData.from_msgpack(command.data)
file_bytes = self.api_client.load_bytes(file_data.filename, file_data.folder) file_bytes = self.api_client.load_bytes(file_data.filename, file_data.folder)
@@ -61,9 +64,6 @@ cdef class CommandProcessor:
data = UploadFileData.from_msgpack(command.data) data = UploadFileData.from_msgpack(command.data)
file_bytes = self.api_client.upload_big_small_resource(data.resource, data.filename, data.folder) file_bytes = self.api_client.upload_big_small_resource(data.resource, data.filename, data.folder)
self.remote_handler.send(command.client_id, RemoteCommand(CommandType.OK).serialize()) self.remote_handler.send(command.client_id, RemoteCommand(CommandType.OK).serialize())
elif command.command_type == CommandType.EXIT:
t = Thread(target=self.stop) # non-block worker:
t.start()
else: else:
pass pass
except Exception as e: except Exception as e:
+1
View File
@@ -1,6 +1,7 @@
cdef enum CommandType: cdef enum CommandType:
OK = 3 OK = 3
LOGIN = 10 LOGIN = 10
CHECK_RESOURCE = 12
LIST_REQUEST = 15 LIST_REQUEST = 15
LIST_FILES = 18 LIST_FILES = 18
LOAD = 20 LOAD = 20
+1
View File
@@ -10,6 +10,7 @@ cdef class RemoteCommand:
command_type_names = { command_type_names = {
3: "OK", 3: "OK",
10: "LOGIN", 10: "LOGIN",
12: "CHECK_RESOURCE",
15: "LIST_REQUEST", 15: "LIST_REQUEST",
18: "LIST_FILES", 18: "LIST_FILES",
20: "LOAD", 20: "LOAD",
+9 -3
View File
@@ -1,9 +1,15 @@
using MessagePack;
namespace Azaion.LoaderUI; namespace Azaion.LoaderUI;
public class ApiCredentials(string email, string pw) [MessagePackObject]
public class ApiCredentials
{ {
public string Email { get; set; } = email; [Key(nameof(Email))]
public string Password { get; set; } = pw; public string Email { get; set; } = null!;
[Key(nameof(Password))]
public string Password { get; set; } = null!;
public bool IsValid() => public bool IsValid() =>
!string.IsNullOrWhiteSpace(Email) && !string.IsNullOrWhiteSpace(Password); !string.IsNullOrWhiteSpace(Email) && !string.IsNullOrWhiteSpace(Password);
+2
View File
@@ -10,9 +10,11 @@
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="MessagePack" Version="3.1.4" />
<PackageReference Include="Microsoft.Extensions.Hosting" Version="9.0.5" /> <PackageReference Include="Microsoft.Extensions.Hosting" Version="9.0.5" />
<PackageReference Include="Microsoft.Extensions.Hosting.Abstractions" Version="9.0.5" /> <PackageReference Include="Microsoft.Extensions.Hosting.Abstractions" Version="9.0.5" />
<PackageReference Include="Microsoft.Extensions.Http" Version="9.0.5" /> <PackageReference Include="Microsoft.Extensions.Http" Version="9.0.5" />
<PackageReference Include="NetMQ" Version="4.0.1.13" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" /> <PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
<PackageReference Include="Serilog.Extensions.Hosting" Version="9.0.0" /> <PackageReference Include="Serilog.Extensions.Hosting" Version="9.0.0" />
<PackageReference Include="Serilog.Extensions.Logging" Version="9.0.1" /> <PackageReference Include="Serilog.Extensions.Logging" Version="9.0.1" />
+4
View File
@@ -6,4 +6,8 @@ public static class Constants
public const string API_URL = "https://api.azaion.com"; public const string API_URL = "https://api.azaion.com";
public const string AZAION_SUITE_EXE = "Azaion.Suite.exe"; public const string AZAION_SUITE_EXE = "Azaion.Suite.exe";
public const string SUITE_FOLDER = "suite"; public const string SUITE_FOLDER = "suite";
public const string INFERENCE_EXE = "azaion-inference";
public const string EXTERNAL_LOADER_PATH = "azaion-loader.exe";
public const int EXTERNAL_LOADER_PORT = 5020;
public const string EXTERNAL_LOADER_HOST = "127.0.0.1";
} }
+104 -6
View File
@@ -1,10 +1,15 @@
using System.Diagnostics; using System.Diagnostics;
using System.IO; using System.IO;
using System.Text;
using System.Windows; using System.Windows;
using System.Windows.Controls; using System.Windows.Controls;
using System.Windows.Input; using System.Windows.Input;
using System.Windows.Media;
using MessagePack;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options; using Microsoft.Extensions.Options;
using NetMQ;
using NetMQ.Sockets;
namespace Azaion.LoaderUI; namespace Azaion.LoaderUI;
@@ -23,17 +28,40 @@ public partial class Login
InitializeComponent(); InitializeComponent();
} }
private void SetControlsStatus(bool isLoading)
{
LoginBtn.IsEnabled = !isLoading;
TbEmail.IsEnabled = !isLoading;
TbPassword.IsEnabled = !isLoading;
LoginBtn.Cursor = isLoading ? Cursors.Wait : Cursors.Arrow;
Cursor = isLoading ? Cursors.Wait : Cursors.Arrow;
}
private async void LoginClick(object sender, RoutedEventArgs e) private async void LoginClick(object sender, RoutedEventArgs e)
{ {
var creds = new ApiCredentials(TbEmail.Text, TbPassword.Password); var creds = new ApiCredentials
{
Email = TbEmail.Text,
Password = TbPassword.Password
};
if (!creds.IsValid()) if (!creds.IsValid())
return; return;
LoginBtn.Cursor = Cursors.Wait; SetControlsStatus(isLoading: true);
Cursor = Cursors.Wait;
_azaionApi.Login(creds); _azaionApi.Login(creds);
try
{
Validate(creds);
}
catch (Exception exception)
{
_logger.LogError(exception, exception.Message);
TbStatus.Foreground = Brushes.Red;
TbStatus.Text = exception.Message;
SetControlsStatus(isLoading: false);
return;
}
TbStatus.Foreground = Brushes.Black;
var installerVersion = await GetInstallerVer(); var installerVersion = await GetInstallerVer();
var localVersion = GetLocalVer(); var localVersion = GetLocalVer();
@@ -44,12 +72,81 @@ public partial class Login
TbStatus.Text = $"Installed {installerVersion}!"; TbStatus.Text = $"Installed {installerVersion}!";
} }
else else
TbStatus.Text = $"Your version is up to date!"; TbStatus.Text = "Your version is up to date!";
Process.Start(Constants.AZAION_SUITE_EXE, $"-e {creds.Email} -p {creds.Password}"); Process.Start(Constants.AZAION_SUITE_EXE, $"-e {creds.Email} -p {creds.Password}");
await Task.Delay(800);
TbStatus.Text = "Loading...";
while (!Process.GetProcessesByName(Constants.INFERENCE_EXE).Any())
await Task.Delay(500);
await Task.Delay(500);
Close(); Close();
} }
private void Validate(ApiCredentials creds)
{
var dealer = new DealerSocket();
try
{
using var process = new Process();
process.StartInfo = new ProcessStartInfo
{
FileName = Constants.EXTERNAL_LOADER_PATH,
Arguments = $"--port {Constants.EXTERNAL_LOADER_PORT} --api {Constants.API_URL}",
CreateNoWindow = true
};
process.Start();
dealer.Options.Identity = Encoding.UTF8.GetBytes(Guid.NewGuid().ToString("N"));
dealer.Connect($"tcp://{Constants.EXTERNAL_LOADER_HOST}:{Constants.EXTERNAL_LOADER_PORT}");
var result = SendCommand(dealer, RemoteCommand.Create(CommandType.Login, creds));
if (result.CommandType != CommandType.Ok)
throw new Exception(result.Message);
result = SendCommand(dealer, RemoteCommand.Create(CommandType.CheckResource));
if (result.CommandType != CommandType.Ok)
throw new Exception(result.Message);
}
catch (Exception e)
{
_logger.LogError(e, e.Message);
throw;
}
finally
{
SendCommand(dealer, RemoteCommand.Create(CommandType.Exit));
dealer.Close();
dealer.Dispose();
}
}
private RemoteCommand SendCommand(DealerSocket dealer, RemoteCommand command, int retryCount = 30, int retryDelayMs = 800)
{
try
{
dealer.SendFrame(MessagePackSerializer.Serialize(command));
var tryNum = 0;
while (tryNum++ < retryCount)
{
if (!dealer.TryReceiveFrameBytes(TimeSpan.FromMilliseconds(retryDelayMs), out var bytes))
continue;
var res = MessagePackSerializer.Deserialize<RemoteCommand>(bytes);
if (res.CommandType == CommandType.Error)
throw new Exception(res.Message);
return res;
}
throw new Exception($"Sent {command} {retryCount} times, with wait time {retryDelayMs}ms for each call. No response from client.");
}
catch (Exception e)
{
_logger.LogError(e, e.Message);
throw;
}
}
private async Task DownloadAndRunInstaller() private async Task DownloadAndRunInstaller()
{ {
var (installerName, stream) = await _azaionApi.DownloadInstaller(_dirConfig?.SuiteInstallerDirectory ?? ""); var (installerName, stream) = await _azaionApi.DownloadInstaller(_dirConfig?.SuiteInstallerDirectory ?? "");
@@ -65,6 +162,7 @@ public partial class Login
var process = Process.Start(processInfo); var process = Process.Start(processInfo);
await process!.WaitForExitAsync(); await process!.WaitForExitAsync();
File.Delete(installerName);
} }
private async Task<Version> GetInstallerVer() private async Task<Version> GetInstallerVer()
+56
View File
@@ -0,0 +1,56 @@
using MessagePack;
namespace Azaion.LoaderUI;
[MessagePackObject]
public class RemoteCommand(CommandType commandType, byte[]? data = null, string? message = null)
{
[Key("CommandType")]
public CommandType CommandType { get; set; } = commandType;
[Key("Data")]
public byte[]? Data { get; set; } = data;
[Key("Message")]
public string? Message { get; set; } = message;
public static RemoteCommand Create(CommandType commandType) =>
new(commandType);
public static RemoteCommand Create<T>(CommandType commandType, T data, string? message = null) where T : class =>
new(commandType, MessagePackSerializer.Serialize(data), message);
public override string ToString() => $"({CommandType.ToString().ToUpper()}: Data: {Data?.Length ?? 0} bytes. Message: {Message})";
}
[MessagePackObject]
public class LoadFileData(string filename, string? folder = null )
{
[Key(nameof(Folder))]
public string? Folder { get; set; } = folder;
[Key(nameof(Filename))]
public string Filename { get; set; } = filename;
}
public enum CommandType
{
None = 0,
Ok = 3,
Login = 10,
CheckResource = 12,
ListRequest = 15,
ListFiles = 18,
Load = 20,
LoadBigSmall = 22,
UploadBigSmall = 24,
DataBytes = 25,
Inference = 30,
InferenceData = 35,
StopInference = 40,
AIAvailabilityCheck = 80,
AIAvailabilityResult = 85,
Error = 90,
Exit = 100,
}
+1 -1
View File
@@ -111,7 +111,7 @@ public partial class App
_loaderClient = new LoaderClient(initConfig.LoaderClientConfig, Log.Logger, _mainCTokenSource.Token); _loaderClient = new LoaderClient(initConfig.LoaderClientConfig, Log.Logger, _mainCTokenSource.Token);
_loaderClient.StartClient(); _loaderClient.StartClient();
_loaderClient.Connect(); //Client app should be already started by LoaderUI _loaderClient.Connect();
_loaderClient.Login(credentials); _loaderClient.Login(credentials);
var azaionApi = new AzaionApi(Log.Logger, new HttpClient { BaseAddress = new Uri(initConfig.InferenceClientConfig.ApiUrl) }, _cache, credentials); var azaionApi = new AzaionApi(Log.Logger, new HttpClient { BaseAddress = new Uri(initConfig.InferenceClientConfig.ApiUrl) }, _cache, credentials);