From 7a7cefe7b5ef3be57598675b55d24cbeb328489b Mon Sep 17 00:00:00 2001 From: shept Date: Mon, 15 Sep 2025 00:12:36 +0500 Subject: [PATCH] WIP: move logic to Core project --- .../MetaforceInstaller.Cli.csproj | 6 +- MetaforceInstaller.Cli/Program.cs | 251 ++++-------------- .../Utils/ArgumentParser.cs | 53 ++++ .../Intefaces/IAdbService.cs | 10 + .../MetaforceInstaller.Core.csproj | 19 ++ MetaforceInstaller.Core/Models/DeviceInfo.cs | 8 + .../Models/InstallationRequest.cs | 8 + .../Services/AdbService.cs | 106 ++++++++ .../adb/AdbWinApi.dll | Bin .../adb/AdbWinUsbApi.dll | Bin .../adb/adb.exe | Bin MetaforceInstaller.sln | 6 + 12 files changed, 267 insertions(+), 200 deletions(-) create mode 100644 MetaforceInstaller.Cli/Utils/ArgumentParser.cs create mode 100644 MetaforceInstaller.Core/Intefaces/IAdbService.cs create mode 100644 MetaforceInstaller.Core/MetaforceInstaller.Core.csproj create mode 100644 MetaforceInstaller.Core/Models/DeviceInfo.cs create mode 100644 MetaforceInstaller.Core/Models/InstallationRequest.cs create mode 100644 MetaforceInstaller.Core/Services/AdbService.cs rename {MetaforceInstaller.Cli => MetaforceInstaller.Core}/adb/AdbWinApi.dll (100%) rename {MetaforceInstaller.Cli => MetaforceInstaller.Core}/adb/AdbWinUsbApi.dll (100%) rename {MetaforceInstaller.Cli => MetaforceInstaller.Core}/adb/adb.exe (100%) diff --git a/MetaforceInstaller.Cli/MetaforceInstaller.Cli.csproj b/MetaforceInstaller.Cli/MetaforceInstaller.Cli.csproj index 79e2376..0f2fdaa 100644 --- a/MetaforceInstaller.Cli/MetaforceInstaller.Cli.csproj +++ b/MetaforceInstaller.Cli/MetaforceInstaller.Cli.csproj @@ -10,11 +10,9 @@ - + - - - + diff --git a/MetaforceInstaller.Cli/Program.cs b/MetaforceInstaller.Cli/Program.cs index fa8c389..ec19c2a 100644 --- a/MetaforceInstaller.Cli/Program.cs +++ b/MetaforceInstaller.Cli/Program.cs @@ -1,57 +1,53 @@ -using System.Reflection; -using AdvancedSharpAdbClient; -using AdvancedSharpAdbClient.DeviceCommands; -using AdvancedSharpAdbClient.Models; +using MetaforceInstaller.Cli.Utils; +using MetaforceInstaller.Core.Services; namespace MetaforceInstaller.Cli; -class Program +static class Program { - // 1. Получить имя апк и зипки, если не предоставлены - забить дефолтными значениями - // 2. Распаковать в временную директорию adb (готово) - // 3. Установить апк - // 4. Получить имя пакета - // 5. Сформировать строку пути для контента - // 6. Копировать зип по сформированному пути - - static AdbClient adbClient; - static DeviceData deviceData; - static void Main(string[] args) { try { - var (apkPath, zipPath, outputPath) = ParseArguments(args); + var installationRequest = ArgumentParser.ParseArguments(args); - if (string.IsNullOrEmpty(apkPath) || string.IsNullOrEmpty(zipPath) || string.IsNullOrEmpty(outputPath)) + if (installationRequest is null || + string.IsNullOrEmpty(installationRequest.ApkPath) || + string.IsNullOrEmpty(installationRequest.ZipPath) || + string.IsNullOrEmpty(installationRequest.OutputPath)) { ShowUsage(); return; } - var adbPath = ExtractAdbFiles(); + var adbService = new AdbService(); - var server = new AdbServer(); - var result = server.StartServer(adbPath, restartServerIfNewer: false); - Console.WriteLine($"ADB сервер запущен: {result}"); + adbService.InstallApk(installationRequest.ApkPath); + adbService.CopyFile(installationRequest.ZipPath, installationRequest.OutputPath); - adbClient = new AdbClient(); - - var devices = adbClient.GetDevices(); - - if (!devices.Any()) - { - Console.WriteLine("Устройства не найдены. Подключите Android-устройство и включите отладку по USB."); - return; - } - - deviceData = devices.FirstOrDefault(); - Console.WriteLine($"Найдено устройство: {deviceData.Serial}"); - Console.WriteLine($"Состояние: {deviceData.State}"); - Console.WriteLine($"Имя устройства: {deviceData.Name} - {deviceData.Model}"); - - InstallApk(apkPath); - CopyFileToDevice(zipPath, outputPath); + // var adbPath = ExtractAdbFiles(); + // + // var server = new AdbServer(); + // var result = server.StartServer(adbPath, restartServerIfNewer: false); + // Console.WriteLine($"ADB сервер запущен: {result}"); + // + // adbClient = new AdbClient(); + // + // var devices = adbClient.GetDevices(); + // + // if (!devices.Any()) + // { + // Console.WriteLine("Устройства не найдены. Подключите Android-устройство и включите отладку по USB."); + // return; + // } + // + // deviceData = devices.FirstOrDefault(); + // Console.WriteLine($"Найдено устройство: {deviceData.Serial}"); + // Console.WriteLine($"Состояние: {deviceData.State}"); + // Console.WriteLine($"Имя устройства: {deviceData.Name} - {deviceData.Model}"); + // + // InstallApk(installationRequest.ApkPath); + // CopyFileToDevice(installationRequest.ZipPath, installationRequest.OutputPath); } catch (Exception ex) { @@ -78,168 +74,31 @@ class Program Console.WriteLine(" MetaforceInstaller.exe -a app.apk -c data.zip -o /sdcard/data.zip"); } - - private static (string? apkPath, string? zipPath, string? outputPath) ParseArguments(string[] args) + private static void DrawProgressBar(int progress, long receivedBytes, long totalBytes) { - string apkPath = null; - string zipPath = null; - string outputPath = null; + Console.SetCursorPosition(0, Console.CursorTop); - for (int i = 0; i < args.Length; i++) + var barLength = 40; + var filledLength = (int)(barLength * progress / 100.0); + + var bar = "[" + new string('█', filledLength) + new string('░', barLength - filledLength) + "]"; + var bytesText = $" {FormatBytes(receivedBytes)} / {FormatBytes(totalBytes)}"; + + Console.Write($"\r{bar} {progress}%{bytesText}"); + } + + private static string FormatBytes(long bytes) + { + string[] suffixes = ["B", "KB", "MB", "GB", "TB"]; + var counter = 0; + double number = bytes; + + while (Math.Round(number / 1024) >= 1) { - switch (args[i].ToLower()) - { - case "--apk": - case "-a": - if (i + 1 < args.Length) - { - apkPath = args[i + 1]; - i++; - } - - break; - - case "--content": - case "-c": - if (i + 1 < args.Length) - { - zipPath = args[i + 1]; - i++; - } - - break; - - case "--output": - case "-o": - if (i + 1 < args.Length) - { - outputPath = args[i + 1]; - i++; - } - - break; - - case "--help": - case "-h": - ShowUsage(); - Environment.Exit(0); - break; - } + number /= 1024; + counter++; } - return (apkPath, zipPath, outputPath); + return $"{number:N1} {suffixes[counter]}"; } - - private static void ExtractResource(string resourceName, string outputPath) - { - using var stream = Assembly.GetExecutingAssembly().GetManifestResourceStream(resourceName); - using var fileStream = File.Create(outputPath); - stream.CopyTo(fileStream); - } - - private static string ExtractAdbFiles() - { - var tempDir = Path.Combine(Path.GetTempPath(), "MetaforceInstaller", "adb"); - Directory.CreateDirectory(tempDir); - - var adbPath = Path.Combine(tempDir, "adb.exe"); - - if (!File.Exists(adbPath)) - { - ExtractResource("MetaforceInstaller.Cli.adb.adb.exe", adbPath); - ExtractResource("MetaforceInstaller.Cli.adb.AdbWinApi.dll", Path.Combine(tempDir, "AdbWinApi.dll")); - ExtractResource("MetaforceInstaller.Cli.adb.AdbWinUsbApi.dll", Path.Combine(tempDir, "AdbWinUsbApi.dll")); - } - - return adbPath; - } - - private static void InstallApk(string apkPath) - { - try - { - if (!File.Exists(apkPath)) - { - Console.WriteLine($"APK файл не найден: {apkPath}"); - return; - } - - Console.WriteLine($"Установка APK: {apkPath}"); - - var packageManager = new PackageManager(adbClient, deviceData); - packageManager.InstallPackage(apkPath, new Action(o => { })); - - Console.WriteLine("APK успешно установлен!"); - } - catch (Exception ex) - { - Console.WriteLine($"Ошибка установки APK: {ex.Message}"); - } - } - -private static void CopyFileToDevice(string localPath, string remotePath) -{ - try - { - if (!File.Exists(localPath)) - { - Console.WriteLine($"Локальный файл не найден: {localPath}"); - return; - } - - Console.WriteLine($"Копирование файла {localPath} в {remotePath}"); - - var lastProgress = -1; - - using var fileStream = File.OpenRead(localPath); - var syncService = new SyncService(adbClient, deviceData); - - syncService.Push(fileStream, remotePath, UnixFileStatus.DefaultFileMode, DateTime.Now, - new Action(progress => - { - var currentProgress = progress.ProgressPercentage; - - if (currentProgress != lastProgress) - { - lastProgress = (int)currentProgress; - DrawProgressBar(lastProgress, progress.ReceivedBytesSize, progress.TotalBytesToReceive); - } - })); - - Console.WriteLine(); - Console.WriteLine("Файл успешно скопирован!"); - } - catch (Exception ex) - { - Console.WriteLine($"Ошибка копирования файла: {ex.Message}"); - } -} - -private static void DrawProgressBar(int progress, long receivedBytes, long totalBytes) -{ - Console.SetCursorPosition(0, Console.CursorTop); - - var barLength = 40; - var filledLength = (int)(barLength * progress / 100.0); - - var bar = "[" + new string('█', filledLength) + new string('░', barLength - filledLength) + "]"; - var bytesText = $" {FormatBytes(receivedBytes)} / {FormatBytes(totalBytes)}"; - - Console.Write($"\r{bar} {progress}%{bytesText}"); -} - -private static string FormatBytes(long bytes) -{ - string[] suffixes = { "B", "KB", "MB", "GB", "TB" }; - var counter = 0; - double number = bytes; - - while (Math.Round(number / 1024) >= 1) - { - number /= 1024; - counter++; - } - - return $"{number:N1} {suffixes[counter]}"; -} } \ No newline at end of file diff --git a/MetaforceInstaller.Cli/Utils/ArgumentParser.cs b/MetaforceInstaller.Cli/Utils/ArgumentParser.cs new file mode 100644 index 0000000..ffdb561 --- /dev/null +++ b/MetaforceInstaller.Cli/Utils/ArgumentParser.cs @@ -0,0 +1,53 @@ +using MetaforceInstaller.Core.Models; + +namespace MetaforceInstaller.Cli.Utils; + +public static class ArgumentParser +{ + public static InstallationRequest? ParseArguments(string[] args) + { + var result = new InstallationRequest(); + + for (var i = 0; i < args.Length; i++) + { + switch (args[i].ToLower()) + { + case "--apk": + case "-a": + if (i + 1 < args.Length) + { + result.ApkPath = args[i + 1]; + i++; + } + + break; + + case "--content": + case "-c": + if (i + 1 < args.Length) + { + result.ZipPath = args[i + 1]; + i++; + } + + break; + + case "--output": + case "-o": + if (i + 1 < args.Length) + { + result.OutputPath = args[i + 1]; + i++; + } + + break; + + case "--help": + case "-h": + return null; + } + } + + return result; + } +} \ No newline at end of file diff --git a/MetaforceInstaller.Core/Intefaces/IAdbService.cs b/MetaforceInstaller.Core/Intefaces/IAdbService.cs new file mode 100644 index 0000000..c520ed6 --- /dev/null +++ b/MetaforceInstaller.Core/Intefaces/IAdbService.cs @@ -0,0 +1,10 @@ +using MetaforceInstaller.Core.Models; + +namespace MetaforceInstaller.Core.Intefaces; + +public interface IAdbService +{ + public void InstallApk(string apkPath); + public void CopyFile(string localPath, string remotePath); + public DeviceInfo GetDeviceInfo(); +} \ No newline at end of file diff --git a/MetaforceInstaller.Core/MetaforceInstaller.Core.csproj b/MetaforceInstaller.Core/MetaforceInstaller.Core.csproj new file mode 100644 index 0000000..9b6a6fd --- /dev/null +++ b/MetaforceInstaller.Core/MetaforceInstaller.Core.csproj @@ -0,0 +1,19 @@ + + + + net8.0 + enable + enable + + + + + + + + + + + + + diff --git a/MetaforceInstaller.Core/Models/DeviceInfo.cs b/MetaforceInstaller.Core/Models/DeviceInfo.cs new file mode 100644 index 0000000..802cd3c --- /dev/null +++ b/MetaforceInstaller.Core/Models/DeviceInfo.cs @@ -0,0 +1,8 @@ +namespace MetaforceInstaller.Core.Models; + +public record DeviceInfo( + string SerialNumber, + string State, + string Model, + string Name +); \ No newline at end of file diff --git a/MetaforceInstaller.Core/Models/InstallationRequest.cs b/MetaforceInstaller.Core/Models/InstallationRequest.cs new file mode 100644 index 0000000..c64b271 --- /dev/null +++ b/MetaforceInstaller.Core/Models/InstallationRequest.cs @@ -0,0 +1,8 @@ +namespace MetaforceInstaller.Core.Models; + +public class InstallationRequest +{ + public string ApkPath { get; set; } + public string ZipPath { get; set; } + public string OutputPath { get; set; } +} \ No newline at end of file diff --git a/MetaforceInstaller.Core/Services/AdbService.cs b/MetaforceInstaller.Core/Services/AdbService.cs new file mode 100644 index 0000000..b646012 --- /dev/null +++ b/MetaforceInstaller.Core/Services/AdbService.cs @@ -0,0 +1,106 @@ +using System.Reflection; +using AdvancedSharpAdbClient; +using AdvancedSharpAdbClient.DeviceCommands; +using AdvancedSharpAdbClient.Logs; +using AdvancedSharpAdbClient.Models; +using MetaforceInstaller.Core.Intefaces; +using MetaforceInstaller.Core.Models; + +namespace MetaforceInstaller.Core.Services; + +public class AdbService : IAdbService +{ + private ILogger _logger; + private readonly AdbClient _adbClient; + private DeviceData _deviceData; + + public AdbService() + { + var adbPath = GetAdbPath(); + var server = new AdbServer(); + var serverStatus = server.StartServer(adbPath, restartServerIfNewer: false); + _adbClient = new AdbClient(); + var devices = _adbClient.GetDevices(); + _deviceData = devices.FirstOrDefault(); + } + + private void ExtractResource(string resourceName, string outputPath) + { + _logger.LogInformation($"Extracting resource: {resourceName} to {outputPath}"); + using var stream = Assembly.GetExecutingAssembly().GetManifestResourceStream(resourceName); + using var fileStream = File.Create(outputPath); + stream.CopyTo(fileStream); + _logger.LogInformation($"Resource extracted: {resourceName} to {outputPath}"); + } + + private string GetAdbPath() + { + var tempDir = Path.Combine(Path.GetTempPath(), "MetaforceInstaller", "adb"); + Directory.CreateDirectory(tempDir); + + var adbPath = Path.Combine(tempDir, "adb.exe"); + + if (File.Exists(adbPath)) return adbPath; + ExtractResource("MetaforceInstaller.Cli.adb.adb.exe", adbPath); + ExtractResource("MetaforceInstaller.Cli.adb.AdbWinApi.dll", Path.Combine(tempDir, "AdbWinApi.dll")); + ExtractResource("MetaforceInstaller.Cli.adb.AdbWinUsbApi.dll", Path.Combine(tempDir, "AdbWinUsbApi.dll")); + + return adbPath; + } + + public void InstallApk(string apkPath) + { + try + { + if (!File.Exists(apkPath)) + { + _logger.LogCritical("Error: Could not find APK file."); + return; + } + + _logger.LogInformation($"Installing APK: {apkPath}"); + + var packageManager = new PackageManager(_adbClient, _deviceData); + packageManager.InstallPackage(apkPath, o => { }); + + _logger.LogInformation("APK successfully installed!"); + } + catch (Exception ex) + { + _logger.LogCritical($"Error: {ex.Message}"); + throw; + } + } + + public void CopyFile(string localPath, string remotePath) + { + try + { + if (!File.Exists(localPath)) + { + _logger.LogCritical($"Error: Could not find file: {localPath}"); + return; + } + + _logger.LogInformation($"Copying file: {localPath} to {remotePath}"); + + using var fileStream = File.OpenRead(localPath); + var syncService = new SyncService(_adbClient, _deviceData); + + syncService.Push(fileStream, remotePath, UnixFileStatus.DefaultFileMode, DateTime.Now, + new Action(progress => { })); + + _logger.LogInformation("File successfully copied!"); + } + catch (Exception ex) + { + _logger.LogCritical($"Error: {ex.Message}"); + throw; + } + } + + public DeviceInfo GetDeviceInfo() + { + return new DeviceInfo(_deviceData.Serial, _deviceData.State.ToString(), _deviceData.Model, _deviceData.Name); + } +} \ No newline at end of file diff --git a/MetaforceInstaller.Cli/adb/AdbWinApi.dll b/MetaforceInstaller.Core/adb/AdbWinApi.dll similarity index 100% rename from MetaforceInstaller.Cli/adb/AdbWinApi.dll rename to MetaforceInstaller.Core/adb/AdbWinApi.dll diff --git a/MetaforceInstaller.Cli/adb/AdbWinUsbApi.dll b/MetaforceInstaller.Core/adb/AdbWinUsbApi.dll similarity index 100% rename from MetaforceInstaller.Cli/adb/AdbWinUsbApi.dll rename to MetaforceInstaller.Core/adb/AdbWinUsbApi.dll diff --git a/MetaforceInstaller.Cli/adb/adb.exe b/MetaforceInstaller.Core/adb/adb.exe similarity index 100% rename from MetaforceInstaller.Cli/adb/adb.exe rename to MetaforceInstaller.Core/adb/adb.exe diff --git a/MetaforceInstaller.sln b/MetaforceInstaller.sln index 44d9b89..a2406c6 100644 --- a/MetaforceInstaller.sln +++ b/MetaforceInstaller.sln @@ -2,6 +2,8 @@ Microsoft Visual Studio Solution File, Format Version 12.00 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MetaforceInstaller.Cli", "MetaforceInstaller.Cli\MetaforceInstaller.Cli.csproj", "{4928C2AC-6B63-4B18-9472-705807A15893}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MetaforceInstaller.Core", "MetaforceInstaller.Core\MetaforceInstaller.Core.csproj", "{83961B6E-21E7-4B7A-B4FA-6128A44BCE1F}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -12,5 +14,9 @@ Global {4928C2AC-6B63-4B18-9472-705807A15893}.Debug|Any CPU.Build.0 = Debug|Any CPU {4928C2AC-6B63-4B18-9472-705807A15893}.Release|Any CPU.ActiveCfg = Release|Any CPU {4928C2AC-6B63-4B18-9472-705807A15893}.Release|Any CPU.Build.0 = Release|Any CPU + {83961B6E-21E7-4B7A-B4FA-6128A44BCE1F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {83961B6E-21E7-4B7A-B4FA-6128A44BCE1F}.Debug|Any CPU.Build.0 = Debug|Any CPU + {83961B6E-21E7-4B7A-B4FA-6128A44BCE1F}.Release|Any CPU.ActiveCfg = Release|Any CPU + {83961B6E-21E7-4B7A-B4FA-6128A44BCE1F}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection EndGlobal