using System.Diagnostics; using System.IO; using System.Text; using System.Text.RegularExpressions; using System.Windows; using System.Windows.Controls; using System.Windows.Input; using System.Windows.Media; using Azaion.Common; using MessagePack; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; using NetMQ; using NetMQ.Sockets; namespace Azaion.LoaderUI; public partial class Login { private readonly IAzaionApi _azaionApi; private readonly ILogger _logger; private readonly DirectoriesConfig? _dirConfig; public Login(IAzaionApi azaionApi, IOptions directoriesConfig, ILogger logger) { _azaionApi = azaionApi; _logger = logger; _dirConfig = directoriesConfig.Value; 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) { var creds = new ApiCredentials { Email = TbEmail.Text, Password = TbPassword.Password }; if (string.IsNullOrWhiteSpace(creds.Email) || string.IsNullOrWhiteSpace(creds.Password)) return; try { SetControlsStatus(isLoading: true); _azaionApi.Login(creds); Validate(creds); TbStatus.Foreground = Brushes.Black; var installerVersion = await GetInstallerVer(); var localVersion = GetLocalVer(); var credsEncrypted = Security.Encrypt(creds); if (installerVersion > localVersion) { TbStatus.Text = $"Updating from {localVersion} to {installerVersion}..."; var (installerName, stream) = await _azaionApi.DownloadInstaller(_dirConfig?.SuiteInstallerDirectory ?? ""); var localFileStream = new FileStream(installerName, FileMode.Create, FileAccess.Write); await stream.CopyToAsync(localFileStream); localFileStream.Close(); stream.Close(); Process.Start(new ProcessStartInfo { FileName = "cmd.exe", Arguments = $"/c updater.cmd {Process.GetCurrentProcess().Id} {installerName} {Constants.AZAION_SUITE_EXE} \"{credsEncrypted}\"" }); } else { TbStatus.Text = "Your version is up to date!"; Process.Start(Constants.AZAION_SUITE_EXE, $"-c {credsEncrypted}"); await Task.Delay(800); TbStatus.Text = "Loading..."; while (!Process.GetProcessesByName(Constants.INFERENCE_EXE).Any()) await Task.Delay(500); await Task.Delay(1500); } Close(); } catch (Exception exception) { _logger.LogError(exception, exception.Message); TbStatus.Foreground = Brushes.Red; TbStatus.Text = exception.Message; SetControlsStatus(isLoading: false); } } 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(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 GetInstallerVer() { TbStatus.Text = "Checking for the newer version..."; var installerDir = string.IsNullOrWhiteSpace(_dirConfig?.SuiteInstallerDirectory) ? Constants.SUITE_FOLDER : _dirConfig.SuiteInstallerDirectory; var installerName = await _azaionApi.GetLastInstallerName(installerDir); var match = Regex.Match(installerName, @"\d+(\.\d+)+"); if (!match.Success) throw new Exception($"Can't find version in {installerName}"); return new Version(match.Value); } private Version GetLocalVer() { var localFileInfo = FileVersionInfo.GetVersionInfo(Constants.AZAION_SUITE_EXE); if (string.IsNullOrWhiteSpace(localFileInfo.ProductVersion)) throw new Exception($"Can't find {Constants.AZAION_SUITE_EXE} and its version"); return new Version(localFileInfo.FileVersion!); } 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(); } }