now with animations lol
This commit is contained in:
parent
7a7cefe7b5
commit
243224a720
6 changed files with 192 additions and 43 deletions
|
|
@ -7,6 +7,10 @@
|
||||||
<Nullable>enable</Nullable>
|
<Nullable>enable</Nullable>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\MetaforceInstaller.Core\MetaforceInstaller.Core.csproj" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="AdvancedSharpAdbClient" Version="3.4.14" />
|
<PackageReference Include="AdvancedSharpAdbClient" Version="3.4.14" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@ namespace MetaforceInstaller.Cli;
|
||||||
|
|
||||||
static class Program
|
static class Program
|
||||||
{
|
{
|
||||||
static void Main(string[] args)
|
static async Task Main(string[] args)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
|
@ -22,32 +22,29 @@ static class Program
|
||||||
|
|
||||||
var adbService = new AdbService();
|
var adbService = new AdbService();
|
||||||
|
|
||||||
adbService.InstallApk(installationRequest.ApkPath);
|
// Подписка на события прогресса
|
||||||
adbService.CopyFile(installationRequest.ZipPath, installationRequest.OutputPath);
|
adbService.ProgressChanged += OnProgressChanged;
|
||||||
|
adbService.StatusChanged += OnStatusChanged;
|
||||||
|
|
||||||
// var adbPath = ExtractAdbFiles();
|
// Получение информации об устройстве
|
||||||
//
|
var deviceInfo = adbService.GetDeviceInfo();
|
||||||
// var server = new AdbServer();
|
Console.WriteLine($"Найдено устройство: {deviceInfo.SerialNumber}");
|
||||||
// var result = server.StartServer(adbPath, restartServerIfNewer: false);
|
Console.WriteLine($"Состояние: {deviceInfo.State}");
|
||||||
// Console.WriteLine($"ADB сервер запущен: {result}");
|
Console.WriteLine($"Модель: {deviceInfo.Model} - {deviceInfo.Name}");
|
||||||
//
|
Console.WriteLine();
|
||||||
// adbClient = new AdbClient();
|
|
||||||
//
|
// Создание объекта для отслеживания прогресса
|
||||||
// var devices = adbClient.GetDevices();
|
var progress = new Progress<MetaforceInstaller.Core.Models.ProgressInfo>(OnProgressReport);
|
||||||
//
|
|
||||||
// if (!devices.Any())
|
// Установка APK
|
||||||
// {
|
await adbService.InstallApkAsync(installationRequest.ApkPath, progress);
|
||||||
// Console.WriteLine("Устройства не найдены. Подключите Android-устройство и включите отладку по USB.");
|
Console.WriteLine();
|
||||||
// return;
|
|
||||||
// }
|
// Копирование файла
|
||||||
//
|
await adbService.CopyFileAsync(installationRequest.ZipPath, installationRequest.OutputPath, progress);
|
||||||
// deviceData = devices.FirstOrDefault();
|
Console.WriteLine();
|
||||||
// Console.WriteLine($"Найдено устройство: {deviceData.Serial}");
|
|
||||||
// Console.WriteLine($"Состояние: {deviceData.State}");
|
Console.WriteLine("Операция завершена успешно!");
|
||||||
// Console.WriteLine($"Имя устройства: {deviceData.Name} - {deviceData.Model}");
|
|
||||||
//
|
|
||||||
// InstallApk(installationRequest.ApkPath);
|
|
||||||
// CopyFileToDevice(installationRequest.ZipPath, installationRequest.OutputPath);
|
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
|
|
@ -55,6 +52,29 @@ static class Program
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static void OnProgressChanged(object? sender, MetaforceInstaller.Core.Models.ProgressInfo e)
|
||||||
|
{
|
||||||
|
DrawProgressBar(e.PercentageComplete, e.BytesTransferred, e.TotalBytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void OnStatusChanged(object? sender, string e)
|
||||||
|
{
|
||||||
|
Console.WriteLine(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void OnProgressReport(MetaforceInstaller.Core.Models.ProgressInfo progressInfo)
|
||||||
|
{
|
||||||
|
if (progressInfo.TotalBytes > 0)
|
||||||
|
{
|
||||||
|
DrawProgressBar(progressInfo.PercentageComplete, progressInfo.BytesTransferred, progressInfo.TotalBytes);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Для случаев без информации о байтах (например, установка APK)
|
||||||
|
DrawProgressBar(progressInfo.PercentageComplete, 0, 100);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void ShowUsage()
|
static void ShowUsage()
|
||||||
{
|
{
|
||||||
Console.WriteLine("Использование:");
|
Console.WriteLine("Использование:");
|
||||||
|
|
@ -82,7 +102,12 @@ static class Program
|
||||||
var filledLength = (int)(barLength * progress / 100.0);
|
var filledLength = (int)(barLength * progress / 100.0);
|
||||||
|
|
||||||
var bar = "[" + new string('█', filledLength) + new string('░', barLength - filledLength) + "]";
|
var bar = "[" + new string('█', filledLength) + new string('░', barLength - filledLength) + "]";
|
||||||
var bytesText = $" {FormatBytes(receivedBytes)} / {FormatBytes(totalBytes)}";
|
|
||||||
|
string bytesText = "";
|
||||||
|
if (totalBytes > 0)
|
||||||
|
{
|
||||||
|
bytesText = $" {FormatBytes(receivedBytes)} / {FormatBytes(totalBytes)}";
|
||||||
|
}
|
||||||
|
|
||||||
Console.Write($"\r{bar} {progress}%{bytesText}");
|
Console.Write($"\r{bar} {progress}%{bytesText}");
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,18 @@
|
||||||
using MetaforceInstaller.Core.Models;
|
using MetaforceInstaller.Core.Models;
|
||||||
|
using MetaforceInstaller.Core.Models;
|
||||||
|
|
||||||
namespace MetaforceInstaller.Core.Intefaces;
|
namespace MetaforceInstaller.Core.Intefaces;
|
||||||
|
|
||||||
public interface IAdbService
|
public interface IAdbService
|
||||||
{
|
{
|
||||||
public void InstallApk(string apkPath);
|
event EventHandler<ProgressInfo>? ProgressChanged;
|
||||||
public void CopyFile(string localPath, string remotePath);
|
event EventHandler<string>? StatusChanged;
|
||||||
public DeviceInfo GetDeviceInfo();
|
|
||||||
|
Task InstallApkAsync(string apkPath, IProgress<ProgressInfo>? progress = null, CancellationToken cancellationToken = default);
|
||||||
|
Task CopyFileAsync(string localPath, string remotePath, IProgress<ProgressInfo>? progress = null, CancellationToken cancellationToken = default);
|
||||||
|
DeviceInfo GetDeviceInfo();
|
||||||
|
|
||||||
|
// Синхронные версии для обратной совместимости
|
||||||
|
void InstallApk(string apkPath);
|
||||||
|
void CopyFile(string localPath, string remotePath);
|
||||||
}
|
}
|
||||||
|
|
@ -13,7 +13,13 @@
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="8.0.0" />
|
||||||
<PackageReference Include="AdvancedSharpAdbClient" Version="3.4.14" />
|
<PackageReference Include="AdvancedSharpAdbClient" Version="3.4.14" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="AdvancedSharpAdbClient" Version="3.4.14" />
|
||||||
|
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="8.0.3" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
|
|
||||||
19
MetaforceInstaller.Core/Models/ProgressInfo.cs
Normal file
19
MetaforceInstaller.Core/Models/ProgressInfo.cs
Normal file
|
|
@ -0,0 +1,19 @@
|
||||||
|
namespace MetaforceInstaller.Core.Models;
|
||||||
|
|
||||||
|
public class ProgressInfo
|
||||||
|
{
|
||||||
|
public int PercentageComplete { get; set; }
|
||||||
|
public long BytesTransferred { get; set; }
|
||||||
|
public long TotalBytes { get; set; }
|
||||||
|
public string? Message { get; set; }
|
||||||
|
public string? CurrentFile { get; set; }
|
||||||
|
public ProgressType Type { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum ProgressType
|
||||||
|
{
|
||||||
|
Installation,
|
||||||
|
FileCopy,
|
||||||
|
Extraction,
|
||||||
|
General
|
||||||
|
}
|
||||||
|
|
@ -1,33 +1,42 @@
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using AdvancedSharpAdbClient;
|
using AdvancedSharpAdbClient;
|
||||||
using AdvancedSharpAdbClient.DeviceCommands;
|
using AdvancedSharpAdbClient.DeviceCommands;
|
||||||
using AdvancedSharpAdbClient.Logs;
|
|
||||||
using AdvancedSharpAdbClient.Models;
|
using AdvancedSharpAdbClient.Models;
|
||||||
using MetaforceInstaller.Core.Intefaces;
|
using MetaforceInstaller.Core.Intefaces;
|
||||||
using MetaforceInstaller.Core.Models;
|
using MetaforceInstaller.Core.Models;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
|
using Microsoft.Extensions.Logging.Abstractions;
|
||||||
|
|
||||||
namespace MetaforceInstaller.Core.Services;
|
namespace MetaforceInstaller.Core.Services;
|
||||||
|
|
||||||
public class AdbService : IAdbService
|
public class AdbService : IAdbService
|
||||||
{
|
{
|
||||||
private ILogger<AdbService> _logger;
|
private readonly ILogger<AdbService> _logger;
|
||||||
private readonly AdbClient _adbClient;
|
private readonly AdbClient _adbClient;
|
||||||
private DeviceData _deviceData;
|
private DeviceData _deviceData;
|
||||||
|
|
||||||
public AdbService()
|
public event EventHandler<ProgressInfo>? ProgressChanged;
|
||||||
|
public event EventHandler<string>? StatusChanged;
|
||||||
|
|
||||||
|
public AdbService(ILogger<AdbService>? logger = null)
|
||||||
{
|
{
|
||||||
|
_logger = logger ?? new NullLogger<AdbService>();
|
||||||
var adbPath = GetAdbPath();
|
var adbPath = GetAdbPath();
|
||||||
var server = new AdbServer();
|
var server = new AdbServer();
|
||||||
var serverStatus = server.StartServer(adbPath, restartServerIfNewer: false);
|
var serverStatus = server.StartServer(adbPath, restartServerIfNewer: false);
|
||||||
_adbClient = new AdbClient();
|
_adbClient = new AdbClient();
|
||||||
var devices = _adbClient.GetDevices();
|
var devices = _adbClient.GetDevices();
|
||||||
|
foreach (var device in devices)
|
||||||
|
{
|
||||||
|
Console.WriteLine(device.Model);
|
||||||
|
}
|
||||||
_deviceData = devices.FirstOrDefault();
|
_deviceData = devices.FirstOrDefault();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ExtractResource(string resourceName, string outputPath)
|
private void ExtractResource(string resourceName, string outputPath)
|
||||||
{
|
{
|
||||||
_logger.LogInformation($"Extracting resource: {resourceName} to {outputPath}");
|
_logger.LogInformation($"Extracting resource: {resourceName} to {outputPath}");
|
||||||
using var stream = Assembly.GetExecutingAssembly().GetManifestResourceStream(resourceName);
|
using var stream = Assembly.GetAssembly(typeof(AdbService)).GetManifestResourceStream(resourceName);
|
||||||
using var fileStream = File.Create(outputPath);
|
using var fileStream = File.Create(outputPath);
|
||||||
stream.CopyTo(fileStream);
|
stream.CopyTo(fileStream);
|
||||||
_logger.LogInformation($"Resource extracted: {resourceName} to {outputPath}");
|
_logger.LogInformation($"Resource extracted: {resourceName} to {outputPath}");
|
||||||
|
|
@ -41,14 +50,30 @@ public class AdbService : IAdbService
|
||||||
var adbPath = Path.Combine(tempDir, "adb.exe");
|
var adbPath = Path.Combine(tempDir, "adb.exe");
|
||||||
|
|
||||||
if (File.Exists(adbPath)) return adbPath;
|
if (File.Exists(adbPath)) return adbPath;
|
||||||
ExtractResource("MetaforceInstaller.Cli.adb.adb.exe", adbPath);
|
ExtractResource("MetaforceInstaller.Core.adb.adb.exe", adbPath);
|
||||||
ExtractResource("MetaforceInstaller.Cli.adb.AdbWinApi.dll", Path.Combine(tempDir, "AdbWinApi.dll"));
|
ExtractResource("MetaforceInstaller.Core.adb.AdbWinApi.dll", Path.Combine(tempDir, "AdbWinApi.dll"));
|
||||||
ExtractResource("MetaforceInstaller.Cli.adb.AdbWinUsbApi.dll", Path.Combine(tempDir, "AdbWinUsbApi.dll"));
|
ExtractResource("MetaforceInstaller.Core.adb.AdbWinUsbApi.dll", Path.Combine(tempDir, "AdbWinUsbApi.dll"));
|
||||||
|
|
||||||
return adbPath;
|
return adbPath;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void OnProgressChanged(ProgressInfo progressInfo)
|
||||||
|
{
|
||||||
|
ProgressChanged?.Invoke(this, progressInfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnStatusChanged(string status)
|
||||||
|
{
|
||||||
|
StatusChanged?.Invoke(this, status);
|
||||||
|
}
|
||||||
|
|
||||||
public void InstallApk(string apkPath)
|
public void InstallApk(string apkPath)
|
||||||
|
{
|
||||||
|
InstallApkAsync(apkPath).Wait();
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task InstallApkAsync(string apkPath, IProgress<ProgressInfo>? progress = null,
|
||||||
|
CancellationToken cancellationToken = default)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
|
@ -58,11 +83,37 @@ public class AdbService : IAdbService
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
OnStatusChanged("Начинаем установку APK...");
|
||||||
_logger.LogInformation($"Installing APK: {apkPath}");
|
_logger.LogInformation($"Installing APK: {apkPath}");
|
||||||
|
|
||||||
var packageManager = new PackageManager(_adbClient, _deviceData);
|
progress?.Report(new ProgressInfo
|
||||||
packageManager.InstallPackage(apkPath, o => { });
|
{
|
||||||
|
PercentageComplete = 0,
|
||||||
|
Message = "Подготовка к установке APK...",
|
||||||
|
Type = ProgressType.Installation,
|
||||||
|
CurrentFile = Path.GetFileName(apkPath)
|
||||||
|
});
|
||||||
|
|
||||||
|
var packageManager = new PackageManager(_adbClient, _deviceData);
|
||||||
|
|
||||||
|
await Task.Run(() =>
|
||||||
|
{
|
||||||
|
packageManager.InstallPackage(apkPath, installProgress =>
|
||||||
|
{
|
||||||
|
var progressInfo = new ProgressInfo
|
||||||
|
{
|
||||||
|
PercentageComplete = (int)installProgress.UploadProgress,
|
||||||
|
Message = $"Установка APK: {installProgress.UploadProgress:F1}%",
|
||||||
|
Type = ProgressType.Installation,
|
||||||
|
CurrentFile = Path.GetFileName(apkPath)
|
||||||
|
};
|
||||||
|
|
||||||
|
progress?.Report(progressInfo);
|
||||||
|
OnProgressChanged(progressInfo);
|
||||||
|
});
|
||||||
|
}, cancellationToken);
|
||||||
|
|
||||||
|
OnStatusChanged("APK успешно установлен!");
|
||||||
_logger.LogInformation("APK successfully installed!");
|
_logger.LogInformation("APK successfully installed!");
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
|
|
@ -73,6 +124,12 @@ public class AdbService : IAdbService
|
||||||
}
|
}
|
||||||
|
|
||||||
public void CopyFile(string localPath, string remotePath)
|
public void CopyFile(string localPath, string remotePath)
|
||||||
|
{
|
||||||
|
CopyFileAsync(localPath, remotePath).Wait();
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task CopyFileAsync(string localPath, string remotePath, IProgress<ProgressInfo>? progress = null,
|
||||||
|
CancellationToken cancellationToken = default)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
|
@ -82,14 +139,44 @@ public class AdbService : IAdbService
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
OnStatusChanged("Начинаем копирование файла...");
|
||||||
_logger.LogInformation($"Copying file: {localPath} to {remotePath}");
|
_logger.LogInformation($"Copying file: {localPath} to {remotePath}");
|
||||||
|
|
||||||
|
var fileInfo = new FileInfo(localPath);
|
||||||
|
|
||||||
|
progress?.Report(new ProgressInfo
|
||||||
|
{
|
||||||
|
PercentageComplete = 0,
|
||||||
|
Message = "Подготовка к копированию файла...",
|
||||||
|
Type = ProgressType.FileCopy,
|
||||||
|
CurrentFile = Path.GetFileName(localPath),
|
||||||
|
TotalBytes = fileInfo.Length
|
||||||
|
});
|
||||||
|
|
||||||
|
await Task.Run(() =>
|
||||||
|
{
|
||||||
using var fileStream = File.OpenRead(localPath);
|
using var fileStream = File.OpenRead(localPath);
|
||||||
var syncService = new SyncService(_adbClient, _deviceData);
|
var syncService = new SyncService(_adbClient, _deviceData);
|
||||||
|
|
||||||
syncService.Push(fileStream, remotePath, UnixFileStatus.DefaultFileMode, DateTime.Now,
|
syncService.Push(fileStream, remotePath, UnixFileStatus.DefaultFileMode, DateTime.Now,
|
||||||
new Action<SyncProgressChangedEventArgs>(progress => { }));
|
copyProgress =>
|
||||||
|
{
|
||||||
|
var progressInfo = new ProgressInfo
|
||||||
|
{
|
||||||
|
PercentageComplete = (int)copyProgress.ProgressPercentage,
|
||||||
|
BytesTransferred = copyProgress.ReceivedBytesSize,
|
||||||
|
TotalBytes = copyProgress.TotalBytesToReceive,
|
||||||
|
Message = $"Копирование: {copyProgress.ProgressPercentage:F1}%",
|
||||||
|
Type = ProgressType.FileCopy,
|
||||||
|
CurrentFile = Path.GetFileName(localPath)
|
||||||
|
};
|
||||||
|
|
||||||
|
progress?.Report(progressInfo);
|
||||||
|
OnProgressChanged(progressInfo);
|
||||||
|
});
|
||||||
|
}, cancellationToken);
|
||||||
|
|
||||||
|
OnStatusChanged("Файл успешно скопирован!");
|
||||||
_logger.LogInformation("File successfully copied!");
|
_logger.LogInformation("File successfully copied!");
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue