diff --git a/imgs/bowl.jpeg b/imgs/bowl.jpeg new file mode 100644 index 00000000..b099e216 Binary files /dev/null and b/imgs/bowl.jpeg differ diff --git a/src/c#/GeneralUpdate.Bowl.Test/GeneralUpdate.Bowl.Test.csproj b/src/c#/GeneralUpdate.Bowl.Test/GeneralUpdate.Bowl.Test.csproj new file mode 100644 index 00000000..085bdddf --- /dev/null +++ b/src/c#/GeneralUpdate.Bowl.Test/GeneralUpdate.Bowl.Test.csproj @@ -0,0 +1,23 @@ + + + + net8.0 + enable + enable + + false + true + + + + + + + + + + + + + + diff --git a/src/c#/GeneralUpdate.Bowl.Test/UnitTest1.cs b/src/c#/GeneralUpdate.Bowl.Test/UnitTest1.cs new file mode 100644 index 00000000..c76c89cc --- /dev/null +++ b/src/c#/GeneralUpdate.Bowl.Test/UnitTest1.cs @@ -0,0 +1,9 @@ +namespace GeneralUpdate.Bowl.Test; + +public class UnitTest1 +{ + [Fact] + public void Test1() + { + } +} \ No newline at end of file diff --git a/src/c#/GeneralUpdate.Bowl/Bowl.cs b/src/c#/GeneralUpdate.Bowl/Bowl.cs index fc828ebb..25d84697 100644 --- a/src/c#/GeneralUpdate.Bowl/Bowl.cs +++ b/src/c#/GeneralUpdate.Bowl/Bowl.cs @@ -4,7 +4,10 @@ namespace GeneralUpdate.Bowl; -public class Bowl +/// +/// Surveillance Main Program. +/// +public sealed class Bowl { private IStrategy _strategy; @@ -14,7 +17,7 @@ public Bowl(MonitorParameter parameter = null) _strategy!.SetParameter(parameter); } - private void CreateStrategy() + private Bowl CreateStrategy() { if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) { @@ -24,6 +27,11 @@ private void CreateStrategy() { _strategy = new LinuxStrategy(); } + + if (_strategy == null) + throw new PlatformNotSupportedException("Unsupported operating system"); + + return this; } public Bowl SetParameter(MonitorParameter parameter) @@ -35,5 +43,9 @@ public Bowl SetParameter(MonitorParameter parameter) return this; } - public void Launch() => _strategy.Launch(); + public Bowl Launch() + { + _strategy.Launch(); + return this; + } } \ No newline at end of file diff --git a/src/c#/GeneralUpdate.Bowl/Strategys/AbstractStrategy.cs b/src/c#/GeneralUpdate.Bowl/Strategys/AbstractStrategy.cs index dcf8f275..9b06b153 100644 --- a/src/c#/GeneralUpdate.Bowl/Strategys/AbstractStrategy.cs +++ b/src/c#/GeneralUpdate.Bowl/Strategys/AbstractStrategy.cs @@ -11,7 +11,8 @@ public abstract class AbstractStrategy : IStrategy private readonly IReadOnlyList _sensitiveCharacter = new List { "Exit", - "exit" + "exit", + "EXIT" }; public virtual void Launch() diff --git a/src/c#/GeneralUpdate.Bowl/Strategys/LinuxStrategy.cs b/src/c#/GeneralUpdate.Bowl/Strategys/LinuxStrategy.cs index 64f300c5..bb1c93bf 100644 --- a/src/c#/GeneralUpdate.Bowl/Strategys/LinuxStrategy.cs +++ b/src/c#/GeneralUpdate.Bowl/Strategys/LinuxStrategy.cs @@ -8,14 +8,16 @@ namespace GeneralUpdate.Bowl.Strategys; public class LinuxStrategy : AbstractStrategy { - /*procdump-3.3.0-0.cm2.x86_64.rpm: - 适合系统:此RPM包可能适用于基于CentOS或RHEL的某些派生版本,具体来说是CM2版本。CM2通常指的是ClearOS 7.x或类似的社区维护版本。 - procdump-3.3.0-0.el8.x86_64.rpm: - 适合系统:此RPM包适用于Red Hat Enterprise Linux 8 (RHEL 8)、CentOS 8及其他基于RHEL 8的发行版。 - procdump_3.3.0_amd64.deb: - 适合系统:此DEB包适用于Debian及其衍生发行版,如Ubuntu,适用于64位系统(amd64架构)。*/ + /*procdump-3.3.0-0.cm2.x86_64.rpm: + Compatible Systems: This RPM package may be suitable for certain CentOS or RHEL-based derivatives, specifically the CM2 version. CM2 typically refers to ClearOS 7.x or similar community-maintained versions. + + procdump-3.3.0-0.el8.x86_64.rpm: + Compatible Systems: This RPM package is suitable for Red Hat Enterprise Linux 8 (RHEL 8), CentOS 8, and other RHEL 8-based distributions. + + procdump_3.3.0_amd64.deb: + Compatible Systems: This DEB package is suitable for Debian and its derivatives, such as Ubuntu, for 64-bit systems (amd64 architecture).*/ - private IReadOnlyList procdump_amd64 = new List { "Ubuntu", "Debian" }; + private IReadOnlyList _rocdumpAmd64 = new List { "Ubuntu", "Debian" }; private IReadOnlyList procdump_el8_x86_64 = new List { "Red Hat", "CentOS", "Fedora" }; private IReadOnlyList procdump_cm2_x86_64 = new List { "ClearOS" }; @@ -64,9 +66,9 @@ private void Install() private string GetPacketName() { - string packageFileName = string.Empty; - LinuxSystem system = GetSystem(); - if (procdump_amd64.Contains(system.Name)) + var packageFileName = string.Empty; + var system = GetSystem(); + if (_rocdumpAmd64.Contains(system.Name)) { packageFileName = $"procdump_3.3.0_amd64.deb"; } @@ -105,9 +107,7 @@ private LinuxSystem GetSystem() return new LinuxSystem(distro, version); } - else - { - throw new FileNotFoundException("Cannot determine the Linux distribution. The /etc/os-release file does not exist."); - } + + throw new FileNotFoundException("Cannot determine the Linux distribution. The /etc/os-release file does not exist."); } } \ No newline at end of file diff --git a/src/c#/GeneralUpdate.Client.Test/GeneralUpdate.Client.Test.csproj b/src/c#/GeneralUpdate.Client.Test/GeneralUpdate.Client.Test.csproj new file mode 100644 index 00000000..085bdddf --- /dev/null +++ b/src/c#/GeneralUpdate.Client.Test/GeneralUpdate.Client.Test.csproj @@ -0,0 +1,23 @@ + + + + net8.0 + enable + enable + + false + true + + + + + + + + + + + + + + diff --git a/src/c#/GeneralUpdate.Client.Test/UnitTest1.cs b/src/c#/GeneralUpdate.Client.Test/UnitTest1.cs new file mode 100644 index 00000000..a34ba46c --- /dev/null +++ b/src/c#/GeneralUpdate.Client.Test/UnitTest1.cs @@ -0,0 +1,9 @@ +namespace GeneralUpdate.Client.Test; + +public class UnitTest1 +{ + [Fact] + public void Test1() + { + } +} \ No newline at end of file diff --git a/src/c#/GeneralUpdate.Client/MySample.cs b/src/c#/GeneralUpdate.Client/MySample.cs deleted file mode 100644 index d602edbc..00000000 --- a/src/c#/GeneralUpdate.Client/MySample.cs +++ /dev/null @@ -1,322 +0,0 @@ -using GeneralUpdate.ClientCore; -using GeneralUpdate.Core.Bootstrap; -using GeneralUpdate.Core.Domain.Entity; -using GeneralUpdate.Core.Domain.Enum; -using GeneralUpdate.Core.Driver; -using GeneralUpdate.Core.Events.CommonArgs; -using GeneralUpdate.Core.Events.MultiEventArgs; -using GeneralUpdate.Core.Strategys.PlatformWindows; -using GeneralUpdate.Differential; -using System.Diagnostics; -using System.Text; - -namespace GeneralUpdate.Client -{ - internal class MySample - { - #region 推送功能 - - private const string baseUrl = @"http://127.0.0.1:5000"; - private const string hubName = "versionhub"; - - internal MySample() - { - //Receive sample code pushed by the server - //VersionHub.Instance.Subscribe($"{baseUrl}/{hubName}", "TESTNAME", new Action(GetMessage)); - } - - //Receive sample code pushed by the server - private async void GetMessage(string msg) - { - var isUpdate = true; - if (isUpdate) Upgrade(); - } - - #endregion 推送功能 - - #region 常规更新 - - public async Task Upgrade() - { - //Task.Run(async () => - //{ - // var url = "http://192.168.50.203"; - // var appName = "GeneralUpdate.Client"; - // var version = "1.0.0.0"; - // var versionFileName = "version.json"; - // ParamsOSS @params = new ParamsOSS(url, appName, version, versionFileName); - // await GeneralClientOSS.Start(@params); - //}); - - //ClientStrategy该更新策略将完成1.自动升级组件自更新 2.启动更新组件 3.配置好ClientParameter无需再像之前的版本写args数组进程通讯了。 - //generalClientBootstrap.Config(baseUrl, "B8A7FADD-386C-46B0-B283-C9F963420C7C"). - var configinfo = GetWindowsConfigInfo(); - var generalClientBootstrap = await new GeneralClientBootstrap() - //单个或多个更新包下载通知事件 - .AddListenerMultiDownloadProgress(OnMultiDownloadProgressChanged) - //单个或多个更新包下载速度、剩余下载事件、当前下载版本信息通知事件 - .AddListenerMultiDownloadStatistics(OnMultiDownloadStatistics) - //单个或多个更新包下载完成 - .AddListenerMultiDownloadCompleted(OnMultiDownloadCompleted) - //完成所有的下载任务通知 - .AddListenerMultiAllDownloadCompleted(OnMultiAllDownloadCompleted) - //下载过程出现的异常通知 - .AddListenerMultiDownloadError(OnMultiDownloadError) - //整个更新过程出现的任何问题都会通过这个事件通知 - .AddListenerException(OnException) - .Config(configinfo) - .Option(UpdateOption.DownloadTimeOut, 60) - .Option(UpdateOption.Encoding, Encoding.Default) - .Option(UpdateOption.Format, Format.ZIP) - //开启驱动更新 - //.Option(UpdateOption.Drive, true) - //开启遗言功能,需要部署GeneralUpdate.SystemService Windows服务。 - .Option(UpdateOption.WillMessage, true) - .Strategy() - //注入一个func让用户决定是否跳过本次更新,如果是强制更新则不生效 - //.SetCustomSkipOption(ShowCustomOption) - //注入一个自定义方法集合,该集合会在更新启动前执行。执行自定义方法列表如果出现任何异常,将通过异常订阅通知。(推荐在更新之前检查当前软件环境) - //.AddCustomOption(new List>() { () => Check1(), () => Check2() }) - //默认黑名单文件: { "Newtonsoft.Json.dll" } 默认黑名单文件扩展名: { ".patch", ".7z", ".zip", ".rar", ".tar" , ".json" } - //如果不需要扩展,需要重新传入黑名单集合来覆盖。 - //.SetBlacklist(GetBlackFiles(), GetBlackFormats()) - .LaunchTaskAsync(); - } - - private bool Check1() => true; - - private bool Check2() => true; - - private List GetBlackFiles() - { - var blackFiles = new List(); - blackFiles.Add("MainApp"); - return blackFiles; - } - - private List GetBlackFormats() - { - var blackFormats = new List(); - blackFormats.Add(".zip"); - return blackFormats; - } - - /// - /// 获取Windows平台所需的配置参数 - /// - /// - private Configinfo GetWindowsConfigInfo() - { - //该对象用于主程序客户端与更新组件进程之间交互用的对象 - var config = new Configinfo(); - //本机的客户端程序应用地址 - config.InstallPath = @"D:\packet\source"; - //更新公告网页 - config.UpdateLogUrl = "https://www.baidu.com/"; - //客户端当前版本号 - config.ClientVersion = "1.1.1.1"; - //客户端类型:1.主程序客户端 2.更新组件 - config.AppType = AppType.UpgradeApp; - //指定应用密钥,用于区分客户端应用 - config.AppSecretKey = "B8A7FADD-386C-46B0-B283-C9F963420C7C"; - //更新组件更新包下载地址 - config.UpdateUrl = $"{baseUrl}/versions/{config.AppType}/{config.ClientVersion}/{config.AppSecretKey}"; - //更新程序exe名称 - config.AppName = "GeneralUpdate.Core"; - //主程序客户端exe名称 - config.MainAppName = "GeneralUpdate.ClientCore"; - //主程序信息 - var mainVersion = "1.1.1.1"; - //主程序客户端更新包下载地址 - config.MainUpdateUrl = $"{baseUrl}/versions/{AppType.ClientApp}/{mainVersion}/{config.AppSecretKey}"; - return config; - } - - /// - /// 获取Android平台所需要的参数 - /// - /// - private Configinfo GetAndroidConfigInfo() - { - var config = new Configinfo(); - config.InstallPath = System.Threading.Thread.GetDomain().BaseDirectory; - //主程序客户端当前版本号 - config.ClientVersion = "1.0.0.0"; //VersionTracking.Default.CurrentVersion.ToString(); - config.AppType = AppType.ClientApp; - config.AppSecretKey = "41A54379-C7D6-4920-8768-21A3468572E5"; - //主程序客户端exe名称 - config.MainAppName = "GeneralUpdate.ClientCore"; - //主程序信息 - var mainVersion = "1.1.1.1"; - config.MainUpdateUrl = $"{baseUrl}/versions/{AppType.ClientApp}/{mainVersion}/{config.AppSecretKey}"; - return config; - } - - /// - /// 让用户决定是否跳过本次更新 - /// - /// - private async Task ShowCustomOption() - { - return await Task.FromResult(true); - } - - private void OnMultiDownloadStatistics(object sender, MultiDownloadStatisticsEventArgs e) - { - //e.Remaining 剩余下载时间 - //e.Speed 下载速度 - //e.Version 当前下载的版本信息 - } - - private void OnMultiDownloadProgressChanged(object sender, MultiDownloadProgressChangedEventArgs e) - { - //e.TotalBytesToReceive 当前更新包需要下载的总大小 - //e.ProgressValue 当前进度值 - //e.ProgressPercentage 当前进度的百分比 - //e.Version 当前下载的版本信息 - //e.Type 当前正在执行的操作 1.ProgressType.Check 检查版本信息中 2.ProgressType.Donwload 正在下载当前版本 3. ProgressType.Updatefile 更新当前版本 4. ProgressType.Done更新完成 5.ProgressType.Fail 更新失败 - //e.BytesReceived 已下载大小 - DispatchMessage($"{e.ProgressPercentage}%"); - //MyProgressBar.ProgressTo(e.ProgressValue, 100, Easing.Default); - } - - private void OnException(object sender, ExceptionEventArgs e) - { - //DispatchMessage(e.Exception.Message); - } - - private void OnMultiAllDownloadCompleted(object sender, MultiAllDownloadCompletedEventArgs e) - { - //e.FailedVersions; 如果出现下载失败则会把下载错误的版本、错误原因统计到该集合当中。 - DispatchMessage($"Is all download completed {e.IsAllDownloadCompleted}."); - } - - private void OnMultiDownloadCompleted(object sender, MultiDownloadCompletedEventArgs e) - { - var info = e.Version as VersionInfo; - DispatchMessage($"{info.Name} download completed."); - } - - private void OnMultiDownloadError(object sender, MultiDownloadErrorEventArgs e) - { - var info = e.Version as VersionInfo; - DispatchMessage($"{info.Name} error!"); - } - - private void DispatchMessage(string message) - { - } - - #endregion 常规更新 - - #region 测试二进制更新包整理 - - public async Task TestDifferentialClean() - { - var path1 = "D:\\packet\\source"; - var path2 = "D:\\packet\\target"; - var path3 = "D:\\packet\\patchs"; - await DifferentialCore.Instance.Clean(path1, path2, path3); - } - - public async Task TestDifferentialDirty() - { - var path1 = "D:\\packet\\source"; - var path2 = "D:\\packet\\patchs"; - await DifferentialCore.Instance.Dirty(path1, path2); - } - - #endregion 测试二进制更新包整理 - - #region 测试驱动功能 - - public void TestDrive() - { - var path1 = "D:\\packet\\source"; - var path2 = "D:\\packet\\target"; - - var drivers = GetAllDriverDirectories(path1); - - var information = new DriverInformation.Builder() - .SetInstallDirectory(path1) - .SetOutPutDirectory(path2) - .SetDriverNames(drivers) - .Build(); - - var processor = new DriverProcessor(); - processor.AddCommand(new BackupDriverCommand(information)); - processor.AddCommand(new DeleteDriverCommand(information)); - processor.AddCommand(new InstallDriverCommand(information)); - processor.ProcessCommands(); - } - - /// - /// Identifies all folders containing driver files in the specified directory and returns the directory collection. - /// - /// - /// - private List GetAllDriverDirectories(string path) - { - var driverDirectories = new HashSet(); - try - { - foreach (string filePath in Directory.GetFiles(path)) - { - if (IsDriverFile(filePath)) - driverDirectories.Add(filePath); - } - - foreach (string directory in Directory.GetDirectories(path)) - { - driverDirectories.UnionWith(GetAllDriverDirectories(directory)); - } - } - catch (UnauthorizedAccessException) - { - Trace.WriteLine("No access directory:" + path); - } - catch (PathTooLongException) - { - Trace.WriteLine("Path overlength:" + path); - } - - return new List(driverDirectories); - } - - /// - /// Match the driver installation boot file. - /// - /// - /// - private bool IsDriverFile(string filePath) => - string.Equals(Path.GetExtension(filePath), ".inf", StringComparison.OrdinalIgnoreCase); - - #endregion 测试驱动功能 - - #region 文件管理测试 - - public void TestFileProvider() - { - var sourcePath = "D:\\packet\\source"; - var targetPath = "D:\\packet\\target"; - var resultPath = "D:\\packet\\patchs"; - - //FileProvider fileProvider = new FileProvider(); - //var list = fileProvider.ExecuteOperation(sourcePath, targetPath,new List(), new List()); - //foreach (var item in list) { - // Console.WriteLine(item); - //} - //Console.WriteLine("total" + list.Count()); - //Console.WriteLine("--------------------------------------"); - //FileProvider fileProvider1 = new FileProvider(); - //var list1 = fileProvider1.ExecuteOperation(targetPath, sourcePath, new List(), new List()); - //foreach (var item in list1) - //{ - // Console.WriteLine(item); - //} - //Console.WriteLine("total" + list1.Count()); - } - - #endregion 文件管理测试 - } -} \ No newline at end of file diff --git a/src/c#/GeneralUpdate.Client/Program.cs b/src/c#/GeneralUpdate.Client/Program.cs index 1b9dd51c..dc9b8f2b 100644 --- a/src/c#/GeneralUpdate.Client/Program.cs +++ b/src/c#/GeneralUpdate.Client/Program.cs @@ -1,28 +1,104 @@ -namespace GeneralUpdate.Client +using System.Diagnostics; +using System.Text; +using GeneralUpdate.ClientCore; +using GeneralUpdate.Common.Download; +using GeneralUpdate.Common.Internal; +using GeneralUpdate.Common.Internal.Bootstrap; +using GeneralUpdate.Common.Shared.Object; + +namespace GeneralUpdate.Client { - internal class Program + internal class Progra { private static void Main(string[] args) { - MySample sample = new MySample(); - sample.TestFileProvider(); - //Task.Run(async() => - //{ - // //415eed05eb310f480d1e4d15516fa00e484ddb9f416908b217f17b782ded2030 - // //var zip1 = @"D:\github_project\WpfClient\WebApi\UpdateFiles\WpfClient_1_24.1.5.1218.zip"; - // //94bd3d806d39cd1b8813298ec0637c7f377658e766845a06cc50917306cb4ad9 - // //var zip2 = @"D:\github_project\WpfClient\WebApi\UpdateFiles\WpfClient_1_24.1.5.1224.zip"; - - // //var hashAlgorithm = new Sha256HashAlgorithm(); - // //var hashSha256 = hashAlgorithm.ComputeHash(zip1); - // //var hashSha2561 = hashAlgorithm.ComputeHash(zip2); - - // MySample sample = new MySample(); - // //await sample.TestDifferentialClean(); - // //await sample.TestDifferentialDirty(); - // await sample.Upgrade(); - //}); + /*Task.Run(async () => + { + var source = @"D:\packet\app"; + var target = @"D:\packet\release"; + var patch = @"D:\packet\patch"; + + await DifferentialCore.Instance?.Clean(source, target, patch); + await DifferentialCore.Instance?.Dirty(source, patch); + });*/ + + Task.Run(async () => + { + Console.WriteLine("主程序启动辣!!!!"); + await Task.Delay(3000); + + var configinfo = new Configinfo(); + //configinfo.UpdateLogUrl = "https://www.baidu.com"; + configinfo.ReportUrl = "http://127.0.0.1:5008/Upgrade/Report"; + configinfo.UpdateUrl = "http://127.0.0.1:5008/Upgrade/Verification"; + + configinfo.AppName = "GeneralUpdate.Upgrad.exe"; + configinfo.MainAppName = "GeneralUpdate.Client.exe"; + configinfo.InstallPath = Thread.GetDomain().BaseDirectory; + + //当前客户端的版本号 + configinfo.ClientVersion = "1.0.0.0"; + //当前升级端的版本号 + configinfo.UpgradeClientVersion = "1.0.0.0"; + + //平台 + configinfo.Platform = 1; + //产品id + configinfo.ProductId = "a77c9df5-45f8-4ee9-b3ad-b9431ce0b51c"; + //应用密钥 + configinfo.AppSecretKey = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + + _ = new GeneralClientBootstrap()//单个或多个更新包下载通知事件 + .AddListenerMultiDownloadProgress(OnMultiDownloadProgressChanged) + //单个或多个更新包下载速度、剩余下载事件、当前下载版本信息通知事件 + .AddListenerMultiDownloadStatistics(OnMultiDownloadStatistics) + //单个或多个更新包下载完成 + .AddListenerMultiDownloadCompleted(OnMultiDownloadCompleted) + //完成所有的下载任务通知 + .AddListenerMultiAllDownloadCompleted(OnMultiAllDownloadCompleted) + //下载过程出现的异常通知 + .AddListenerMultiDownloadError(OnMultiDownloadError) + //整个更新过程出现的任何问题都会通过这个事件通知 + .AddListenerException(OnException) + .SetConfig(configinfo) + .Option(UpdateOption.DownloadTimeOut, 60) + .Option(UpdateOption.Encoding, Encoding.UTF8) + .Option(UpdateOption.Format, Format.ZIP) + .LaunchAsync(); + }); + Console.Read(); } + + private static void OnMultiDownloadError(object arg1, MultiDownloadErrorEventArgs arg2) + { + Debug.WriteLine(arg2.Exception); + } + + private static void OnMultiAllDownloadCompleted(object arg1, MultiAllDownloadCompletedEventArgs arg2) + { + Debug.WriteLine(arg2.IsAllDownloadCompleted); + } + + private static void OnMultiDownloadCompleted(object arg1, MultiDownloadCompletedEventArgs arg2) + { + var v = arg2.Version as VersionInfo; + Debug.WriteLine(v.Version); + } + + private static void OnMultiDownloadStatistics(object arg1, MultiDownloadStatisticsEventArgs arg2) + { + Debug.WriteLine(arg2.Speed); + } + + private static void OnMultiDownloadProgressChanged(object arg1, MultiDownloadProgressChangedEventArgs arg2) + { + Debug.WriteLine(arg2.ProgressValue); + } + + private static void OnException(object arg1, ExceptionEventArgs arg2) + { + Debug.WriteLine(arg2.Exception); + } } } \ No newline at end of file diff --git a/src/c#/GeneralUpdate.ClientCore/Bootstrap/.gitkeep b/src/c#/GeneralUpdate.ClientCore/Bootstrap/.gitkeep deleted file mode 100644 index e69de29b..00000000 diff --git a/src/c#/GeneralUpdate.ClientCore/CustomAwaiter/.gitkeep b/src/c#/GeneralUpdate.ClientCore/CustomAwaiter/.gitkeep deleted file mode 100644 index e69de29b..00000000 diff --git a/src/c#/GeneralUpdate.ClientCore/Differential/.gitkeep b/src/c#/GeneralUpdate.ClientCore/Differential/.gitkeep deleted file mode 100644 index e69de29b..00000000 diff --git a/src/c#/GeneralUpdate.ClientCore/Differential/Binary/.gitkeep b/src/c#/GeneralUpdate.ClientCore/Differential/Binary/.gitkeep deleted file mode 100644 index e69de29b..00000000 diff --git a/src/c#/GeneralUpdate.ClientCore/Differential/ContentProvider/.gitkeep b/src/c#/GeneralUpdate.ClientCore/Differential/ContentProvider/.gitkeep deleted file mode 100644 index e69de29b..00000000 diff --git a/src/c#/GeneralUpdate.ClientCore/Differential/GStream/.gitkeep b/src/c#/GeneralUpdate.ClientCore/Differential/GStream/.gitkeep deleted file mode 100644 index e69de29b..00000000 diff --git a/src/c#/GeneralUpdate.ClientCore/Domain/.gitkeep b/src/c#/GeneralUpdate.ClientCore/Domain/.gitkeep deleted file mode 100644 index e69de29b..00000000 diff --git a/src/c#/GeneralUpdate.ClientCore/Domain/DTO/Assembler/.gitkeep b/src/c#/GeneralUpdate.ClientCore/Domain/DTO/Assembler/.gitkeep deleted file mode 100644 index e69de29b..00000000 diff --git a/src/c#/GeneralUpdate.ClientCore/Domain/Entity/Assembler/.gitkeep b/src/c#/GeneralUpdate.ClientCore/Domain/Entity/Assembler/.gitkeep deleted file mode 100644 index e69de29b..00000000 diff --git a/src/c#/GeneralUpdate.ClientCore/Domain/Enum/.gitkeep b/src/c#/GeneralUpdate.ClientCore/Domain/Enum/.gitkeep deleted file mode 100644 index e69de29b..00000000 diff --git a/src/c#/GeneralUpdate.ClientCore/Domain/PO/.gitkeep b/src/c#/GeneralUpdate.ClientCore/Domain/PO/.gitkeep deleted file mode 100644 index e69de29b..00000000 diff --git a/src/c#/GeneralUpdate.ClientCore/Domain/PO/Assembler/.gitkeep b/src/c#/GeneralUpdate.ClientCore/Domain/PO/Assembler/.gitkeep deleted file mode 100644 index e69de29b..00000000 diff --git a/src/c#/GeneralUpdate.ClientCore/Domain/Service/.gitkeep b/src/c#/GeneralUpdate.ClientCore/Domain/Service/.gitkeep deleted file mode 100644 index e69de29b..00000000 diff --git a/src/c#/GeneralUpdate.ClientCore/Domain/VO/.gitkeep b/src/c#/GeneralUpdate.ClientCore/Domain/VO/.gitkeep deleted file mode 100644 index e69de29b..00000000 diff --git a/src/c#/GeneralUpdate.ClientCore/Download/.gitkeep b/src/c#/GeneralUpdate.ClientCore/Download/.gitkeep deleted file mode 100644 index e69de29b..00000000 diff --git a/src/c#/GeneralUpdate.ClientCore/Driver/.gitkeep b/src/c#/GeneralUpdate.ClientCore/Driver/.gitkeep deleted file mode 100644 index e69de29b..00000000 diff --git a/src/c#/GeneralUpdate.ClientCore/Events/CommonArgs/.gitkeep b/src/c#/GeneralUpdate.ClientCore/Events/CommonArgs/.gitkeep deleted file mode 100644 index e69de29b..00000000 diff --git a/src/c#/GeneralUpdate.ClientCore/Events/MultiEventArgs/.gitkeep b/src/c#/GeneralUpdate.ClientCore/Events/MultiEventArgs/.gitkeep deleted file mode 100644 index e69de29b..00000000 diff --git a/src/c#/GeneralUpdate.ClientCore/Exceptions/.gitkeep b/src/c#/GeneralUpdate.ClientCore/Exceptions/.gitkeep deleted file mode 100644 index e69de29b..00000000 diff --git a/src/c#/GeneralUpdate.ClientCore/Exceptions/CustomArgs/.gitkeep b/src/c#/GeneralUpdate.ClientCore/Exceptions/CustomArgs/.gitkeep deleted file mode 100644 index e69de29b..00000000 diff --git a/src/c#/GeneralUpdate.ClientCore/Exceptions/CustomException/.gitkeep b/src/c#/GeneralUpdate.ClientCore/Exceptions/CustomException/.gitkeep deleted file mode 100644 index e69de29b..00000000 diff --git a/src/c#/GeneralUpdate.ClientCore/GeneralClientBootstrap.cs b/src/c#/GeneralUpdate.ClientCore/GeneralClientBootstrap.cs index 11bded52..fe14f11e 100644 --- a/src/c#/GeneralUpdate.ClientCore/GeneralClientBootstrap.cs +++ b/src/c#/GeneralUpdate.ClientCore/GeneralClientBootstrap.cs @@ -1,271 +1,370 @@ -using GeneralUpdate.Core.Bootstrap; -using GeneralUpdate.Core.Domain.DTO.Assembler; -using GeneralUpdate.Core.Domain.Entity; -using GeneralUpdate.Core.Domain.Entity.Assembler; -using GeneralUpdate.Core.Domain.Enum; -using GeneralUpdate.Core.Domain.Service; -using GeneralUpdate.Core.Exceptions.CustomArgs; -using GeneralUpdate.Core.Exceptions.CustomException; -using GeneralUpdate.Core.Strategys; using System; using System.Collections.Generic; using System.Diagnostics; -using System.IO; using System.Linq; -using System.Reflection; -using System.Security; +using System.Runtime.InteropServices; +using System.Text; +using System.Text.Json; using System.Threading.Tasks; +using GeneralUpdate.ClientCore.Strategys; +using GeneralUpdate.Common.FileBasic; +using GeneralUpdate.Common.Download; +using GeneralUpdate.Common.Internal; +using GeneralUpdate.Common.Internal.Bootstrap; +using GeneralUpdate.Common.Internal.Event; +using GeneralUpdate.Common.Internal.Strategy; +using GeneralUpdate.Common.Shared.Object; +using GeneralUpdate.Common.Shared.Service; -namespace GeneralUpdate.ClientCore +namespace GeneralUpdate.ClientCore; + +/// +/// This component is used only for client application bootstrapping classes. +/// +public class GeneralClientBootstrap : AbstractBootstrap { /// - /// This component is used only for client application bootstrapping classes. + /// All update actions of the core object for automatic upgrades will be related to the packet object. /// - public class GeneralClientBootstrap : AbstractBootstrap - { - private Func _customSkipOption; - private Func> _customSkipTaskOption; + private GlobalConfigInfo? _configinfo; + private IStrategy? _strategy; + private Func? _customSkipOption; + private readonly List> _customOptions = new(); + + #region Public Methods - private List> _customOptions; - private List>> _customTaskOptions; + /// + /// Main function for booting the update startup. + /// + /// + public override async Task LaunchAsync() + { + ExecuteCustomOptions(); + ClearEnvironmentVariable(); + await ExecuteWorkflowAsync(); + return this; + } - public GeneralClientBootstrap() : base() + /// + /// Configure server address (Recommended Windows,Linux,Mac). + /// + /// Remote server address. + /// The updater name does not need to contain an extension. + /// + /// Parameter initialization is abnormal. + public GeneralClientBootstrap SetConfig(Configinfo configInfo) + { + Debug.Assert(configInfo != null, "configInfo should not be null"); + configInfo?.Validate(); + _configinfo = new GlobalConfigInfo { - _customOptions = new List>(); - _customTaskOptions = new List>>(); - } + AppName = configInfo.AppName, + MainAppName = configInfo.MainAppName, + ClientVersion = configInfo.ClientVersion, + InstallPath = configInfo.InstallPath, + UpdateLogUrl = configInfo.UpdateLogUrl, + UpdateUrl = configInfo.UpdateUrl, + ReportUrl = configInfo.ReportUrl, + AppSecretKey = configInfo.AppSecretKey, + BlackFormats = configInfo.BlackFormats, + BlackFiles = configInfo.BlackFiles, + Platform = configInfo.Platform, + ProductId = configInfo.ProductId, + UpgradeClientVersion = configInfo.UpgradeClientVersion + }; + return this; + } - #region Public Methods + /// + /// Let the user decide whether to update in the state of non-mandatory update. + /// + /// + /// Custom function ,Custom actions to let users decide whether to update. true update false do not + /// update . + /// + /// + public GeneralClientBootstrap SetCustomSkipOption(Func func) + { + Debug.Assert(func != null); + _customSkipOption = func; + return this; + } - /// - /// Start the update. - /// - /// - public override GeneralClientBootstrap LaunchAsync() - { - Task.Run(() => BaseLaunch()); - return this; - } + /// + /// Add an asynchronous custom operation. + /// In theory, any custom operation can be done. It is recommended to register the environment check method to ensure + /// that there are normal dependencies and environments after the update is completed. + /// + /// + /// + /// + public GeneralClientBootstrap AddCustomOption(List> funcs) + { + Debug.Assert(funcs != null && funcs.Any()); + _customOptions.AddRange(funcs); + return this; + } - /// - /// Start the update. - /// - /// - public Task LaunchTaskAsync() => BaseLaunch(); + public GeneralClientBootstrap AddListenerMultiAllDownloadCompleted( + Action callbackAction) + => AddListener(callbackAction); - private async Task BaseLaunch() - { - ClearEnvironmentVariable(); - await ExecuteCustomOptions(); - var versionService = new VersionService(); - var mainResp = await versionService.ValidationVersion(Packet.MainUpdateUrl); - var upgradeResp = await versionService.ValidationVersion(Packet.UpdateUrl); - //if (!CheckWillMessage()) return this; - Packet.IsUpgradeUpdate = upgradeResp.Body.IsUpdate; - Packet.IsMainUpdate = mainResp.Body.IsUpdate; - //No need to update, return directly. - if ((!Packet.IsMainUpdate) && (!Packet.IsUpgradeUpdate)) return this; - //If the main program needs to be forced to update, the skip will not take effect. - var isForcibly = mainResp.Body.IsForcibly || upgradeResp.Body.IsForcibly; - if (await IsSkip(isForcibly)) return this; - Packet.UpdateVersions = VersionAssembler.ToEntitys(upgradeResp.Body.Versions); - Packet.LastVersion = Packet.UpdateVersions.Last().Version; - var processInfo = new ProcessInfo(Packet.MainAppName, Packet.InstallPath, - Packet.ClientVersion, Packet.LastVersion, Packet.UpdateLogUrl, - Packet.Encoding, Packet.Format, Packet.DownloadTimeOut, - Packet.AppSecretKey, mainResp.Body.Versions); - Packet.ProcessBase64 = ProcessAssembler.ToBase64(processInfo); - return base.LaunchAsync(); - } + public GeneralClientBootstrap AddListenerMultiDownloadProgress( + Action callbackAction) + => AddListener(callbackAction); - /// - /// Configure server address (Recommended Windows,Linux,Mac). - /// - /// Remote server address. - /// The updater name does not need to contain an extension. - /// - /// Parameter initialization is abnormal. - public GeneralClientBootstrap Config(string url, string appSecretKey, string appName = "GeneralUpdate.Upgrade") - { - if (string.IsNullOrEmpty(url)) throw new Exception("Url cannot be empty !"); - try - { - string basePath = System.Threading.Thread.GetDomain().BaseDirectory; - Packet.InstallPath = basePath; - Packet.AppSecretKey = appSecretKey; - //update app. - Packet.AppName = appName; - string clientVersion = GetFileVersion(Path.Combine(basePath, $"{Packet.AppName}.exe")); - Packet.ClientVersion = clientVersion; - Packet.AppType = AppType.ClientApp; - Packet.UpdateUrl = $"{url}/versions/{AppType.ClientApp}/{clientVersion}/{Packet.AppSecretKey}"; - //main app. - string mainAppName = Path.GetFileNameWithoutExtension(Process.GetCurrentProcess().MainModule.FileName); - string mainVersion = Assembly.GetExecutingAssembly().GetName().Version.ToString(); - Packet.MainUpdateUrl = $"{url}/versions/{AppType.ClientApp}/{mainVersion}/{Packet.AppSecretKey}"; - Packet.MainAppName = mainAppName; - return this; - } - catch (Exception ex) - { - throw new GeneralUpdateException(ex.Message, ex.InnerException); - } - } + public GeneralClientBootstrap AddListenerMultiDownloadCompleted( + Action callbackAction) + => AddListener(callbackAction); - /// - /// Custom Configuration (Recommended : All platforms). - /// - /// - /// - public GeneralClientBootstrap Config(Configinfo info) - { - Packet.AppType = info.AppType; - Packet.AppName = info.AppName; - Packet.AppSecretKey = info.AppSecretKey; - Packet.ClientVersion = info.ClientVersion; - Packet.UpdateUrl = info.UpdateUrl; - Packet.MainUpdateUrl = info.MainUpdateUrl; - Packet.MainAppName = info.MainAppName; - Packet.InstallPath = info.InstallPath; - Packet.UpdateLogUrl = info.UpdateLogUrl; - return this; - } + public GeneralClientBootstrap AddListenerMultiDownloadError( + Action callbackAction) + => AddListener(callbackAction); - /// - /// Let the user decide whether to update in the state of non-mandatory update. - /// - /// Custom function ,Custom actions to let users decide whether to update. true update false do not update . - /// - public GeneralClientBootstrap SetCustomSkipOption(Func func) - { - if (func == null) throw new ArgumentNullException(nameof(func)); - _customSkipOption = func; - return this; - } + public GeneralClientBootstrap AddListenerMultiDownloadStatistics( + Action callbackAction) + => AddListener(callbackAction); + + public GeneralClientBootstrap AddListenerException(Action callbackAction) + => AddListener(callbackAction); + + #endregion Public Methods - /// - /// Let the user decide whether to update in the state of non-mandatory update. - /// - /// Custom function ,Custom actions to let users decide whether to update. true update false do not update . - /// - /// - public GeneralClientBootstrap SetCustomSkipOption(Func> func) + #region Private Methods + + private async Task ExecuteWorkflowAsync() + { + //Request the upgrade information needed by the client and upgrade end, and determine if an upgrade is necessary. + var mainResp = await VersionService.Validate(_configinfo.UpdateUrl + , _configinfo.ClientVersion + ,1 + ,_configinfo.AppSecretKey + ,_configinfo.Platform + ,_configinfo.ProductId); + + var upgradeResp = await VersionService.Validate(_configinfo.UpdateUrl + , _configinfo.UpgradeClientVersion + ,2 + ,_configinfo.AppSecretKey + ,_configinfo.Platform + ,_configinfo.ProductId); + + _configinfo.IsUpgradeUpdate = CheckUpgrade(upgradeResp); + _configinfo.IsMainUpdate = CheckUpgrade(mainResp); + + //If the main program needs to be forced to update, the skip will not take effect. + var isForcibly = CheckForcibly(mainResp.Body) || CheckForcibly(upgradeResp.Body); + if (CanSkip(isForcibly)) return; + + _configinfo.Encoding = GetOption(UpdateOption.Encoding) ?? Encoding.Default; + _configinfo.Format = GetOption(UpdateOption.Format) ?? ".zip"; + _configinfo.DownloadTimeOut = GetOption(UpdateOption.DownloadTimeOut) == 0 ? 60 : GetOption(UpdateOption.DownloadTimeOut); + _configinfo.DriveEnabled = GetOption(UpdateOption.Drive) ?? false; + _configinfo.TempPath = GeneralFileManager.GetTempDirectory("main_temp"); + + if (_configinfo.IsMainUpdate) { - if (func == null) throw new ArgumentNullException(nameof(func)); - _customSkipTaskOption = func; - return this; + _configinfo.UpdateVersions = mainResp.Body.OrderBy(x => x.ReleaseDate).ToList(); + _configinfo.LastVersion = _configinfo.UpdateVersions.Last().Version; + + //var failed = CheckFail(_configinfo.LastVersion); + //if (failed) return; + + //Initialize the process transfer parameter object. + var processInfo = new ProcessInfo(_configinfo.MainAppName + , _configinfo.InstallPath + , _configinfo.ClientVersion + , _configinfo.LastVersion + , _configinfo.UpdateLogUrl + , _configinfo.Encoding + , _configinfo.Format + , _configinfo.DownloadTimeOut + , _configinfo.AppSecretKey + , mainResp.Body + , _configinfo.ReportUrl); + + _configinfo.ProcessInfo = JsonSerializer.Serialize(processInfo); } - /// - /// Add an asynchronous custom operation. - /// In theory, any custom operation can be done. It is recommended to register the environment check method to ensure that there are normal dependencies and environments after the update is completed. - /// - /// - /// - /// - public GeneralClientBootstrap AddCustomOption(List> funcs) + StrategyFactory(); + + switch (_configinfo.IsUpgradeUpdate) { - if (funcs == null || !funcs.Any()) throw new ArgumentNullException(nameof(funcs)); - _customOptions.AddRange(funcs); - return this; + case true when _configinfo.IsMainUpdate: + //Both upgrade and main program update. + await Download(); + await _strategy?.ExecuteAsync()!; + _strategy?.StartApp(); + break; + case true when !_configinfo.IsMainUpdate: + //Upgrade program update. + await Download(); + await _strategy?.ExecuteAsync()!; + break; + case false when _configinfo.IsMainUpdate: + //Main program update. + _strategy?.StartApp(); + break; } - - /// - /// Add a synchronization custom operation. - /// In theory, any custom operation can be done. It is recommended to register the environment check method to ensure that there are normal dependencies and environments after the update is completed. - /// - /// - /// - /// - public GeneralClientBootstrap AddCustomOption(List>> funcs) + } + + private async Task Download() + { + var manager = new DownloadManager(_configinfo.TempPath, _configinfo.Format, _configinfo.DownloadTimeOut); + manager.MultiAllDownloadCompleted += OnMultiAllDownloadCompleted; + manager.MultiDownloadCompleted += OnMultiDownloadCompleted; + manager.MultiDownloadError += OnMultiDownloadError; + manager.MultiDownloadProgressChanged += OnMultiDownloadProgressChanged; + manager.MultiDownloadStatistics += OnMultiDownloadStatistics; + foreach (var versionInfo in _configinfo.UpdateVersions) { - if (funcs == null || !funcs.Any()) throw new ArgumentNullException(nameof(funcs)); - _customTaskOptions.AddRange(funcs); - return this; + manager.Add(new DownloadTask(manager, versionInfo)); } + await manager.LaunchTasksAsync(); + } - #endregion Public Methods - - #region Private Methods + /// + /// Check if there has been a recent update failure. + /// + /// + /// + private bool CheckFail(string version) + { + /* + Read the version number of the last failed upgrade from the system environment variables, then compare it with the version number of the current request. + If it is less than or equal to the failed version number, do not perform the update. + */ + var fail = Environment.GetEnvironmentVariable("UpgradeFail", EnvironmentVariableTarget.User); + if (string.IsNullOrEmpty(fail) || string.IsNullOrEmpty(version)) + return false; + + var failVersion = new Version(fail); + var lastVersion = new Version(version); + return failVersion >= lastVersion; + } - /// - ///Gets the application version number - /// - /// - /// - /// - private string GetFileVersion(string filePath) + /// + /// Determine whether the current version verification result indicates that an update is needed. + /// + /// + /// + private bool CheckUpgrade(VersionRespDTO? response) + { + if (response == null) { - var fileInfo = new FileInfo(filePath); - if (fileInfo != null && fileInfo.Exists) return FileVersionInfo.GetVersionInfo(filePath).FileVersion; - throw new GeneralUpdateException($"Failed to obtain file '{filePath}' version. Procedure."); + return false; } - /// - /// User decides if update is required. - /// - /// is false to continue execution. - private async Task IsSkip(bool isForcibly) + if (response.Code == HttpStatus.OK) { - try - { - bool isSkip = false; - if (isForcibly) return false; - if (_customSkipTaskOption != null) isSkip = await _customSkipTaskOption.Invoke(); - if (_customSkipOption != null) isSkip = _customSkipOption.Invoke(); - return isSkip; - } - catch (Exception ex) + return response.Body.Count > 0; + } + + return false; + } + + /// + /// During the iteration process, if any version requires a mandatory update, all the update content from this request should be updated. + /// + /// + /// + private bool CheckForcibly(List? versions) + { + if (versions == null) + return false; + + foreach (var item in versions) + { + if (item.IsForcibly == true) { - throw new GeneralUpdateException($"The injected user skips this update with an exception ! {ex.Message}", ex.InnerException); + return true; } } - /// - /// Performs all injected custom operations. - /// - /// - private async Task ExecuteCustomOptions() + return false; + } + + /// + /// User decides if update is required. + /// + /// is false to continue execution. + private bool CanSkip(bool isForcibly) + { + if (isForcibly) return false; + return _customSkipOption?.Invoke() == true; + } + + /// + /// Performs all injected custom operations. + /// + /// + private void ExecuteCustomOptions() + { + if (!_customOptions.Any()) return; + + foreach (var option in _customOptions) { - if (_customTaskOptions.Any()) - { - foreach (var option in _customTaskOptions) - { - var isSuccess = await option.Invoke(); - if (!isSuccess) - Core.Events.EventManager.Instance.Dispatch>(this, new Core.Events.CommonArgs.ExceptionEventArgs($"{nameof(option)}Execution failure!")); - } - } - else if (_customOptions.Any()) + if (!option.Invoke()) { - foreach (var option in _customOptions) - { - var isSuccess = option.Invoke(); - if (!isSuccess) - Core.Events.EventManager.Instance.Dispatch>(this, new Core.Events.CommonArgs.ExceptionEventArgs($"{nameof(option)}Execution failure!")); - } + EventManager.Instance.Dispatch(this, + new ExceptionEventArgs(null, $"{nameof(option)}Execution failure!")); } } + } - /// - /// The values passed between processes during previous updates are cleared when the client starts. - /// - private void ClearEnvironmentVariable() + /// + /// Clear the environment variable information needed to start the upgrade assistant process. + /// + private void ClearEnvironmentVariable() + { + try { - try - { - Environment.SetEnvironmentVariable("ProcessBase64", null, EnvironmentVariableTarget.User); - } - catch (SecurityException ex) - { - Trace.WriteLine($"Error: You do not have sufficient permissions to delete this environment variable.{ex}"); - } - catch (ArgumentException ex) - { - Trace.WriteLine($"Error: The environment variable name is invalid. {ex}"); - } + Environment.SetEnvironmentVariable("ProcessInfo", null, EnvironmentVariableTarget.User); + } + catch (Exception ex) + { + EventManager.Instance.Dispatch(this, new ExceptionEventArgs(ex, "Error: An unknown error occurred while deleting the environment variable.")); } + } + + protected override void ExecuteStrategy()=> throw new NotImplementedException(); + + protected override Task ExecuteStrategyAsync()=> throw new NotImplementedException(); + + protected override GeneralClientBootstrap StrategyFactory() + { + if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + _strategy = new WindowsStrategy(); + else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) + _strategy = new LinuxStrategy(); + else + throw new PlatformNotSupportedException("The current operating system is not supported!"); - #endregion Private Methods + _strategy?.Create(_configinfo!); + return this; + } + + private GeneralClientBootstrap AddListener(Action callbackAction) where TArgs : EventArgs + { + Debug.Assert(callbackAction != null); + EventManager.Instance.AddListener(callbackAction); + return this; } + + private void OnMultiDownloadStatistics(object sender, MultiDownloadStatisticsEventArgs e) + => EventManager.Instance.Dispatch(sender, e); + + private void OnMultiDownloadProgressChanged(object sender, MultiDownloadProgressChangedEventArgs e) + => EventManager.Instance.Dispatch(sender, e); + + private void OnMultiDownloadCompleted(object sender, MultiDownloadCompletedEventArgs e) + => EventManager.Instance.Dispatch(sender, e); + + private void OnMultiDownloadError(object sender, MultiDownloadErrorEventArgs e) + => EventManager.Instance.Dispatch(sender, e); + + private void OnMultiAllDownloadCompleted(object sender, MultiAllDownloadCompletedEventArgs e) + => EventManager.Instance.Dispatch(sender, e); + + #endregion Private Methods } \ No newline at end of file diff --git a/src/c#/GeneralUpdate.ClientCore/GeneralClientOSS.cs b/src/c#/GeneralUpdate.ClientCore/GeneralClientOSS.cs index c08f1e57..548bac28 100644 --- a/src/c#/GeneralUpdate.ClientCore/GeneralClientOSS.cs +++ b/src/c#/GeneralUpdate.ClientCore/GeneralClientOSS.cs @@ -1,95 +1,95 @@ -using GeneralUpdate.Core.ContentProvider; -using GeneralUpdate.Core.Domain.Entity; -using GeneralUpdate.Core.Domain.Entity.Assembler; -using GeneralUpdate.Core.Domain.PO; -using System; +using System; using System.Collections.Generic; using System.Diagnostics; +using System.Diagnostics.Contracts; using System.IO; using System.Linq; using System.Net; +using System.Text.Json; +using System.Threading; using System.Threading.Tasks; +using GeneralUpdate.Common.FileBasic; +using GeneralUpdate.Common.Internal; +using GeneralUpdate.Common.Internal.Event; +using GeneralUpdate.Common.Shared.Object; -namespace GeneralUpdate.ClientCore +namespace GeneralUpdate.ClientCore; + +public sealed class GeneralClientOSS { - public sealed class GeneralClientOSS + private GeneralClientOSS() { - private GeneralClientOSS() - { } + } - /// - /// Starting an OSS update for windows,Linux,mac platform. - /// - /// - public static async Task Start(ParamsOSS configParams, string upgradeAppName = "GeneralUpdate.Upgrade") + /// + /// Starting an OSS update for windows,Linux,mac platform. + /// + /// + public static async Task Start(ParamsOSS configParams, string upgradeAppName = "GeneralUpdate.Upgrade") + { + await Task.Run(() => { - await Task.Run(() => + try { - try - { - string basePath = System.Threading.Thread.GetDomain().BaseDirectory; - //Download the version information file from OSS to be updated.(JSON) - var versionsFilePath = Path.Combine(basePath, configParams.VersionFileName); - DownloadFile(configParams.Url + "/" + configParams.VersionFileName, versionsFilePath); - if (!File.Exists(versionsFilePath)) return; - var versions = FileProvider.GetJson>(versionsFilePath); - if (versions == null || versions.Count == 0) return; - versions = versions.OrderByDescending(x => x.PubTime).ToList(); - var newVersion = versions.First(); - //Determine whether the current client version needs to be upgraded. - if (!IsUpgrade(configParams.CurrentVersion, newVersion.Version)) return; - var appPath = Path.Combine(basePath, $"{upgradeAppName}.exe"); - if (!File.Exists(appPath)) throw new Exception($"The application does not exist {upgradeAppName} !"); - //If you confirm that an update is required, start the upgrade application. - var processBase64 = ProcessAssembler.ToBase64(configParams); - Process.Start(appPath, processBase64); - } - catch (Exception ex) - { - GeneralUpdate.Core.Events.EventManager.Instance.Dispatch>(typeof(GeneralClientOSS), new GeneralUpdate.Core.Events.CommonArgs.ExceptionEventArgs(ex)); - throw new Exception($"GeneralClientOSS update exception ! {ex.Message}", ex.InnerException); - } - finally - { - Process.GetCurrentProcess().Kill(); - } - }); - } - - /// - /// Determine whether the current client version needs to be upgraded. - /// - /// - /// - /// true: Upgrade required , false: No upgrade is required - private static bool IsUpgrade(string clientVersion, string serverVersion) - { - if (string.IsNullOrWhiteSpace(clientVersion) || string.IsNullOrWhiteSpace(serverVersion)) return false; - Version currentClientVersion = null; - Version currentServerVersion = null; - bool isParseClientVersion = Version.TryParse(clientVersion, out currentClientVersion); - bool isParseServerVersion = Version.TryParse(serverVersion, out currentServerVersion); - if (!isParseClientVersion || !isParseServerVersion) return false; - if (currentClientVersion < currentServerVersion) return true; - return false; - } - - private static void DownloadFile(string url, string path) - { - using (var webClient = new WebClient()) + var basePath = Thread.GetDomain().BaseDirectory; + //Download the version information file from OSS to be updated.(JSON) + var versionsFilePath = Path.Combine(basePath, configParams.VersionFileName); + DownloadFile(configParams.Url + "/" + configParams.VersionFileName, versionsFilePath); + if (!File.Exists(versionsFilePath)) return; + var versions = GeneralFileManager.GetJson>(versionsFilePath); + if (versions == null || versions.Count == 0) return; + versions = versions.OrderByDescending(x => x.PubTime).ToList(); + var newVersion = versions.First(); + //Determine whether the current client version needs to be upgraded. + if (!IsUpgrade(configParams.CurrentVersion, newVersion.Version)) return; + var appPath = Path.Combine(basePath, $"{upgradeAppName}.exe"); + if (!File.Exists(appPath)) throw new Exception($"The application does not exist {upgradeAppName} !"); + //If you confirm that an update is required, start the upgrade application. + var json = JsonSerializer.Serialize(configParams); + //TODO: set environment variable + Process.Start(appPath, json); + } + catch (Exception ex) + { + throw new Exception($"GeneralClientOSS update exception ! {ex.Message}", ex.InnerException); + } + finally { - webClient.DownloadFile(new Uri(url), path); + Process.GetCurrentProcess().Kill(); } - } + }); + } - public static void AddListenerException(Action callbackAction) - { - AddListener(callbackAction); - } + /// + /// Determine whether the current client version needs to be upgraded. + /// + /// + /// + /// true: Upgrade required , false: No upgrade is required + private static bool IsUpgrade(string clientVersion, string serverVersion) + { + if (string.IsNullOrWhiteSpace(clientVersion) || string.IsNullOrWhiteSpace(serverVersion)) return false; + Version currentClientVersion = null; + Version currentServerVersion = null; + var isParseClientVersion = Version.TryParse(clientVersion, out currentClientVersion); + var isParseServerVersion = Version.TryParse(serverVersion, out currentServerVersion); + if (!isParseClientVersion || !isParseServerVersion) return false; + if (currentClientVersion < currentServerVersion) return true; + return false; + } - private static void AddListener(Action callbackAction) where TArgs : EventArgs - { - if (callbackAction != null) GeneralUpdate.Core.Events.EventManager.Instance.AddListener(callbackAction); - } + private static void DownloadFile(string url, string path) + { + using var webClient = new WebClient(); + webClient.DownloadFile(new Uri(url), path); + } + + public static void AddListenerException(Action callbackAction) + => AddListener(callbackAction); + + private static void AddListener(Action callbackAction) where TArgs : EventArgs + { + Contract.Requires(callbackAction != null); + EventManager.Instance.AddListener(callbackAction); } } \ No newline at end of file diff --git a/src/c#/GeneralUpdate.ClientCore/GeneralUpdate.ClientCore.csproj b/src/c#/GeneralUpdate.ClientCore/GeneralUpdate.ClientCore.csproj index 1c03115f..a39dacbe 100644 --- a/src/c#/GeneralUpdate.ClientCore/GeneralUpdate.ClientCore.csproj +++ b/src/c#/GeneralUpdate.ClientCore/GeneralUpdate.ClientCore.csproj @@ -1,258 +1,36 @@ - - netstandard2.0 - 2.12.10 - juster.zhu - Provides functions related to upgrade and update programs. - GeneralUpdate.ico - GeneralUpdate128.png - False - False - https://github.com/JusterZhu/GeneralUpdate - Copyright © 2023 - Provides high-performance, low-loss, resume-breakpoint, version-by-version update, binary differential update, incremental update function, configuration file retention update and other features - https://github.com/JusterZhu/GeneralUpdate - 12 - enable - + + netstandard2.0 + 2.12.10 + juster.zhu + Provides functions related to upgrade and update programs. + GeneralUpdate.ico + GeneralUpdate128.png + False + False + https://github.com/JusterZhu/GeneralUpdate + Copyright © 2024 + Provides high-performance, low-loss, resume-breakpoint, version-by-version update, binary differential update, incremental update function, configuration file retention update and other features + https://github.com/JusterZhu/GeneralUpdate + 12 + enable + - - - - - - - - - - - + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + diff --git a/src/c#/GeneralUpdate.ClientCore/HashAlgorithms/.gitkeep b/src/c#/GeneralUpdate.ClientCore/HashAlgorithms/.gitkeep deleted file mode 100644 index e69de29b..00000000 diff --git a/src/c#/GeneralUpdate.ClientCore/Hubs/RandomRetryPolicy.cs b/src/c#/GeneralUpdate.ClientCore/Hubs/RandomRetryPolicy.cs index f274eaaf..93ef549c 100644 --- a/src/c#/GeneralUpdate.ClientCore/Hubs/RandomRetryPolicy.cs +++ b/src/c#/GeneralUpdate.ClientCore/Hubs/RandomRetryPolicy.cs @@ -1,25 +1,19 @@ -using Microsoft.AspNetCore.SignalR.Client; -using System; +using System; +using Microsoft.AspNetCore.SignalR.Client; -namespace GeneralUpdate.ClientCore.Hubs +namespace GeneralUpdate.ClientCore.Hubs; + +public class RandomRetryPolicy : IRetryPolicy { - public class RandomRetryPolicy : IRetryPolicy - { - private readonly Random _random = new Random(); + private readonly Random _random = new(); - public TimeSpan? NextRetryDelay(RetryContext retryContext) - { - // If we've been reconnecting for less than 60 seconds so far, - // wait between 0 and 10 seconds before the next reconnect attempt. - if (retryContext.ElapsedTime < TimeSpan.FromSeconds(60)) - { - return TimeSpan.FromSeconds(_random.NextDouble() * 10); - } - else - { - // If we've been reconnecting for more than 60 seconds so far, stop reconnecting. - return null; - } - } + public TimeSpan? NextRetryDelay(RetryContext retryContext) + { + // If we've been reconnecting for less than 60 seconds so far, + // wait between 0 and 10 seconds before the next reconnect attempt. + if (retryContext.ElapsedTime < TimeSpan.FromSeconds(60)) + return TimeSpan.FromSeconds(_random.NextDouble() * 10); + // If we've been reconnecting for more than 60 seconds so far, stop reconnecting. + return null; } } \ No newline at end of file diff --git a/src/c#/GeneralUpdate.ClientCore/Hubs/VersionHub.cs b/src/c#/GeneralUpdate.ClientCore/Hubs/VersionHub.cs index 6b656f14..b4e04cbd 100644 --- a/src/c#/GeneralUpdate.ClientCore/Hubs/VersionHub.cs +++ b/src/c#/GeneralUpdate.ClientCore/Hubs/VersionHub.cs @@ -1,196 +1,205 @@ -using GeneralUpdate.Core.ContentProvider; -using Microsoft.AspNetCore.SignalR.Client; -using System; +using System; +using System.Text.Json; using System.Threading.Tasks; +using Microsoft.AspNetCore.SignalR.Client; -namespace GeneralUpdate.ClientCore.Hubs -{ - public sealed class VersionHub where TParameter : class - { - #region Private Members - - private const string ReceiveMessageflag = "ReceiveMessage"; - private const string SendMessageflag = "SendMessage"; - private const string Onlineflag = "Online"; - - private HubConnection _connection = null; - private static VersionHub _instance; - private static readonly object _lock = new object(); - private Action _receiveMessageCallback; - private Action _onlineMessageCallback; - private Action _reconnectedCallback; - private string _name; - - #endregion Private Members +namespace GeneralUpdate.ClientCore.Hubs; - #region Constructors +public sealed class VersionHub where TParameter : class +{ + #region Constructors - private VersionHub() - { } + private VersionHub() + { + } - #endregion Constructors + #endregion Constructors - #region Public Properties + #region Public Properties - public static VersionHub Instance + public static VersionHub Instance + { + get { - get - { - if (_instance == null) + if (_instance == null) + lock (_lock) { - lock (_lock) - { - if (_instance == null) - _instance = new VersionHub(); - } + if (_instance == null) + _instance = new VersionHub(); } - return _instance; - } - } - #endregion Public Properties + return _instance; + } + } - #region Public Methods + #endregion Public Properties + + #region Private Members + + private const string ReceiveMessageflag = "ReceiveMessage"; + private const string SendMessageflag = "SendMessage"; + private const string Onlineflag = "Online"; + + private HubConnection _connection; + private static VersionHub _instance; + private static readonly object _lock = new(); + private Action _receiveMessageCallback; + private Action _onlineMessageCallback; + private Action _reconnectedCallback; + private string _name; + + #endregion Private Members + + #region Public Methods + + /// + /// Subscribe to the latest version. + /// + /// remote server address , E.g : https://127.0.0.1:8080/versionhub . + /// The name needs to be guaranteed to be unique. + /// + /// Receive server push callback function, The caller needs to implement the update + /// process. + /// + /// Receive online and offline notification callback function. + /// Reconnect notification callback function. + /// Subscribe exception. + public void Subscribe(string url, string name, Action receiveMessageCallback, + Action onlineMessageCallback = null, Action reconnectedCallback = null) + { + if (string.IsNullOrWhiteSpace(url) || receiveMessageCallback == null) + throw new Exception("Subscription key parameter cannot be null !"); - /// - /// Subscribe to the latest version. - /// - /// remote server address , E.g : https://127.0.0.1:8080/versionhub . - /// The name needs to be guaranteed to be unique. - /// Receive server push callback function, The caller needs to implement the update process. - /// Receive online and offline notification callback function. - /// Reconnect notification callback function. - /// Subscribe exception. - public void Subscribe(string url, string name, Action receiveMessageCallback, Action onlineMessageCallback = null, Action reconnectedCallback = null) + try { - if (string.IsNullOrWhiteSpace(url) || receiveMessageCallback == null) throw new Exception("Subscription key parameter cannot be null !"); - - try + _name = name; + _receiveMessageCallback = receiveMessageCallback; + _onlineMessageCallback = onlineMessageCallback; + _reconnectedCallback = reconnectedCallback; + if (_connection == null) { - _name = name; - _receiveMessageCallback = receiveMessageCallback; - _onlineMessageCallback = onlineMessageCallback; - _reconnectedCallback = reconnectedCallback; - if (_connection == null) - { - _connection = new HubConnectionBuilder() - .WithUrl(url) - .WithAutomaticReconnect(new RandomRetryPolicy()) - .Build(); - _connection.On(ReceiveMessageflag, OnReceiveMessage); - _connection.On(Onlineflag, OnOnlineMessage); - _connection.Reconnected += OnReconnected; - _connection.Closed += OnClosed; - } - _connection.StartAsync(); - } - catch (Exception ex) - { - throw new Exception($"'VersionHub' Subscribe error : {ex.Message}", ex.InnerException); + _connection = new HubConnectionBuilder() + .WithUrl(url) + .WithAutomaticReconnect(new RandomRetryPolicy()) + .Build(); + _connection.On(ReceiveMessageflag, OnReceiveMessage); + _connection.On(Onlineflag, OnOnlineMessage); + _connection.Reconnected += OnReconnected; + _connection.Closed += OnClosed; } + + _connection.StartAsync(); } + catch (Exception ex) + { + throw new Exception($"'VersionHub' Subscribe error : {ex.Message}", ex.InnerException); + } + } - /// - /// Send message to server.[Not recommended for now] - /// - /// - /// - /// - public async Task Send(string msg) + /// + /// Send message to server.[Not recommended for now] + /// + /// + /// + /// + public async Task Send(string msg) + { + try { - try - { - if (_connection == null) return; - await _connection.InvokeAsync(SendMessageflag, _name, msg); - } - catch (Exception ex) - { - throw new Exception($"'VersionHub' Send error : {ex.Message}", ex.InnerException); - } + if (_connection == null) return; + await _connection.InvokeAsync(SendMessageflag, _name, msg); } + catch (Exception ex) + { + throw new Exception($"'VersionHub' Send error : {ex.Message}", ex.InnerException); + } + } - #endregion Public Methods + #endregion Public Methods - #region Private Methods + #region Private Methods - /// - /// Receives the message. - /// - /// - private void OnReceiveMessage(string name, string message) + /// + /// Receives the message. + /// + /// + private void OnReceiveMessage(string name, string message) + { + if (_receiveMessageCallback == null || string.IsNullOrWhiteSpace(message)) return; + try { - if (_receiveMessageCallback == null || string.IsNullOrWhiteSpace(message)) return; - try - { - var clientParameter = FileProvider.Deserialize(message); - if (clientParameter == null) throw new ArgumentNullException($"'VersionHub' Receiving server push version information deserialization failed , receive content : {message} ."); - _receiveMessageCallback.Invoke(clientParameter); - } - catch (Exception ex) - { - throw new Exception($"'VersionHub' Receive message error : {ex.Message}", ex.InnerException); - } + var clientParameter = JsonSerializer.Deserialize(message); + if (clientParameter == null) + throw new ArgumentNullException( + $"'VersionHub' Receiving server push version information deserialization failed , receive content : {message} ."); + _receiveMessageCallback.Invoke(clientParameter); + } + catch (Exception ex) + { + throw new Exception($"'VersionHub' Receive message error : {ex.Message}", ex.InnerException); } + } - /// - /// Online and offline notification. - /// - /// - private void OnOnlineMessage(string message) + /// + /// Online and offline notification. + /// + /// + private void OnOnlineMessage(string message) + { + try { - try - { - if (_onlineMessageCallback != null) _onlineMessageCallback.Invoke(message); - } - catch (Exception ex) - { - throw new Exception($"'VersionHub' Online message error : {ex.Message}", ex.InnerException); - } + if (_onlineMessageCallback != null) _onlineMessageCallback.Invoke(message); } + catch (Exception ex) + { + throw new Exception($"'VersionHub' Online message error : {ex.Message}", ex.InnerException); + } + } - /// - /// Reconnection notice. - /// - /// - /// - private Task OnReconnected(string arg) + /// + /// Reconnection notice. + /// + /// + /// + private Task OnReconnected(string arg) + { + try { - try - { - if (_reconnectedCallback != null) _reconnectedCallback.Invoke(arg); - } - catch (Exception ex) - { - throw new Exception($"'VersionHub' On reconnected error : {ex.Message}", ex.InnerException); - } - return Task.CompletedTask; + if (_reconnectedCallback != null) _reconnectedCallback.Invoke(arg); + } + catch (Exception ex) + { + throw new Exception($"'VersionHub' On reconnected error : {ex.Message}", ex.InnerException); } - /// - /// Shut down. - /// - /// - /// - private async Task OnClosed(Exception arg) + return Task.CompletedTask; + } + + /// + /// Shut down. + /// + /// + /// + private async Task OnClosed(Exception arg) + { + try { - try - { - if (arg != null) throw new Exception($"'VersionHub' On closed internal exception : {arg.Message}", arg.InnerException); + if (arg != null) + throw new Exception($"'VersionHub' On closed internal exception : {arg.Message}", arg.InnerException); - if (_connection == null) return; - await Task.Delay(new Random().Next(0, 3) * 1000); - await _connection.StartAsync(); - } - catch (ArgumentOutOfRangeException ex) - { - throw new ArgumentOutOfRangeException(ex.Message); - } - catch (Exception ex) - { - throw new Exception($"'VersionHub' On closed error : {ex.Message}", ex.InnerException); - } + if (_connection == null) return; + await Task.Delay(new Random().Next(0, 3) * 1000); + await _connection.StartAsync(); + } + catch (ArgumentOutOfRangeException ex) + { + throw new ArgumentOutOfRangeException(ex.Message); + } + catch (Exception ex) + { + throw new Exception($"'VersionHub' On closed error : {ex.Message}", ex.InnerException); } - - #endregion Private Methods } + + #endregion Private Methods } \ No newline at end of file diff --git a/src/c#/GeneralUpdate.ClientCore/Pipeline/HashMiddleware.cs b/src/c#/GeneralUpdate.ClientCore/Pipeline/HashMiddleware.cs new file mode 100644 index 00000000..64f23bf3 --- /dev/null +++ b/src/c#/GeneralUpdate.ClientCore/Pipeline/HashMiddleware.cs @@ -0,0 +1,28 @@ +using System; +using System.Security.Cryptography; +using System.Threading.Tasks; +using GeneralUpdate.Common.HashAlgorithms; +using GeneralUpdate.Common.Internal.Pipeline; + +namespace GeneralUpdate.ClientCore.Pipeline; + +public class HashMiddleware : IMiddleware +{ + public async Task InvokeAsync(PipelineContext context) + { + var path = context.Get("ZipFilePath"); + var hash = context.Get("Hash"); + var isVerify = await VerifyFileHash(path, hash); + if (!isVerify) throw new CryptographicException("Hash verification failed ."); + } + + private Task VerifyFileHash(string path, string hash) + { + return Task.Run(() => + { + var hashAlgorithm = new Sha256HashAlgorithm(); + var hashSha256 = hashAlgorithm.ComputeHash(path); + return string.Equals(hash, hashSha256, StringComparison.OrdinalIgnoreCase); + }); + } +} \ No newline at end of file diff --git a/src/c#/GeneralUpdate.ClientCore/Pipeline/PatchMiddleware.cs b/src/c#/GeneralUpdate.ClientCore/Pipeline/PatchMiddleware.cs new file mode 100644 index 00000000..8c9c2ecf --- /dev/null +++ b/src/c#/GeneralUpdate.ClientCore/Pipeline/PatchMiddleware.cs @@ -0,0 +1,22 @@ +using System.Collections.Generic; +using System.Threading.Tasks; +using GeneralUpdate.Common.FileBasic; +using GeneralUpdate.Common.Internal.Pipeline; +using GeneralUpdate.Differential; + +namespace GeneralUpdate.ClientCore.Pipeline; + +public class PatchMiddleware : IMiddleware +{ + public async Task InvokeAsync(PipelineContext context) + { + var sourcePath = context.Get("SourcePath"); + var targetPath = context.Get("PatchPath"); + var blackFiles = context.Get>("BlackFiles"); + var blackFileFormats = context.Get>("BlackFileFormats"); + + BlackListManager.Instance.AddBlackFiles(blackFiles); + BlackListManager.Instance.AddBlackFileFormats(blackFileFormats); + await DifferentialCore.Instance?.Dirty(sourcePath, targetPath); + } +} \ No newline at end of file diff --git a/src/c#/GeneralUpdate.ClientCore/Pipeline/ZipMiddleware.cs b/src/c#/GeneralUpdate.ClientCore/Pipeline/ZipMiddleware.cs new file mode 100644 index 00000000..9b591151 --- /dev/null +++ b/src/c#/GeneralUpdate.ClientCore/Pipeline/ZipMiddleware.cs @@ -0,0 +1,49 @@ +using System; +using System.Text; +using System.Threading.Tasks; +using GeneralUpdate.Common.Internal; +using GeneralUpdate.Common.Internal.Event; +using GeneralUpdate.Common.Internal.Pipeline; +using GeneralUpdate.Zip; +using GeneralUpdate.Zip.Factory; + +namespace GeneralUpdate.ClientCore.Pipeline; + +public class ZipMiddleware : IMiddleware +{ + public Task InvokeAsync(PipelineContext? context) + { + return Task.Run(() => + { + try + { + var type = MatchType(context.Get("Format")); + var name = context.Get("Name"); + var sourcePath = context.Get("ZipFilePath"); + var destinationPath = context.Get("PatchPath"); + var encoding = context.Get("Encoding"); + + var generalZipfactory = new GeneralZipFactory(); + generalZipfactory.CompressProgress += (sender, args) => { }; + generalZipfactory.Completed += (sender, args) => { }; + generalZipfactory.CreateOperate(type, name, sourcePath, destinationPath, true, encoding); + generalZipfactory.UnZip(); + } + catch (Exception e) + { + EventManager.Instance.Dispatch(this, new ExceptionEventArgs(e, e.Message)); + } + }); + } + + private static OperationType MatchType(string extensionName) + { + var type = extensionName switch + { + ".zip" => OperationType.GZip, + ".7z" => OperationType.G7z, + _ => OperationType.None + }; + return type; + } +} \ No newline at end of file diff --git a/src/c#/GeneralUpdate.ClientCore/Pipelines/Attributes/.gitkeep b/src/c#/GeneralUpdate.ClientCore/Pipelines/Attributes/.gitkeep deleted file mode 100644 index e69de29b..00000000 diff --git a/src/c#/GeneralUpdate.ClientCore/Pipelines/Context/.gitkeep b/src/c#/GeneralUpdate.ClientCore/Pipelines/Context/.gitkeep deleted file mode 100644 index e69de29b..00000000 diff --git a/src/c#/GeneralUpdate.ClientCore/Pipelines/Middleware/.gitkeep b/src/c#/GeneralUpdate.ClientCore/Pipelines/Middleware/.gitkeep deleted file mode 100644 index e69de29b..00000000 diff --git a/src/c#/GeneralUpdate.ClientCore/Pipelines/MiddlewareResolver/.gitkeep b/src/c#/GeneralUpdate.ClientCore/Pipelines/MiddlewareResolver/.gitkeep deleted file mode 100644 index e69de29b..00000000 diff --git a/src/c#/GeneralUpdate.ClientCore/Pipelines/Pipeline/.gitkeep b/src/c#/GeneralUpdate.ClientCore/Pipelines/Pipeline/.gitkeep deleted file mode 100644 index e69de29b..00000000 diff --git a/src/c#/GeneralUpdate.ClientCore/Strategys/LinuxStrategy.cs b/src/c#/GeneralUpdate.ClientCore/Strategys/LinuxStrategy.cs new file mode 100644 index 00000000..f5e42dac --- /dev/null +++ b/src/c#/GeneralUpdate.ClientCore/Strategys/LinuxStrategy.cs @@ -0,0 +1,7 @@ +using GeneralUpdate.Common.Internal.Strategy; + +namespace GeneralUpdate.ClientCore.Strategys; + +public class LinuxStrategy : AbstractStrategy +{ +} \ No newline at end of file diff --git a/src/c#/GeneralUpdate.ClientCore/Strategys/PlatformLinux/.gitkeep b/src/c#/GeneralUpdate.ClientCore/Strategys/PlatformLinux/.gitkeep deleted file mode 100644 index e69de29b..00000000 diff --git a/src/c#/GeneralUpdate.ClientCore/Strategys/PlatformWindows/.gitkeep b/src/c#/GeneralUpdate.ClientCore/Strategys/PlatformWindows/.gitkeep deleted file mode 100644 index e69de29b..00000000 diff --git a/src/c#/GeneralUpdate.ClientCore/Strategys/WindowsStrategy.cs b/src/c#/GeneralUpdate.ClientCore/Strategys/WindowsStrategy.cs new file mode 100644 index 00000000..7bfd423c --- /dev/null +++ b/src/c#/GeneralUpdate.ClientCore/Strategys/WindowsStrategy.cs @@ -0,0 +1,108 @@ +using System; +using System.Diagnostics; +using System.IO; +using System.Threading; +using System.Threading.Tasks; +using GeneralUpdate.ClientCore.Pipeline; +using GeneralUpdate.Common.FileBasic; +using GeneralUpdate.Common.Internal; +using GeneralUpdate.Common.Internal.Event; +using GeneralUpdate.Common.Internal.Pipeline; +using GeneralUpdate.Common.Internal.Strategy; +using GeneralUpdate.Common.Shared.Object; +using GeneralUpdate.Common.Shared.Service; + +namespace GeneralUpdate.ClientCore.Strategys; + +/// +/// Update policy based on the Windows platform. +/// +public class WindowsStrategy : AbstractStrategy +{ + private GlobalConfigInfo _configinfo = new(); + + public override void Create(GlobalConfigInfo parameter)=> _configinfo = parameter; + + public override async Task ExecuteAsync() + { + try + { + var status = 0; + var patchPath = GeneralFileManager.GetTempDirectory(PATCHS); + foreach (var version in _configinfo.UpdateVersions) + { + try + { + var context = new PipelineContext(); + //Common + context.Add("ZipFilePath", + Path.Combine(_configinfo.TempPath, $"{version.Name}{_configinfo.Format}")); + //hash middleware + context.Add("Hash", version.Hash); + //zip middleware + context.Add("Format", _configinfo.Format); + context.Add("Name", version.Name); + context.Add("Encoding", _configinfo.Encoding); + //patch middleware + context.Add("SourcePath", _configinfo.InstallPath); + context.Add("PatchPath", patchPath); + context.Add("BlackFiles", BlackListManager.Instance.BlackFiles); + context.Add("BlackFileFormats", BlackListManager.Instance.BlackFileFormats); + + var pipelineBuilder = new PipelineBuilder(context) + .UseMiddleware() + .UseMiddleware() + .UseMiddleware(); + await pipelineBuilder.Build(); + status = 2; + } + catch (Exception e) + { + status = 3; + EventManager.Instance.Dispatch(this, new ExceptionEventArgs(e, e.Message)); + } + finally + { + await VersionService.Report(_configinfo.ReportUrl, version.RecordId, status, version.AppType); + } + } + + if (!string.IsNullOrEmpty(_configinfo.UpdateLogUrl)) + { + OpenBrowser(_configinfo.UpdateLogUrl); + } + + Clear(patchPath); + Clear(_configinfo.TempPath); + } + catch (Exception e) + { + EventManager.Instance.Dispatch(this, new ExceptionEventArgs(e, e.Message)); + } + } + + public override void StartApp() + { + try + { + var appPath = Path.Combine(_configinfo.InstallPath, _configinfo.AppName); + if (File.Exists(appPath)) + { + Environment.SetEnvironmentVariable("ProcessInfo", _configinfo.ProcessInfo, EnvironmentVariableTarget.User); + Process.Start(new ProcessStartInfo + { + UseShellExecute = true, + FileName = appPath + }); + } + } + catch (Exception e) + { + EventManager.Instance.Dispatch(this, new ExceptionEventArgs(e, e.Message)); + } + finally + { + Process.GetCurrentProcess().Kill(); + } + } +} \ No newline at end of file diff --git a/src/c#/GeneralUpdate.ClientCore/WillMessage/.gitkeep b/src/c#/GeneralUpdate.ClientCore/WillMessage/.gitkeep deleted file mode 100644 index e69de29b..00000000 diff --git a/src/c#/GeneralUpdate.ClientCore/ZipFactory/Events/.gitkeep b/src/c#/GeneralUpdate.ClientCore/ZipFactory/Events/.gitkeep deleted file mode 100644 index e69de29b..00000000 diff --git a/src/c#/GeneralUpdate.ClientCore/ZipFactory/Factory/.gitkeep b/src/c#/GeneralUpdate.ClientCore/ZipFactory/Factory/.gitkeep deleted file mode 100644 index e69de29b..00000000 diff --git a/src/c#/GeneralUpdate.Common/Download/DownloadManager.cs b/src/c#/GeneralUpdate.Common/Download/DownloadManager.cs index cf8f60ba..a6694103 100644 --- a/src/c#/GeneralUpdate.Common/Download/DownloadManager.cs +++ b/src/c#/GeneralUpdate.Common/Download/DownloadManager.cs @@ -2,11 +2,12 @@ using System.Collections.Generic; using System.Threading.Tasks; using System.Collections.Immutable; -using GeneralUpdate.Common.Download; +using System.Diagnostics; +using System.Linq; -namespace GeneralUpdate.Core.Download +namespace GeneralUpdate.Common.Download { - public class DownloadManager + public class DownloadManager { #region Private Members @@ -14,8 +15,8 @@ public class DownloadManager private readonly string _format; private readonly int _timeOut; private readonly IList<(object, string)> _failedVersions; - private ImmutableList>.Builder _downloadTasksBuilder; - private ImmutableList> _downloadTasks; + private ImmutableList.Builder _downloadTasksBuilder; + private ImmutableList _downloadTasks; #endregion Private Members @@ -27,7 +28,7 @@ public DownloadManager(string path, string format, int timeOut) _format = format; _timeOut = timeOut; _failedVersions = new List<(object, string)>(); - _downloadTasksBuilder = ImmutableList.Create>().ToBuilder(); + _downloadTasksBuilder = ImmutableList.Create().ToBuilder(); } #endregion Constructors @@ -42,7 +43,7 @@ public DownloadManager(string path, string format, int timeOut) public int TimeOut => _timeOut; - public ImmutableList> DownloadTasks => _downloadTasks ?? (_downloadTasksBuilder.ToImmutable()); + private ImmutableList DownloadTasks => _downloadTasks ?? (_downloadTasksBuilder.ToImmutable()); public event EventHandler MultiAllDownloadCompleted; public event EventHandler MultiDownloadProgressChanged; @@ -58,11 +59,7 @@ public async Task LaunchTasksAsync() { try { - var downloadTasks = new List(); - foreach (var task in DownloadTasks) - { - downloadTasks.Add(task.LaunchAsync()); - } + var downloadTasks = DownloadTasks.Select(task => task.LaunchAsync()).ToList(); await Task.WhenAll(downloadTasks); MultiAllDownloadCompleted?.Invoke(this, new MultiAllDownloadCompletedEventArgs(true, _failedVersions)); } @@ -75,19 +72,13 @@ public async Task LaunchTasksAsync() } public void OnMultiDownloadStatistics(object sender, MultiDownloadStatisticsEventArgs e) - { - MultiDownloadStatistics?.Invoke(this, e); - } + => MultiDownloadStatistics?.Invoke(this, e); public void OnMultiDownloadProgressChanged(object sender, MultiDownloadProgressChangedEventArgs e) - { - MultiDownloadProgressChanged?.Invoke(this, e); - } + => MultiDownloadProgressChanged?.Invoke(this, e); public void OnMultiAsyncCompleted(object sender, MultiDownloadCompletedEventArgs e) - { - MultiDownloadCompleted?.Invoke(this, e); - } + => MultiDownloadCompleted?.Invoke(this, e); public void OnMultiDownloadError(object sender, MultiDownloadErrorEventArgs e) { @@ -95,16 +86,15 @@ public void OnMultiDownloadError(object sender, MultiDownloadErrorEventArgs e) _failedVersions.Add((e.Version, e.Exception.Message)); } - public void Add(DownloadTask task) + public void Add(DownloadTask task) { - if (task != null && !_downloadTasksBuilder.Contains(task)) + Debug.Assert(task != null); + if (!_downloadTasksBuilder.Contains(task)) { _downloadTasksBuilder.Add(task); } } - public void Remove(DownloadTask task) => _downloadTasksBuilder.Remove(task); - #endregion Public Methods } } \ No newline at end of file diff --git a/src/c#/GeneralUpdate.Common/Download/DownloadTask.cs b/src/c#/GeneralUpdate.Common/Download/DownloadTask.cs index 05bd92fb..3409acdb 100644 --- a/src/c#/GeneralUpdate.Common/Download/DownloadTask.cs +++ b/src/c#/GeneralUpdate.Common/Download/DownloadTask.cs @@ -4,17 +4,17 @@ using System.Net.Http; using System.Threading; using System.Threading.Tasks; -using GeneralUpdate.Common.Download; +using GeneralUpdate.Common.Shared.Object; -namespace GeneralUpdate.Core.Download +namespace GeneralUpdate.Common.Download { - public class DownloadTask + public class DownloadTask { #region Private Members private readonly HttpClient _httpClient; - private readonly DownloadManager _manager; - private readonly TVersion _version; + private readonly DownloadManager _manager; + private readonly VersionBodyDTO _version; private const int DEFAULT_DELTA = 1048576; // 1024*1024 private long _beforBytes; private long _receivedBytes; @@ -26,7 +26,7 @@ public class DownloadTask #region Constructors - public DownloadTask(DownloadManager manager, TVersion version) + public DownloadTask(DownloadManager manager, VersionBodyDTO version) { _manager = manager; _version = version; @@ -50,20 +50,15 @@ public async Task LaunchAsync() { try { - var url = GetPropertyValue(_version, "Url"); - var name = GetPropertyValue(_version, "Name"); - var installPath = $"{_manager.Path}{name}{_manager.Format}"; - InitStatisticsEvent(); InitProgressEvent(); InitCompletedEvent(); - - await DownloadFileRangeAsync(url, installPath); + var path = Path.Combine(_manager.Path, $"{_version.Name}{_manager.Format}"); + await DownloadFileRangeAsync(_version.Url, path); } catch (Exception ex) { _manager.OnMultiDownloadError(this, new MultiDownloadErrorEventArgs(ex, _version)); - //throw new GeneralUpdateException("'download task' The executes abnormally !", ex); } } @@ -74,19 +69,20 @@ public async Task LaunchAsync() private async Task DownloadFileRangeAsync(string url, string path) { var tempPath = path + ".temp"; - long startPos = CheckFile(tempPath); + var startPos = CheckFile(tempPath); using var response = await _httpClient.GetAsync(url, HttpCompletionOption.ResponseHeadersRead); + if (!response.IsSuccessStatusCode) - { throw new HttpRequestException($"Failed to download file: {response.ReasonPhrase}"); - } var totalBytes = response.Content.Headers.ContentLength ?? 0; if (startPos >= totalBytes) { + if (File.Exists(path)) + File.Delete(path); + File.Move(tempPath, path); - OnCompleted(); return; } @@ -126,13 +122,18 @@ private async Task WriteFileAsync(string tempPath, byte[] chunk, long totalBytes using var fileStream = new FileStream(tempPath, FileMode.Append, FileAccess.Write, FileShare.None); await fileStream.WriteAsync(chunk, 0, chunk.Length); _receivedBytes += chunk.Length; - OnProgressChanged(_receivedBytes, totalBytes); if (_receivedBytes >= totalBytes) { fileStream.Close(); - File.Move(tempPath, tempPath.Replace(".temp", "")); - OnCompleted(); + + var path = tempPath.Replace(".temp", ""); + if (File.Exists(path)) + { + File.Delete(path); + } + + File.Move(tempPath, path); } } @@ -206,32 +207,6 @@ private void InitCompletedEvent() }; } - private void OnProgressChanged(long bytesReceived, long totalBytes) - { - _manager.OnMultiDownloadProgressChanged(this, new MultiDownloadProgressChangedEventArgs( - bytesReceived, totalBytes, (float)bytesReceived / totalBytes, _version)); - } - - private void OnCompleted() - { - _manager.OnMultiAsyncCompleted(this, new MultiDownloadCompletedEventArgs(_version, null, false, _version)); - } - - private TResult GetPropertyValue(TVersion entity, string propertyName) - { - TResult result = default(TResult); - try - { - var propertyInfo = typeof(TVersion).GetProperty(propertyName); - result = (TResult)propertyInfo?.GetValue(entity); - } - catch (Exception ex) - { - //throw new GeneralUpdateException($"Error getting property value: {ex.Message}", ex); - } - return result; - } - private string ToUnit(long byteSize) { var tempSize = Convert.ToSingle(byteSize) / 1024; diff --git a/src/c#/GeneralUpdate.Common/Driver/BackupDriverCommand.cs b/src/c#/GeneralUpdate.Common/Driver/BackupDriverCommand.cs deleted file mode 100644 index cf339c49..00000000 --- a/src/c#/GeneralUpdate.Common/Driver/BackupDriverCommand.cs +++ /dev/null @@ -1,48 +0,0 @@ -using System.IO; -using System.Text; - -namespace GeneralUpdate.Common.Driver -{ - /// - /// When the /export-driver command backs up a driver, it backs up the driver package along with all its dependencies, such as associated library files and other related files. - /// - public class BackupDriverCommand : IDriverCommand - { - private DriverInformation _information; - - public BackupDriverCommand(DriverInformation information) => _information = information; - - public void Execute() - { - /* - * Back up the specified list of drives. - */ - foreach (var driver in _information.Drivers) - { - //Export the backup according to the driver name. - var outPutDirectory = Path.Combine(_information.OutPutDirectory, Path.GetFileNameWithoutExtension(driver)); - - if (Directory.Exists(outPutDirectory)) - Directory.Delete(outPutDirectory, true); - - Directory.CreateDirectory(outPutDirectory); - - /* - * If no test driver files are available, you can run the following command to export all installed driver files. - * (1) dism /online /export-driver /destination:"D:\packet\cache\" - * (2) pnputil /export-driver * D:\packet\cache - * - * The following code example exports the specified driver to the specified directory. - * pnputil /export-driver oem14.inf D:\packet\cache - */ - var command = new StringBuilder("/c pnputil /export-driver ") - .Append(driver) - .Append(' ') - .Append(outPutDirectory) - .ToString(); - - CommandExecutor.ExecuteCommand(command); - } - } - } -} \ No newline at end of file diff --git a/src/c#/GeneralUpdate.Common/Driver/CommandExecutor.cs b/src/c#/GeneralUpdate.Common/Driver/CommandExecutor.cs deleted file mode 100644 index a6c55651..00000000 --- a/src/c#/GeneralUpdate.Common/Driver/CommandExecutor.cs +++ /dev/null @@ -1,44 +0,0 @@ -using System.Diagnostics; - -namespace GeneralUpdate.Common.Driver -{ - /// - /// When the process starts, PnPUtil is used to execute driver processing commands. - /// - public class CommandExecutor - { - public static void ExecuteCommand(string command) - { - /* - * - *Problems may occur, including: -Permission issues: PnPUtil requires administrator rights to run. If you try to run it without the proper permissions, the backup or restore may fail. -Driver compatibility: Although the backed up drivers work properly at backup time, if the operating system is upgraded, the backed up drivers may no longer be compatible with the new operating system version. -Hardware problems: If the hardware device fails or the hardware configuration changes, the backup driver may not work properly. - - To minimize these risks, the following measures are recommended: -Before doing anything, create a system restore point so that it can be restored to its previous state if something goes wrong. -Update the driver regularly to ensure that the driver is compatible with the current operating system version. -If possible, use pre-tested drivers that are proven to work. - * - */ - var processStartInfo = new ProcessStartInfo - { - WindowStyle = ProcessWindowStyle.Hidden, - FileName = "cmd.exe", - Arguments = command, - UseShellExecute = true, - Verb = "runas" - }; - - using (var process = new Process { StartInfo = processStartInfo }) - { - process.Start(); - process.WaitForExit(); - - if (process.ExitCode != 0) - throw new System.Exception($"Operation failed code: {process.ExitCode}"); - } - } - } -} \ No newline at end of file diff --git a/src/c#/GeneralUpdate.Common/Driver/DeleteDriverCommand.cs b/src/c#/GeneralUpdate.Common/Driver/DeleteDriverCommand.cs deleted file mode 100644 index 64c43198..00000000 --- a/src/c#/GeneralUpdate.Common/Driver/DeleteDriverCommand.cs +++ /dev/null @@ -1,23 +0,0 @@ -using System.Text; - -namespace GeneralUpdate.Common.Driver -{ - public class DeleteDriverCommand : IDriverCommand - { - private DriverInformation _information; - - public DeleteDriverCommand(DriverInformation information) => _information = information; - - public void Execute() - { - //Before installing the driver, delete the driver that has been installed on the local system. Otherwise, an exception may occur. - foreach (var driver in _information.Drivers) - { - var command = new StringBuilder("/c pnputil /delete-driver ") - .Append(driver) - .ToString(); - CommandExecutor.ExecuteCommand(command); - } - } - } -} \ No newline at end of file diff --git a/src/c#/GeneralUpdate.Common/Driver/DriverInformation.cs b/src/c#/GeneralUpdate.Common/Driver/DriverInformation.cs deleted file mode 100644 index 8a6a85ee..00000000 --- a/src/c#/GeneralUpdate.Common/Driver/DriverInformation.cs +++ /dev/null @@ -1,69 +0,0 @@ -using System.Collections.Generic; -using System.Linq; - -namespace GeneralUpdate.Common.Driver -{ - /// - /// Driver information object. - /// - public class DriverInformation - { - /// - /// Directory for storing the driver to be installed (Update the driver file in the package). - /// - public string InstallDirectory { get; private set; } - - /// - /// All driver backup directories. - /// - public string OutPutDirectory { get; private set; } - - /// - /// A collection of driver files to be backed up. - /// - public List Drivers { get; private set; } - - private DriverInformation() - { } - - public class Builder - { - private DriverInformation _information = new DriverInformation(); - - public Builder SetInstallDirectory(string installDirectory) - { - _information.InstallDirectory = installDirectory; - return this; - } - - public Builder SetOutPutDirectory(string outPutDirectory) - { - _information.OutPutDirectory = outPutDirectory; - return this; - } - - /// - /// Find the collection of driver names that need to be updated from the update package. - /// - /// - /// - public Builder SetDriverNames(List driverNames) - { - _information.Drivers = driverNames; - return this; - } - - public DriverInformation Build() - { - if (string.IsNullOrWhiteSpace(_information.InstallDirectory) || - string.IsNullOrWhiteSpace(_information.OutPutDirectory) || - !_information.Drivers.Any()) - { - throw new System.ArgumentException("Cannot create DriverInformation, not all fields are set."); - } - - return _information; - } - } - } -} \ No newline at end of file diff --git a/src/c#/GeneralUpdate.Common/Driver/DriverProcessor.cs b/src/c#/GeneralUpdate.Common/Driver/DriverProcessor.cs deleted file mode 100644 index a8d5f970..00000000 --- a/src/c#/GeneralUpdate.Common/Driver/DriverProcessor.cs +++ /dev/null @@ -1,36 +0,0 @@ -using System.Collections.Generic; -using System.Linq; - -namespace GeneralUpdate.Common.Driver -{ - /// - /// Handle all drive-related. - /// - public class DriverProcessor - { - private readonly List _commands = new List(); - - public void AddCommand(IDriverCommand command) - { - _commands.Add(command); - } - - /// - /// Execute all driver-related commands. - /// - public void ProcessCommands() - { - if (!_commands.Any()) return; - - /* - * This section describes the PnPUtil command. - * https://learn.microsoft.com/en-us/windows-hardware/drivers/devtest/pnputil-command-syntax - */ - foreach (var command in _commands) - { - command.Execute(); - } - _commands.Clear(); - } - } -} \ No newline at end of file diff --git a/src/c#/GeneralUpdate.Common/Driver/IDriverCommand.cs b/src/c#/GeneralUpdate.Common/Driver/IDriverCommand.cs deleted file mode 100644 index 4e10a51a..00000000 --- a/src/c#/GeneralUpdate.Common/Driver/IDriverCommand.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace GeneralUpdate.Common.Driver -{ - public interface IDriverCommand - { - void Execute(); - } -} \ No newline at end of file diff --git a/src/c#/GeneralUpdate.Common/Driver/InstallDriverCommand.cs b/src/c#/GeneralUpdate.Common/Driver/InstallDriverCommand.cs deleted file mode 100644 index dc0b8654..00000000 --- a/src/c#/GeneralUpdate.Common/Driver/InstallDriverCommand.cs +++ /dev/null @@ -1,44 +0,0 @@ -using System.IO; -using System.Text; - -namespace GeneralUpdate.Common.Driver -{ - /// - /// Install the new driver, and if the installation fails, the backup is automatically restored. - /// - public class InstallDriverCommand : IDriverCommand - { - private DriverInformation _information; - - public InstallDriverCommand(DriverInformation information) => _information = information; - - public void Execute() - { - try - { - foreach (var driver in _information.Drivers) - { - /* - * 1.It is best to ensure that the installed file is OEM INF, otherwise PnPUtil may indicate that non-OEM INF cannot perform the current operation. - * - * 2.Before installation, you need to delete the previously installed driver, otherwise PnPUtil will prompt 259 to exit the code. - * (On Windows, an ExitCode value of 259 (STILL_ACTIVE) means that the process is still running) - * If you do not remove the previous installation 259 prompt will give you a misleading impression of what is running. - */ - var path = Path.Combine(_information.InstallDirectory, Path.GetFileNameWithoutExtension(driver), driver); - var command = new StringBuilder("/c pnputil /add-driver ") - .Append(path) - .Append(" /install") - .ToString(); - CommandExecutor.ExecuteCommand(command); - } - } - catch (System.Exception ex) - { - //restore all the drivers in the backup directory. - new RestoreDriverCommand(_information).Execute(); - throw new System.Exception($"Failed to execute install command for {_information.InstallDirectory}", ex); - } - } - } -} \ No newline at end of file diff --git a/src/c#/GeneralUpdate.Common/Driver/RestoreDriverCommand.cs b/src/c#/GeneralUpdate.Common/Driver/RestoreDriverCommand.cs deleted file mode 100644 index 504b241f..00000000 --- a/src/c#/GeneralUpdate.Common/Driver/RestoreDriverCommand.cs +++ /dev/null @@ -1,25 +0,0 @@ -using System.IO; -using System.Text; - -namespace GeneralUpdate.Common.Driver -{ - public class RestoreDriverCommand : IDriverCommand - { - private DriverInformation _information; - - public RestoreDriverCommand(DriverInformation information) => _information = information; - - public void Execute() - { - foreach (var driver in _information.Drivers) - { - //Install all drivers in the specified directory, and if the installation fails, restore all the drivers in the backup directory. - var command = new StringBuilder("/c pnputil /add-driver ") - .Append(Path.Combine(_information.OutPutDirectory, Path.GetFileNameWithoutExtension(driver), driver)) - .Append(" /install") - .ToString(); - CommandExecutor.ExecuteCommand(command); - } - } - } -} \ No newline at end of file diff --git a/src/c#/GeneralUpdate.Common/File/ComparisonResult.cs b/src/c#/GeneralUpdate.Common/File/ComparisonResult.cs deleted file mode 100644 index 6a8d165a..00000000 --- a/src/c#/GeneralUpdate.Common/File/ComparisonResult.cs +++ /dev/null @@ -1,20 +0,0 @@ -using System.Collections.Generic; - -namespace GeneralUpdate.Common; - -public class ComparisonResult -{ - private readonly List _uniqueToA = new List(); - private readonly List _uniqueToB = new List(); - private readonly List _differentFiles = new List(); - - public IReadOnlyList UniqueToA => _uniqueToA.AsReadOnly(); - public IReadOnlyList UniqueToB => _uniqueToB.AsReadOnly(); - public IReadOnlyList DifferentFiles => _differentFiles.AsReadOnly(); - - public void AddUniqueToA(IEnumerable files) => _uniqueToA.AddRange(files); - - public void AddUniqueToB(IEnumerable files) => _uniqueToB.AddRange(files); - - public void AddDifferentFiles(IEnumerable files) => _differentFiles.AddRange(files); -} \ No newline at end of file diff --git a/src/c#/GeneralUpdate.Common/File/GeneralFileManager.cs b/src/c#/GeneralUpdate.Common/File/GeneralFileManager.cs deleted file mode 100644 index cf41e9cd..00000000 --- a/src/c#/GeneralUpdate.Common/File/GeneralFileManager.cs +++ /dev/null @@ -1,214 +0,0 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Text; -using GeneralUpdate.Common.HashAlgorithms; -using Newtonsoft.Json; - -namespace GeneralUpdate.Common -{ - public sealed class GeneralFileManager - { - #region Private Members - - private static readonly List _blackFileFormats = new List - { - ".patch", - ".7z", - ".zip", - ".rar", - ".tar", - ".json" - }; - - private static readonly List _blackFiles = new List { "Newtonsoft.Json.dll" }; - - #endregion - - #region Public Properties - - public static IReadOnlyList BlackFileFormats => _blackFileFormats.AsReadOnly(); - public static IReadOnlyList BlackFiles => _blackFiles.AsReadOnly(); - - public ComparisonResult ComparisonResult { get; private set; } - - #endregion - - #region Public Methods - - public static void AddBlackFileFormat(string format) - { - if (!_blackFileFormats.Contains(format)) - { - _blackFileFormats.Add(format); - } - } - - public static void RemoveBlackFileFormat(string format) - { - _blackFileFormats.Remove(format); - } - - public static void AddBlackFile(string fileName) - { - if (!_blackFiles.Contains(fileName)) - { - _blackFiles.Add(fileName); - } - } - - public static void RemoveBlackFile(string fileName) - { - _blackFiles.Remove(fileName); - } - - public void CompareDirectories(string dirA, string dirB) - { - ComparisonResult = new ComparisonResult(); - - var filesA = GetRelativeFilePaths(dirA, dirA).Where(f => !IsBlacklisted(f)).ToList(); - var filesB = GetRelativeFilePaths(dirB, dirB).Where(f => !IsBlacklisted(f)).ToList(); - - ComparisonResult.AddUniqueToA(filesA.Except(filesB).Select(f => Path.Combine(dirA, f))); - ComparisonResult.AddUniqueToB(filesB.Except(filesA).Select(f => Path.Combine(dirB, f))); - - var commonFiles = filesA.Intersect(filesB); - - foreach (var file in commonFiles) - { - var fileA = Path.Combine(dirA, file); - var fileB = Path.Combine(dirB, file); - - if (!FilesAreEqual(fileA, fileB)) - { - ComparisonResult.AddDifferentFiles(new[] { file }); - } - } - } - - public static void CreateJson(string targetPath, T obj) - { - var folderPath = Path.GetDirectoryName(targetPath) ?? - throw new ArgumentException("invalid path", nameof(targetPath)); - if (!Directory.Exists(folderPath)) - { - Directory.CreateDirectory(folderPath); - } - - var jsonString = JsonConvert.SerializeObject(obj); - File.WriteAllText(targetPath, jsonString); - } - - public static T GetJson(string path) - { - if (File.Exists(path)) - { - var json = File.ReadAllText(path); - return JsonConvert.DeserializeObject(json); - } - return default(T); - } - - /// - /// Convert object to base64 string. - /// - /// - /// - public static string Serialize(object obj) - { - if (obj == null) return string.Empty; - var json = JsonConvert.SerializeObject(obj); - var bytes = Encoding.Default.GetBytes(json); - var base64str = Convert.ToBase64String(bytes); - return base64str; - } - - /// - /// Convert base64 object to string. - /// - /// - /// - /// - public static T Deserialize(string str) - { - var obj = default(T); - if (string.IsNullOrEmpty(str)) return obj; - byte[] bytes = Convert.FromBase64String(str); - var json = Encoding.Default.GetString(bytes); - var result = JsonConvert.DeserializeObject(json); - return result; - } - - public static string GetTempDirectory(string name) - { - var path = $"generalupdate_{DateTime.Now.ToString("yyyy-MM-dd")}_{name}"; - var tempDir = Path.Combine(Path.GetTempPath(), path); - if (!Directory.Exists(tempDir)) - { - Directory.CreateDirectory(tempDir); - } - return tempDir; - } - - #endregion - - #region Private Methods - - private IEnumerable GetRelativeFilePaths(string rootDir, string currentDir) - { - foreach (var file in Directory.GetFiles(currentDir)) - { - yield return GetRelativePath(rootDir, file); - } - - foreach (var dir in Directory.GetDirectories(currentDir)) - { - foreach (var file in GetRelativeFilePaths(rootDir, dir)) - { - yield return file; - } - } - } - - private string GetRelativePath(string fromPath, string toPath) - { - var fromUri = new Uri(fromPath); - var toUri = new Uri(toPath); - - if (fromUri.Scheme != toUri.Scheme) - { - return toPath; - } // path can't be made relative. - - var relativeUri = fromUri.MakeRelativeUri(toUri); - var relativePath = Uri.UnescapeDataString(relativeUri.ToString()); - - if (toUri.Scheme.Equals("file", StringComparison.InvariantCultureIgnoreCase)) - { - relativePath = relativePath.Replace(Path.AltDirectorySeparatorChar, Path.DirectorySeparatorChar); - } - - return relativePath; - } - - private bool IsBlacklisted(string relativeFilePath) - { - var fileName = Path.GetFileName(relativeFilePath); - var fileExtension = Path.GetExtension(relativeFilePath); - - return _blackFiles.Contains(fileName) || _blackFileFormats.Contains(fileExtension); - } - - private bool FilesAreEqual(string fileA, string fileB) - { - var sha256 = new Sha256HashAlgorithm(); - var hashA = sha256.ComputeHash(fileA); - var hashB = sha256.ComputeHash(fileB); - - return hashA.SequenceEqual(hashB); - } - - #endregion - } -} \ No newline at end of file diff --git a/src/c#/GeneralUpdate.Common/FileBasic/BlackListManager.cs b/src/c#/GeneralUpdate.Common/FileBasic/BlackListManager.cs new file mode 100644 index 00000000..aea2517d --- /dev/null +++ b/src/c#/GeneralUpdate.Common/FileBasic/BlackListManager.cs @@ -0,0 +1,102 @@ +using System.Collections.Generic; +using System.IO; + +namespace GeneralUpdate.Common.FileBasic; + +public class BlackListManager +{ + private readonly static object _lockObject = new object(); + + private static BlackListManager _instance; + + private static readonly List _blackFileFormats = + [ + ".patch", + ".7z", + ".zip", + ".rar", + ".tar", + ".json", + ".pdb" + ]; + + private static readonly List _blackFiles = ["Newtonsoft.Json.dll"]; + + private BlackListManager() + { + } + + public static BlackListManager Instance + { + get + { + if (_instance == null) + { + lock (_lockObject) + { + if (_instance == null) + { + _instance = new BlackListManager(); + } + } + } + + return _instance; + } + } + + public IReadOnlyList BlackFileFormats => _blackFileFormats.AsReadOnly(); + public IReadOnlyList BlackFiles => _blackFiles.AsReadOnly(); + + public void AddBlackFileFormats(List? formats) + { + if(formats == null) + return; + + foreach (var format in formats) + { + AddBlackFileFormat(format); + } + } + + public void AddBlackFileFormat(string format) + { + if(string.IsNullOrWhiteSpace(format)) + return; + + if (!_blackFileFormats.Contains(format)) + { + _blackFileFormats.Add(format); + } + } + + public void AddBlackFiles(List? fileNames) + { + if(fileNames == null) + return; + + foreach (var fileName in fileNames) + { + AddBlackFile(fileName); + } + } + + public void AddBlackFile(string fileName) + { + if(string.IsNullOrWhiteSpace(fileName)) + return; + + if (!_blackFiles.Contains(fileName)) + { + _blackFiles.Add(fileName); + } + } + + public bool IsBlacklisted(string relativeFilePath) + { + var fileName = Path.GetFileName(relativeFilePath); + var fileExtension = Path.GetExtension(relativeFilePath); + + return _blackFiles.Contains(fileName) || _blackFileFormats.Contains(fileExtension); + } +} \ No newline at end of file diff --git a/src/c#/GeneralUpdate.Common/FileBasic/ComparisonResult.cs b/src/c#/GeneralUpdate.Common/FileBasic/ComparisonResult.cs new file mode 100644 index 00000000..41dbf234 --- /dev/null +++ b/src/c#/GeneralUpdate.Common/FileBasic/ComparisonResult.cs @@ -0,0 +1,41 @@ +using System.Collections.Generic; + +namespace GeneralUpdate.Common.FileBasic; + +/// +/// Result of a comparison between two directories. +/// +public class ComparisonResult +{ + private List _leftNodes; + private List _rightNodes; + private List _differentNodes; + + public ComparisonResult() + { + _leftNodes = new List(); + _rightNodes = new List(); + _differentNodes = new List(); + } + + /// + /// List of files that are unique to A. + /// + public IReadOnlyList LeftNodes => _leftNodes.AsReadOnly(); + + /// + /// List of files that are unique to B. + /// + public IReadOnlyList RightNodes => _rightNodes.AsReadOnly(); + + /// + /// List of files that are different between A and B. + /// + public IReadOnlyList DifferentNodes => _differentNodes.AsReadOnly(); + + public void AddToLeft(IEnumerable files) => _leftNodes.AddRange(files); + + public void AddToRight(IEnumerable files) => _rightNodes.AddRange(files); + + public void AddDifferent(IEnumerable files) => _differentNodes.AddRange(files); +} \ No newline at end of file diff --git a/src/c#/GeneralUpdate.Common/FileBasic/FileNode.cs b/src/c#/GeneralUpdate.Common/FileBasic/FileNode.cs new file mode 100644 index 00000000..90b3831a --- /dev/null +++ b/src/c#/GeneralUpdate.Common/FileBasic/FileNode.cs @@ -0,0 +1,150 @@ +using System; + +namespace GeneralUpdate.Common.FileBasic; + +public class FileNode +{ + #region Public Properties + + public long Id { get; set; } + + public string Name { get; set; } + + public string FullName { get; set; } + + public string Path { get; set; } + + public string Hash { get; set; } + + public FileNode Left { get; set; } + + public FileNode Right { get; set; } + + public int LeftType { get; set; } + + public int RightType { get; set; } + + public string RelativePath { get; set; } + + #endregion Public Properties + + #region Constructors + + public FileNode() + { + } + + public FileNode(int id) + { + Id = id; + } + + #endregion Constructors + + #region Public Methods + + public void Add(FileNode node) + { + if (node == null) return; + + if (node.Id < Id) + { + if (Left == null) + { + Left = node; + } + else + { + Left.Add(node); + } + } + else + { + if (Right == null) + { + Right = node; + } + else + { + Right.Add(node); + } + } + } + + public void InfixOrder() + { + if (Left != null) + { + Left.InfixOrder(); + } + + if (Right != null) + { + Right.InfixOrder(); + } + } + + public FileNode Search(long id) + { + if (id == Id) + { + return this; + } + else if (id < Id) + { + if (Left == null) return null; + return Left.Search(id); + } + else + { + if (Right == null) return null; + return Right.Search(id); + } + } + + /// + /// Find the parent node of the node that you want to delete. + /// + /// + /// + public FileNode SearchParent(long id) + { + if (Left != null && Left.Id == id || Right != null && Right.Id == id) + { + return this; + } + else + { + if (id < Id && Left != null) + { + return Left.SearchParent(id); + } + else if (id >= Id && Right != null) + { + return Right.SearchParent(id); + } + else + { + return null; + } + } + } + + /// + /// Compare tree nodes equally by Hash and file names. + /// + /// + /// + public override bool Equals(object obj) + { + if (obj == null) return false; + var tempNode = obj as FileNode; + if (tempNode == null) throw new ArgumentException(nameof(tempNode)); + return string.Equals(Hash, tempNode.Hash, StringComparison.OrdinalIgnoreCase) && + string.Equals(Name, tempNode.Name, StringComparison.OrdinalIgnoreCase); + } + + public override int GetHashCode() => base.GetHashCode(); + + #endregion Public Methods +} diff --git a/src/c#/GeneralUpdate.Core/ContentProvider/FileTree.cs b/src/c#/GeneralUpdate.Common/FileBasic/FileTree.cs similarity index 98% rename from src/c#/GeneralUpdate.Core/ContentProvider/FileTree.cs rename to src/c#/GeneralUpdate.Common/FileBasic/FileTree.cs index 31fd7f00..085013c7 100644 --- a/src/c#/GeneralUpdate.Core/ContentProvider/FileTree.cs +++ b/src/c#/GeneralUpdate.Common/FileBasic/FileTree.cs @@ -1,8 +1,8 @@ using System.Collections.Generic; using System.Diagnostics; -namespace GeneralUpdate.Core.ContentProvider -{ +namespace GeneralUpdate.Common.FileBasic; + /// /// Simple file binary tree. /// @@ -169,5 +169,4 @@ public void Compare(FileNode node, FileNode node0, ref List nodes) public FileNode GetRoot() => _root; #endregion Public Methods - } -} \ No newline at end of file + } \ No newline at end of file diff --git a/src/c#/GeneralUpdate.Common/FileBasic/GeneralFileManager.cs b/src/c#/GeneralUpdate.Common/FileBasic/GeneralFileManager.cs new file mode 100644 index 00000000..52da377b --- /dev/null +++ b/src/c#/GeneralUpdate.Common/FileBasic/GeneralFileManager.cs @@ -0,0 +1,167 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text.Json; +using System.Threading; +using GeneralUpdate.Common.HashAlgorithms; + +namespace GeneralUpdate.Common.FileBasic +{ + public sealed class GeneralFileManager + { + private long _fileCount = 0; + public ComparisonResult ComparisonResult { get; private set; } + + #region Public Methods + + /// + /// Using the list on the left as a baseline, find the set of differences between the two file lists. + /// + public IEnumerable Except(string leftPath, string rightPath) + { + var leftFileNodes = ReadFileNode(leftPath); + var rightFileNodes = ReadFileNode(rightPath); + var rightNodeDic = rightFileNodes.ToDictionary(x => x.RelativePath); + return leftFileNodes.Where(f => !rightNodeDic.ContainsKey(f.RelativePath)).ToList(); + } + + /// + /// Compare two directories. + /// + /// + /// + public ComparisonResult Compare(string leftDir, string rightDir) + { + ResetId(); + ComparisonResult = new ComparisonResult(); + var leftFileNodes = ReadFileNode(leftDir); + var rightFileNodes = ReadFileNode(rightDir); + var leftTree = new FileTree(leftFileNodes); + var rightTree = new FileTree(rightFileNodes); + var differentTreeNode = new List(); + leftTree.Compare(leftTree.GetRoot(), rightTree.GetRoot(), ref differentTreeNode); + ComparisonResult.AddToLeft(leftFileNodes); + ComparisonResult.AddToRight(rightFileNodes); + ComparisonResult.AddDifferent(differentTreeNode); + return ComparisonResult; + } + + public static void CreateJson(string targetPath, T obj) where T : class + { + var folderPath = Path.GetDirectoryName(targetPath) ?? + throw new ArgumentException("invalid path", nameof(targetPath)); + if (!Directory.Exists(folderPath)) + { + Directory.CreateDirectory(folderPath); + } + + var jsonString = JsonSerializer.Serialize(obj); + File.WriteAllText(targetPath, jsonString); + } + + public static T? GetJson(string path) where T : class + { + if (File.Exists(path)) + { + var json = File.ReadAllText(path); + return JsonSerializer.Deserialize(json); + } + + return default; + } + + public static string GetTempDirectory(string name) + { + var path = $"generalupdate_{DateTime.Now:yyyy-MM-dd}_{name}"; + var tempDir = Path.Combine(Path.GetTempPath(), path); + if (!Directory.Exists(tempDir)) + { + Directory.CreateDirectory(tempDir); + } + + return tempDir; + } + + public static List GetAllfiles(string path) + { + try + { + var files = new List(); + files.AddRange(new DirectoryInfo(path).GetFiles()); + var tmpDir = new DirectoryInfo(path).GetDirectories(); + foreach (var dic in tmpDir) + { + files.AddRange(GetAllfiles(dic.FullName)); + } + + return files; + } + catch (Exception) + { + return null; + } + } + + public static bool HashEquals(string leftPath, string rightPath) + { + var hashAlgorithm = new Sha256HashAlgorithm(); + var hashLeft = hashAlgorithm.ComputeHash(leftPath); + var hashRight = hashAlgorithm.ComputeHash(rightPath); + return hashLeft.SequenceEqual(hashRight); + } + + #endregion + + #region Private Methods + + /// + /// Recursively read all files in the folder path. + /// + private IEnumerable ReadFileNode(string path, string rootPath = null) + { + var resultFiles = new List(); + rootPath ??= path; + if (!rootPath.EndsWith("/")) + { + rootPath += "/"; + } + var rootUri = new Uri(rootPath); + + foreach (var subPath in Directory.EnumerateFiles(path)) + { + if (BlackListManager.Instance.IsBlacklisted(subPath)) continue; + + var hashAlgorithm = new Sha256HashAlgorithm(); + var hash = hashAlgorithm.ComputeHash(subPath); + var subFileInfo = new FileInfo(subPath); + var subUri = new Uri(subFileInfo.FullName); + resultFiles.Add(new FileNode + { + Id = GetId(), + Path = path, + Name = subFileInfo.Name, + Hash = hash, + FullName = subFileInfo.FullName, + RelativePath = rootUri.MakeRelativeUri(subUri).ToString() + }); + } + + foreach (var subPath in Directory.EnumerateDirectories(path)) + { + resultFiles.AddRange(ReadFileNode(subPath, rootPath)); + } + + return resultFiles; + } + + /// + /// Self-growing file tree node ID. + /// + private long GetId() => Interlocked.Increment(ref _fileCount); + + private void ResetId() => Interlocked.Exchange(ref _fileCount, 0); + + #endregion + } +} \ No newline at end of file diff --git a/src/c#/GeneralUpdate.Common/GeneralUpdate.Common.csproj b/src/c#/GeneralUpdate.Common/GeneralUpdate.Common.csproj index 05f942be..f842ca31 100644 --- a/src/c#/GeneralUpdate.Common/GeneralUpdate.Common.csproj +++ b/src/c#/GeneralUpdate.Common/GeneralUpdate.Common.csproj @@ -7,9 +7,9 @@ - - - + + + diff --git a/src/c#/GeneralUpdate.Common/HashAlgorithms/HashAlgorithmBase.cs b/src/c#/GeneralUpdate.Common/HashAlgorithms/HashAlgorithmBase.cs index ef57e5da..d32ee2c8 100644 --- a/src/c#/GeneralUpdate.Common/HashAlgorithms/HashAlgorithmBase.cs +++ b/src/c#/GeneralUpdate.Common/HashAlgorithms/HashAlgorithmBase.cs @@ -15,7 +15,7 @@ public string ComputeHash(string fileName) { using (var file = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.Read)) { - var dataArray = GetHashAlgorithm().ComputeHash(file); + var dataArray = hashAlgorithm.ComputeHash(file); var stringBuilder = new StringBuilder(); for (int i = 0; i < dataArray.Length; i++) { diff --git a/src/c#/GeneralUpdate.Common/Internal/Bootstrap/AbstractBootstrap.cs b/src/c#/GeneralUpdate.Common/Internal/Bootstrap/AbstractBootstrap.cs index c388b248..e9088041 100644 --- a/src/c#/GeneralUpdate.Common/Internal/Bootstrap/AbstractBootstrap.cs +++ b/src/c#/GeneralUpdate.Common/Internal/Bootstrap/AbstractBootstrap.cs @@ -1,7 +1,7 @@ using System; using System.Collections.Concurrent; -using System.Collections.Generic; -using System.Diagnostics.Contracts; +using System.Diagnostics; +using System.Threading.Tasks; using GeneralUpdate.Common.Internal.Strategy; namespace GeneralUpdate.Common.Internal.Bootstrap @@ -10,73 +10,22 @@ public abstract class AbstractBootstrap where TBootstrap : AbstractBootstrap where TStrategy : IStrategy { - #region Private Members - private readonly ConcurrentDictionary _options; - private volatile Func _strategyFactory; - private IStrategy _strategy; - - #endregion Private Members - - #region Constructors - - protected internal AbstractBootstrap() => this._options = new ConcurrentDictionary(); - - #endregion Constructors - #region Methods + protected internal AbstractBootstrap() => + _options = new ConcurrentDictionary(); /// - /// Launch udpate. + /// Launch async udpate. /// /// - public virtual TBootstrap LaunchAsync() - { - return (TBootstrap)this; - } - - #region Strategy + public abstract Task LaunchAsync(); - protected IStrategy InitStrategy() - { - return _strategy; - } - - protected string GetPlatform() => _strategy.GetPlatform(); + protected abstract void ExecuteStrategy(); + + protected abstract Task ExecuteStrategyAsync(); - protected IStrategy ExecuteStrategy() - { - if (_strategy != null) _strategy.Execute(); - return _strategy; - } - - public virtual TBootstrap Validate() - { - if (this._strategyFactory == null) throw new InvalidOperationException("Strategy or strategy factory not set."); - return (TBootstrap)this; - } - - public virtual TBootstrap Strategy() where T : TStrategy, new() => this.StrategyFactory(() => new T()); - - public TBootstrap StrategyFactory(Func strategyFactory) - { - this._strategyFactory = strategyFactory; - return (TBootstrap)this; - } - - #endregion Strategy - - #region Config option. - - /// - /// Files in the blacklist will skip the update. - /// - /// blacklist file name - /// - public virtual TBootstrap SetBlacklist(List files = null, List fileFormats = null) - { - return (TBootstrap)this; - } + protected abstract TBootstrap StrategyFactory(); /// /// Setting update configuration. @@ -85,38 +34,32 @@ public virtual TBootstrap SetBlacklist(List files = null, List f /// Configuration Action Enumeration. /// Value /// - public virtual TBootstrap Option(UpdateOption option, T value) + public TBootstrap Option(UpdateOption option, T value) { - Contract.Requires(option != null); if (value == null) { - this._options.TryRemove(option, out _); + _options.TryRemove(option, out _); } else { - this._options[option] = new UpdateOptionValue(option, value); + _options[option] = new UpdateOptionValue(option, value); } return (TBootstrap)this; } - public virtual T GetOption(UpdateOption option) + protected T? GetOption(UpdateOption? option) { try { - if (_options == null || _options.Count == 0) return default(T); + Debug.Assert(option != null && _options.Count != 0); var val = _options[option]; if (val != null) return (T)val.GetValue(); - return default(T); + return default; } catch { - return default(T); + return default; } } - - #endregion Config option. - - - #endregion Methods } } \ No newline at end of file diff --git a/src/c#/GeneralUpdate.Common/Internal/Bootstrap/UpdateOption.cs b/src/c#/GeneralUpdate.Common/Internal/Bootstrap/UpdateOption.cs index e0455d17..804ac4ad 100644 --- a/src/c#/GeneralUpdate.Common/Internal/Bootstrap/UpdateOption.cs +++ b/src/c#/GeneralUpdate.Common/Internal/Bootstrap/UpdateOption.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Diagnostics.Contracts; +using System.Text; using System.Threading; namespace GeneralUpdate.Common.Internal.Bootstrap @@ -12,10 +13,30 @@ private class UpdateOptionPool : ConstantPool protected override IConstant NewConstant(int id, string name) => new UpdateOption(id, name); } - private static readonly UpdateOptionPool Pool = new UpdateOptionPool(); + private static readonly UpdateOptionPool Pool = new(); public static UpdateOption ValueOf(string name) => (UpdateOption)Pool.ValueOf(name); + /// + /// Update the file format of the package. + /// + public static readonly UpdateOption Format = ValueOf("COMPRESSFORMAT"); + + /// + /// Compress encoding. + /// + public static readonly UpdateOption Encoding = ValueOf("COMPRESSENCODING"); + + /// + /// Timeout period (unit: second). If this parameter is not specified, the default timeout period is 30 seconds. + /// + public static readonly UpdateOption DownloadTimeOut = ValueOf("DOWNLOADTIMEOUT"); + + /// + /// Whether to enable the driver upgrade function. + /// + public static readonly UpdateOption Drive = ValueOf("DRIVE"); + internal UpdateOption(int id, string name) : base(id, name) { } diff --git a/src/c#/GeneralUpdate.Common/Internal/Event/EventManager.cs b/src/c#/GeneralUpdate.Common/Internal/Event/EventManager.cs index f31f430b..4308aab0 100644 --- a/src/c#/GeneralUpdate.Common/Internal/Event/EventManager.cs +++ b/src/c#/GeneralUpdate.Common/Internal/Event/EventManager.cs @@ -1,46 +1,16 @@ using System; using System.Collections.Generic; -using System.ComponentModel; namespace GeneralUpdate.Common.Internal.Event { - /// - /// Manage all events in the component. - /// - public class EventManager : IEventManager, IDisposable + public class EventManager : IDisposable { - // Use interop to call the method necessary - // to clean up the unmanaged resource. - [System.Runtime.InteropServices.DllImport("Kernel32")] - private static extern Boolean CloseHandle(IntPtr handle); - private static readonly object _lockObj = new object(); private static EventManager _instance; private Dictionary _dicDelegates = new Dictionary(); - - // Track whether Dispose has been called. private bool disposed = false; - // Pointer to an external unmanaged resource. - private IntPtr handle; - - // Other managed resource this class uses. - private Component component = null; - - private EventManager() => component = new Component(); - - // Use C# finalizer syntax for finalization code. - // This finalizer will run only if the Dispose method - // does not get called. - // It gives your base class the opportunity to finalize. - // Do not provide finalizer in types derived from this class. - ~EventManager() - { - // Do not re-create Dispose clean-up code here. - // Calling Dispose(disposing: false) is optimal in terms of - // readability and maintainability. - Dispose(disposing: false); - } + private EventManager() { } public static EventManager Instance { @@ -58,107 +28,48 @@ public static EventManager Instance } } - /// - /// Add listener - /// - /// Specify the delegate type. - /// Delegate to be added. - /// parameter null exception. - public void AddListener(TDelegate newDelegate) where TDelegate : Delegate + public void AddListener(Action listener) where TEventArgs : EventArgs { - if (newDelegate == null) throw new ArgumentNullException(nameof(newDelegate)); - if (_dicDelegates.ContainsKey(typeof(TDelegate))) return; - handle = new IntPtr(1); - _dicDelegates.Add(typeof(TDelegate), newDelegate); + if (listener == null) throw new ArgumentNullException(nameof(listener)); + var delegateType = typeof(Action); + if (_dicDelegates.ContainsKey(delegateType)) + { + _dicDelegates[delegateType] = Delegate.Combine(_dicDelegates[delegateType], listener); + } + else + { + _dicDelegates.Add(delegateType, listener); + } } - /// - /// Remove listener - /// - /// Specify the delegate type. - /// Remove old delegates. - /// parameter null exception. - public void RemoveListener(TDelegate oldDelegate) where TDelegate : Delegate + public void RemoveListener(Action listener) where TEventArgs : EventArgs { - if (oldDelegate == null) throw new ArgumentNullException(nameof(oldDelegate)); - var delegateType = oldDelegate.GetType(); - if (!delegateType.IsInstanceOfType(typeof(TDelegate))) return; - Delegate tempDelegate = null; - if (_dicDelegates.TryGetValue(delegateType, out tempDelegate)) + if (listener == null) throw new ArgumentNullException(nameof(listener)); + var delegateType = typeof(Action); + if (_dicDelegates.TryGetValue(delegateType, out var existingDelegate)) { - if (tempDelegate == null) - { - _dicDelegates.Remove(delegateType); - } - else - { - _dicDelegates[delegateType] = tempDelegate; - } + _dicDelegates[delegateType] = Delegate.Remove(existingDelegate, listener); } } - /// - /// Triggers a delegate of the same type. - /// - /// - /// trigger source object. - /// event args. - /// parameter null exception. - public void Dispatch(object sender, EventArgs eventArgs) where TDelegate : Delegate + public void Dispatch(object sender, TEventArgs eventArgs) where TEventArgs : EventArgs { if (sender == null) throw new ArgumentNullException(nameof(sender)); if (eventArgs == null) throw new ArgumentNullException(nameof(eventArgs)); - if (!_dicDelegates.ContainsKey(typeof(TDelegate))) return; - _dicDelegates[typeof(TDelegate)].DynamicInvoke(sender, eventArgs); + var delegateType = typeof(Action); + if (_dicDelegates.TryGetValue(delegateType, out var existingDelegate)) + { + ((Action)existingDelegate)?.Invoke(sender, eventArgs); + } } - /// - /// Clear all listeners. - /// public void Clear() => _dicDelegates.Clear(); - // Implement IDisposable. - // Do not make this method virtual. - // A derived class should not be able to override this method. public void Dispose() { - Dispose(disposing: true); - // This object will be cleaned up by the Dispose method. - // Therefore, you should call GC.SuppressFinalize to - // take this object off the finalization queue - // and prevent finalization code for this object - // from executing a second time. - GC.SuppressFinalize(this); - } - - // Dispose(bool disposing) executes in two distinct scenarios. - // If disposing equals true, the method has been called directly - // or indirectly by a user's code. Managed and unmanaged resources - // can be disposed. - // If disposing equals false, the method has been called by the - // runtime from inside the finalizer and you should not reference - // other objects. Only unmanaged resources can be disposed. - protected virtual void Dispose(bool disposing) - { - // Check to see if Dispose has already been called. if (!this.disposed) { - // If disposing equals true, dispose all managed - // and unmanaged resources. - if (disposing) - { - // Dispose managed resources. - component.Dispose(); - } - - // Call the appropriate methods to clean up - // unmanaged resources here. - // If disposing is false, - // only the following code is executed. - CloseHandle(handle); - handle = IntPtr.Zero; - - // Note disposing has been done. + _dicDelegates.Clear(); disposed = true; } } diff --git a/src/c#/GeneralUpdate.Common/Internal/Exception/BaseArgs.cs b/src/c#/GeneralUpdate.Common/Internal/Exception/BaseArgs.cs index b29af43a..d0aa03d2 100644 --- a/src/c#/GeneralUpdate.Common/Internal/Exception/BaseArgs.cs +++ b/src/c#/GeneralUpdate.Common/Internal/Exception/BaseArgs.cs @@ -1,6 +1,6 @@ using System; -namespace GeneralUpdate.Common.Internal.Exception +namespace GeneralUpdate.Common.Internal { [Serializable] public abstract class BaseArgs diff --git a/src/c#/GeneralUpdate.Common/Internal/Exception/ExceptionEventArgs.cs b/src/c#/GeneralUpdate.Common/Internal/Exception/ExceptionEventArgs.cs new file mode 100644 index 00000000..54850e56 --- /dev/null +++ b/src/c#/GeneralUpdate.Common/Internal/Exception/ExceptionEventArgs.cs @@ -0,0 +1,15 @@ +using System; + +namespace GeneralUpdate.Common.Internal; + +public class ExceptionEventArgs : EventArgs +{ + public ExceptionEventArgs(Exception exception = null, string message = null) + { + Exception = exception ?? throw new Exception(nameof(exception)); + Message = message ?? exception.Message; + } + + public Exception Exception { get; private set; } + public string Message { get; private set; } +} \ No newline at end of file diff --git a/src/c#/GeneralUpdate.Common/Internal/Exception/GeneralUpdateException.cs b/src/c#/GeneralUpdate.Common/Internal/Exception/GeneralUpdateException.cs index f5e05091..ff3f7fd0 100644 --- a/src/c#/GeneralUpdate.Common/Internal/Exception/GeneralUpdateException.cs +++ b/src/c#/GeneralUpdate.Common/Internal/Exception/GeneralUpdateException.cs @@ -2,7 +2,7 @@ using System.Runtime.Serialization; using System.Security.Permissions; -namespace GeneralUpdate.Common.Internal.Exception +namespace GeneralUpdate.Common.Internal { /// /// Exception of GeneralUpdate framework. diff --git a/src/c#/GeneralUpdate.Common/Internal/Pipeline/IContext.cs b/src/c#/GeneralUpdate.Common/Internal/Pipeline/IContext.cs deleted file mode 100644 index 2b8400b1..00000000 --- a/src/c#/GeneralUpdate.Common/Internal/Pipeline/IContext.cs +++ /dev/null @@ -1,10 +0,0 @@ -namespace GeneralUpdate.Common.Internal.Pipeline -{ - /// - /// Pipeline context. - /// - public interface IContext - { - - } -} \ No newline at end of file diff --git a/src/c#/GeneralUpdate.Common/Internal/Pipeline/IMiddleware.cs b/src/c#/GeneralUpdate.Common/Internal/Pipeline/IMiddleware.cs index 910fa130..606b1c7c 100644 --- a/src/c#/GeneralUpdate.Common/Internal/Pipeline/IMiddleware.cs +++ b/src/c#/GeneralUpdate.Common/Internal/Pipeline/IMiddleware.cs @@ -7,6 +7,6 @@ namespace GeneralUpdate.Common.Internal.Pipeline /// public interface IMiddleware { - Task InvokeAsync(IContext context, IMiddleware middleware); + Task InvokeAsync(PipelineContext context); } } \ No newline at end of file diff --git a/src/c#/GeneralUpdate.Common/Internal/Pipeline/PipelineBuilder.cs b/src/c#/GeneralUpdate.Common/Internal/Pipeline/PipelineBuilder.cs index 5d0fb84b..e0ffcc3c 100644 --- a/src/c#/GeneralUpdate.Common/Internal/Pipeline/PipelineBuilder.cs +++ b/src/c#/GeneralUpdate.Common/Internal/Pipeline/PipelineBuilder.cs @@ -7,28 +7,37 @@ namespace GeneralUpdate.Common.Internal.Pipeline /// /// Pipeline builder. /// - public sealed class PipelineBuilder(IContext context = null) + public sealed class PipelineBuilder(PipelineContext context = null) { + /// + /// LIFO,Last In First Out. + /// private ImmutableStack _middlewareStack = ImmutableStack.Empty; - public PipelineBuilder Use(TMiddleware middleware) where TMiddleware : IMiddleware, new() + public PipelineBuilder UseMiddleware() where TMiddleware : IMiddleware, new() { + var middleware = new TMiddleware(); _middlewareStack = _middlewareStack.Push(middleware); return this; } - public PipelineBuilder UseIf(TMiddleware middleware, Func condition) + public PipelineBuilder UseMiddlewareIf(bool? condition) where TMiddleware : IMiddleware, new() { - if (!condition()) return this; + if (condition is null or false) + return this; + + var middleware = new TMiddleware(); _middlewareStack = _middlewareStack.Push(middleware); return this; } public async Task Build() { - var middleware = _middlewareStack.Peek(); - await middleware.InvokeAsync(context, _middlewareStack.Peek()); + foreach (var middleware in _middlewareStack) + { + await middleware.InvokeAsync(context); + } } } } \ No newline at end of file diff --git a/src/c#/GeneralUpdate.Common/Internal/Pipeline/PipelineContext.cs b/src/c#/GeneralUpdate.Common/Internal/Pipeline/PipelineContext.cs new file mode 100644 index 00000000..8a85686f --- /dev/null +++ b/src/c#/GeneralUpdate.Common/Internal/Pipeline/PipelineContext.cs @@ -0,0 +1,32 @@ +using System; +using System.Collections.Concurrent; + +namespace GeneralUpdate.Common.Internal.Pipeline; + +public class PipelineContext +{ + private ConcurrentDictionary _context = new(); + + public TValue? Get(string key) + { + if (_context.TryGetValue(key, out var value)) + { + return value is TValue typedValue ? typedValue : default; + } + return default; + } + + public void Add(string key, TValue? value) + { + if (string.IsNullOrWhiteSpace(key)) + { + throw new ArgumentException("Key cannot be null or whitespace.", nameof(key)); + } + + _context[key] = value; + } + + public bool Remove(string key) => _context.TryRemove(key, out _); + + public bool ContainsKey(string key) => _context.ContainsKey(key); +} \ No newline at end of file diff --git a/src/c#/GeneralUpdate.Common/Internal/Strategy/AbstractStrategy.cs b/src/c#/GeneralUpdate.Common/Internal/Strategy/AbstractStrategy.cs index 527325d6..44f87cba 100644 --- a/src/c#/GeneralUpdate.Common/Internal/Strategy/AbstractStrategy.cs +++ b/src/c#/GeneralUpdate.Common/Internal/Strategy/AbstractStrategy.cs @@ -1,6 +1,9 @@ using System; -using System.Text; +using System.Diagnostics; +using System.IO; +using System.Runtime.InteropServices; using System.Threading.Tasks; +using GeneralUpdate.Common.Shared.Object; namespace GeneralUpdate.Common.Internal.Strategy { @@ -9,15 +12,39 @@ public abstract class AbstractStrategy : IStrategy protected const string PATCHS = "patchs"; public virtual void Execute() => throw new NotImplementedException(); + + public virtual void StartApp() => throw new NotImplementedException(); + + public virtual Task ExecuteAsync() => throw new NotImplementedException(); - public virtual bool StartApp(string appName, int appType) => throw new NotImplementedException(); + public virtual void Create(GlobalConfigInfo parameter) => throw new NotImplementedException(); - public virtual string GetPlatform() => throw new NotImplementedException(); - - public virtual Task ExecuteTaskAsync() => throw new NotImplementedException(); - - public virtual void Create(T parameter) where T : class => throw new NotImplementedException(); - - public virtual void Create(T parameter, Encoding encoding) where T : class => throw new NotImplementedException(); + protected void OpenBrowser(string url) + { + if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + { + Process.Start(new ProcessStartInfo("cmd", $"/c start {url}") { CreateNoWindow = true }); + } + else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) + { + Process.Start("xdg-open", url); + } + else + { + throw new PlatformNotSupportedException("Unsupported OS platform"); + } + } + + /// + /// Remove update redundant files. + /// + /// + protected void Clear(string path) + { + if (Directory.Exists(path)) + { + Directory.Delete(path, true); + } + } } } \ No newline at end of file diff --git a/src/c#/GeneralUpdate.Common/Internal/Strategy/IStrategy.cs b/src/c#/GeneralUpdate.Common/Internal/Strategy/IStrategy.cs index 5295a586..bc583b71 100644 --- a/src/c#/GeneralUpdate.Common/Internal/Strategy/IStrategy.cs +++ b/src/c#/GeneralUpdate.Common/Internal/Strategy/IStrategy.cs @@ -1,4 +1,5 @@ using System.Threading.Tasks; +using GeneralUpdate.Common.Shared.Object; namespace GeneralUpdate.Common.Internal.Strategy { @@ -15,26 +16,16 @@ public interface IStrategy /// /// After the update is complete. /// - /// - /// - /// - bool StartApp(string appName, int appType); - - /// - /// Get the platform for the current strategy. - /// - /// - string GetPlatform(); - + void StartApp(); + /// /// Execution strategy. /// - Task ExecuteTaskAsync(); + Task ExecuteAsync(); /// /// Create a strategy. /// - /// Abstraction for updating package information. - void Create(T parameter) where T : class; + void Create(GlobalConfigInfo parameter); } } \ No newline at end of file diff --git a/src/c#/GeneralUpdate.Common/Shared/Object/Assembler/ProcessAssembler.cs b/src/c#/GeneralUpdate.Common/Shared/Object/Assembler/ProcessAssembler.cs deleted file mode 100644 index 4c30240a..00000000 --- a/src/c#/GeneralUpdate.Common/Shared/Object/Assembler/ProcessAssembler.cs +++ /dev/null @@ -1,60 +0,0 @@ -using System.Text; - -namespace GeneralUpdate.Common.Shared.Object -{ - public class ProcessAssembler - { - public static Packet ToPacket(ProcessInfo info) - { - var packet = new Packet(); - packet.AppName = info.AppName; - packet.AppSecretKey = info.AppSecretKey; - packet.AppType = info.AppType; - packet.InstallPath = info.InstallPath; - packet.ClientVersion = info.CurrentVersion; - packet.LastVersion = info.LastVersion; - packet.UpdateLogUrl = info.LogUrl; - packet.Encoding = ToEncoding(info.CompressEncoding); - packet.Format = info.CompressFormat; - packet.DownloadTimeOut = info.DownloadTimeOut; - packet.UpdateVersions = info.UpdateVersions; - return packet; - } - - private static Encoding ToEncoding(int type) - { - Encoding encoding = Encoding.Default; - switch (type) - { - case 1: - encoding = Encoding.UTF8; - break; - - case 2: - encoding = Encoding.UTF7; - break; - - case 3: - encoding = Encoding.UTF32; - break; - - case 4: - encoding = Encoding.Unicode; - break; - - case 5: - encoding = Encoding.BigEndianUnicode; - break; - - case 6: - encoding = Encoding.ASCII; - break; - - case 7: - encoding = Encoding.Default; - break; - } - return encoding; - } - } -} \ No newline at end of file diff --git a/src/c#/GeneralUpdate.Common/Shared/Object/Assembler/VersionAssembler.cs b/src/c#/GeneralUpdate.Common/Shared/Object/Assembler/VersionAssembler.cs deleted file mode 100644 index 8c3f1ad4..00000000 --- a/src/c#/GeneralUpdate.Common/Shared/Object/Assembler/VersionAssembler.cs +++ /dev/null @@ -1,37 +0,0 @@ -using System.Collections.Generic; - -namespace GeneralUpdate.Common.Shared.Object -{ - public class VersionAssembler - { - public static List ToDataObjects(List versionDTO) - { - List entitys = new List(); - versionDTO.ForEach((v) => - { - entitys.Add(ToDataObject(v)); - }); - return entitys; - } - - public static VersionInfo ToDataObject(VersionConfigDO versionDO) - { - return new VersionInfo(versionDO.PubTime, versionDO.Name, versionDO.Hash, versionDO.Version, versionDO.Url); - } - - public static List ToEntitys(List versionDTO) - { - List entitys = new List(); - versionDTO.ForEach((v) => - { - entitys.Add(ToEntity(v)); - }); - return entitys; - } - - public static VersionInfo ToEntity(VersionDTO versionDTO) - { - return new VersionInfo(versionDTO.PubTime, versionDTO.Name, versionDTO.Hash, versionDTO.Version, versionDTO.Url); - } - } -} \ No newline at end of file diff --git a/src/c#/GeneralUpdate.Common/Shared/Object/Configinfo.cs b/src/c#/GeneralUpdate.Common/Shared/Object/Configinfo.cs index 1b7f541d..f111b33c 100644 --- a/src/c#/GeneralUpdate.Common/Shared/Object/Configinfo.cs +++ b/src/c#/GeneralUpdate.Common/Shared/Object/Configinfo.cs @@ -1,36 +1,38 @@ using System; -using System.IO; +using System.Collections.Generic; namespace GeneralUpdate.Common.Shared.Object { - public class Configinfo : Entity + /// + /// Global update parameters. + /// + public class Configinfo { - public Configinfo() - { } - - public Configinfo(int appType, string appName, string appSecretKey, string clientVersion, string updateUrl, string updateLogUrl, string installPath, string mainUpdateUrl, string mainAppName) - { - AppType = appType; - AppName = appName ?? throw new ArgumentNullException(nameof(appName)); - AppSecretKey = appSecretKey ?? throw new ArgumentNullException(nameof(appSecretKey)); - ClientVersion = clientVersion ?? throw new ArgumentNullException(nameof(clientVersion)); - UpdateUrl = updateUrl ?? throw new ArgumentNullException(nameof(updateUrl)); - UpdateLogUrl = updateLogUrl ?? throw new ArgumentNullException(nameof(updateLogUrl)); - InstallPath = installPath ?? Directory.GetCurrentDirectory(); - MainUpdateUrl = mainUpdateUrl ?? throw new ArgumentNullException(nameof(mainUpdateUrl)); - MainAppName = mainAppName ?? throw new ArgumentNullException(nameof(mainAppName)); - } + /// + /// Update check api address. + /// + public string UpdateUrl { get; set; } /// - /// 1:ClientApp 2:UpdateApp + /// API address for reporting update status. /// - public int AppType { get; set; } + public string ReportUrl { get; set; } /// /// Need to start the name of the app. /// public string AppName { get; set; } + /// + /// The name of the main application, without .exe. + /// + public string MainAppName { get; set; } + + /// + /// Update log web address. + /// + public string UpdateLogUrl { get; set; } + /// /// application key /// @@ -40,27 +42,59 @@ public Configinfo(int appType, string appName, string appSecretKey, string clien /// Client current version. /// public string ClientVersion { get; set; } + + /// + /// Upgrade Client current version. + /// + public string UpgradeClientVersion { get; set; } /// - /// Update check api address. + /// installation path (for update file logic). /// - public string UpdateUrl { get; set; } + public string InstallPath { get; set; } /// - /// Update log web address. + /// Files in the blacklist will skip the update. /// - public string UpdateLogUrl { get; set; } + public List BlackFiles { get; set; } /// - /// installation path (for update file logic). + /// File formats in the blacklist will skip the update. /// - public string InstallPath { get; set; } + public List BlackFormats { get; set; } + + /// + /// The platform of the application. + /// + public int Platform { get; set; } /// - /// Update check api address. + /// Product ID. /// - public string MainUpdateUrl { get; set; } + public string ProductId { get; set; } - public string MainAppName { get; set; } + public void Validate() + { + if (string.IsNullOrWhiteSpace(UpdateUrl) || !Uri.IsWellFormedUriString(UpdateUrl, UriKind.Absolute)) + throw new ArgumentException("Invalid UpdateUrl"); + + if (!string.IsNullOrWhiteSpace(UpdateLogUrl) && !Uri.IsWellFormedUriString(UpdateLogUrl, UriKind.Absolute)) + throw new ArgumentException("Invalid UpdateLogUrl"); + + if (string.IsNullOrWhiteSpace(AppName)) + throw new ArgumentException("AppName cannot be empty"); + + if (string.IsNullOrWhiteSpace(MainAppName)) + throw new ArgumentException("MainAppName cannot be empty"); + + if (string.IsNullOrWhiteSpace(AppSecretKey)) + throw new ArgumentException("AppSecretKey cannot be empty"); + + if (string.IsNullOrWhiteSpace(ClientVersion)) + throw new ArgumentException("ClientVersion cannot be empty"); + + if (string.IsNullOrWhiteSpace(InstallPath)) + throw new ArgumentException("InstallPath cannot be empty"); + } } } \ No newline at end of file diff --git a/src/c#/GeneralUpdate.Common/Shared/Object/DTO/BaseResponseDTO.cs b/src/c#/GeneralUpdate.Common/Shared/Object/DTO/BaseResponseDTO.cs index 72b8a5fa..dfa9b49a 100644 --- a/src/c#/GeneralUpdate.Common/Shared/Object/DTO/BaseResponseDTO.cs +++ b/src/c#/GeneralUpdate.Common/Shared/Object/DTO/BaseResponseDTO.cs @@ -1,11 +1,16 @@ -namespace GeneralUpdate.Common.Shared.Object +using System.Text.Json.Serialization; + +namespace GeneralUpdate.Common.Shared.Object { public class BaseResponseDTO { + [JsonPropertyName("code")] public int Code { get; set; } + [JsonPropertyName("body")] public TBody Body { get; set; } + [JsonPropertyName("message")] public string Message { get; set; } } } \ No newline at end of file diff --git a/src/c#/GeneralUpdate.Common/Shared/Object/DTO/UploadReapDTO.cs b/src/c#/GeneralUpdate.Common/Shared/Object/DTO/UploadReapDTO.cs deleted file mode 100644 index bd1ab92c..00000000 --- a/src/c#/GeneralUpdate.Common/Shared/Object/DTO/UploadReapDTO.cs +++ /dev/null @@ -1,6 +0,0 @@ -namespace GeneralUpdate.Common.Shared.Object -{ - public class UploadReapDTO : BaseResponseDTO - { - } -} \ No newline at end of file diff --git a/src/c#/GeneralUpdate.Common/Shared/Object/DTO/VersionDTO.cs b/src/c#/GeneralUpdate.Common/Shared/Object/DTO/VersionDTO.cs deleted file mode 100644 index 502bd92e..00000000 --- a/src/c#/GeneralUpdate.Common/Shared/Object/DTO/VersionDTO.cs +++ /dev/null @@ -1,24 +0,0 @@ -namespace GeneralUpdate.Common.Shared.Object -{ - public class VersionDTO - { - public VersionDTO(string hash, long pubTime, string version, string url, string name) - { - Hash = hash; - PubTime = pubTime; - Version = version; - Url = url; - Name = name; - } - - public string Hash { get; set; } - - public long PubTime { get; set; } - - public string Version { get; set; } - - public string Url { get; set; } - - public string Name { get; set; } - } -} \ No newline at end of file diff --git a/src/c#/GeneralUpdate.Common/Shared/Object/DTO/VersionRespDTO.cs b/src/c#/GeneralUpdate.Common/Shared/Object/DTO/VersionRespDTO.cs index d42a71d6..a86b9d36 100644 --- a/src/c#/GeneralUpdate.Common/Shared/Object/DTO/VersionRespDTO.cs +++ b/src/c#/GeneralUpdate.Common/Shared/Object/DTO/VersionRespDTO.cs @@ -1,27 +1,48 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; +using System.Text.Json.Serialization; namespace GeneralUpdate.Common.Shared.Object { - public class VersionRespDTO : BaseResponseDTO + public class VersionRespDTO : BaseResponseDTO> { } public class VersionBodyDTO { - public bool IsUpdate { get; set; } - - /// - /// Is forcibly update. - /// - public bool IsForcibly { get; set; } - - /// - /// 1:ClientApp 2:UpdateApp - /// - public int ClientType { get; set; } - - /// - /// Returns information about all versions that are different from the latest version based on the current version of the client. - /// - public List Versions { get; set; } + [JsonPropertyName("recordId")] + public int RecordId { get; set; } + + [JsonPropertyName("name")] + public string? Name { get; set; } + + [JsonPropertyName("hash")] + public string? Hash { get; set; } + + [JsonPropertyName("releaseDate")] + public DateTime? ReleaseDate { get; set; } + + [JsonPropertyName("url")] + public string? Url { get; set; } + + [JsonPropertyName("version")] + public string? Version { get; set; } + + [JsonPropertyName("appType")] + public int? AppType { get; set; } + + [JsonPropertyName("platform")] + public int? Platform { get; set; } + + [JsonPropertyName("productId")] + public string? ProductId { get; set; } + + [JsonPropertyName("isForcibly")] + public bool? IsForcibly { get; set; } + + [JsonPropertyName("format")] + public string Format { get; set; } + + [JsonPropertyName("size")] + public long? Size { get; set; } } } \ No newline at end of file diff --git a/src/c#/GeneralUpdate.Common/Shared/Object/Entity.cs b/src/c#/GeneralUpdate.Common/Shared/Object/Entity.cs deleted file mode 100644 index c40237f6..00000000 --- a/src/c#/GeneralUpdate.Common/Shared/Object/Entity.cs +++ /dev/null @@ -1,31 +0,0 @@ -using System; -using System.Text.RegularExpressions; - -namespace GeneralUpdate.Common.Shared.Object -{ - public class Entity - { - /// - /// 委派标识 - /// - protected string Identity { get; set; } - - public string ID - { - get { return this.Identity; } - protected set { this.Identity = value; } - } - - protected bool IsURL(string url) - { - string check = @"((http|ftp|https)://)(([a-zA-Z0-9\._-]+\.[a-zA-Z]{2,6})|([0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}))(:[0-9]{1,4})*(/[a-zA-Z0-9\&%_\./-~-]*)?"; - var regex = new Regex(check); - return regex.IsMatch(url); - } - - protected bool IsVersion(string version) - { - return Version.TryParse(version, out var ver); - } - } -} \ No newline at end of file diff --git a/src/c#/GeneralUpdate.Common/Shared/Object/Enum/Format.cs b/src/c#/GeneralUpdate.Common/Shared/Object/Enum/Format.cs index cae1d5d2..0548ee08 100644 --- a/src/c#/GeneralUpdate.Common/Shared/Object/Enum/Format.cs +++ b/src/c#/GeneralUpdate.Common/Shared/Object/Enum/Format.cs @@ -2,7 +2,7 @@ { public class Format { - public const string ZIP = "zip"; - public const string SEVENZIP = "7z"; + public const string ZIP = ".zip"; + public const string SEVENZIP = ".7z"; } } \ No newline at end of file diff --git a/src/c#/GeneralUpdate.Common/Shared/Object/Enum/ProgressType.cs b/src/c#/GeneralUpdate.Common/Shared/Object/Enum/ProgressType.cs index 0547e764..7cd00365 100644 --- a/src/c#/GeneralUpdate.Common/Shared/Object/Enum/ProgressType.cs +++ b/src/c#/GeneralUpdate.Common/Shared/Object/Enum/ProgressType.cs @@ -1,4 +1,4 @@ -namespace GeneralUpdate.Common.Shared.Object +namespace GeneralUpdate.Common.Shared.Object.Enum { public enum ProgressType { diff --git a/src/c#/GeneralUpdate.Common/Shared/Object/GlobalConfigInfo.cs b/src/c#/GeneralUpdate.Common/Shared/Object/GlobalConfigInfo.cs new file mode 100644 index 00000000..96400bc3 --- /dev/null +++ b/src/c#/GeneralUpdate.Common/Shared/Object/GlobalConfigInfo.cs @@ -0,0 +1,118 @@ +using System.Collections.Generic; +using System.Text; + +namespace GeneralUpdate.Common.Shared.Object; + +public class GlobalConfigInfo +{ + /// + /// Update check api address. + /// + public string UpdateUrl { get; set; } + + /// + /// API address for reporting update status. + /// + public string ReportUrl { get; set; } + + /// + /// Need to start the name of the app. + /// + public string AppName { get; set; } + + /// + /// The name of the main application, without .exe. + /// + public string MainAppName { get; set; } + + /// + /// Update package file format(Defult format is Zip). + /// + public string Format { get; set; } + + /// + /// Whether an update is required to upgrade the application. + /// + public bool IsUpgradeUpdate { get; set; } + + /// + /// Whether the main application needs to be updated. + /// + public bool IsMainUpdate { get; set; } + + /// + /// Update log web address. + /// + public string UpdateLogUrl { get; set; } + + /// + /// Version information that needs to be updated. + /// + public List UpdateVersions { get; set; } + + /// + /// The encoding format for file operations. + /// + public Encoding Encoding { get; set; } + + /// + /// Time-out event for file download. + /// + public int DownloadTimeOut { get; set; } + + /// + /// application key + /// + public string AppSecretKey { get; set; } + + /// + /// Client current version. + /// + public string ClientVersion { get; set; } + + /// + /// Upgrade Client current version. + /// + public string UpgradeClientVersion { get; set; } + + /// + /// The latest version. + /// + public string LastVersion { get; set; } + + /// + /// installation path (for update file logic). + /// + public string InstallPath { get; set; } + + /// + /// Download file temporary storage path (for update file logic). + /// + public string TempPath { get; set; } + + /// + /// Configuration parameters for upgrading the terminal program. + /// + public string ProcessInfo { get; set; } + + /// + /// Files in the blacklist will skip the update. + /// + public List BlackFiles { get; set; } + + /// + /// File formats in the blacklist will skip the update. + /// + public List BlackFormats { get; set; } + + /// + /// Whether to enable the driver upgrade function. + /// + public bool? DriveEnabled { get; set; } + + public int Platform { get; set; } + + public string ProductId { get; set; } + + public Dictionary FieldMappings { get; set; } +} \ No newline at end of file diff --git a/src/c#/GeneralUpdate.Common/Shared/Object/Packet.cs b/src/c#/GeneralUpdate.Common/Shared/Object/Packet.cs deleted file mode 100644 index a2edd846..00000000 --- a/src/c#/GeneralUpdate.Common/Shared/Object/Packet.cs +++ /dev/null @@ -1,145 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Text; - -namespace GeneralUpdate.Common.Shared.Object -{ - public class Packet : Entity - { - public Packet() - { } - - public Packet(string mainUpdateUrl, int appType, string updateUrl, string appName, string mainAppName, string format, bool isUpdate, string updateLogUrl, Encoding encoding, int downloadTimeOut, string appSecretKey, string tempPath) - { - if (!IsURL(mainUpdateUrl)) throw new Exception($"Illegal url {nameof(mainUpdateUrl)}"); - MainUpdateUrl = mainUpdateUrl ?? throw new ArgumentNullException(nameof(MainUpdateUrl)); - if (!IsURL(updateUrl)) throw new Exception($"Illegal url {nameof(UpdateUrl)}"); - UpdateUrl = updateUrl ?? throw new ArgumentNullException(nameof(updateUrl)); - UpdateLogUrl = updateLogUrl ?? throw new ArgumentNullException(nameof(updateLogUrl)); - AppType = appType; - AppName = appName ?? throw new ArgumentNullException(nameof(appName)); - MainAppName = mainAppName ?? throw new ArgumentNullException(nameof(mainAppName)); - Format = format ?? throw new ArgumentNullException(nameof(format)); - IsUpgradeUpdate = isUpdate; - Encoding = encoding ?? throw new ArgumentNullException(nameof(encoding)); - DownloadTimeOut = downloadTimeOut; - AppSecretKey = appSecretKey ?? throw new ArgumentNullException(nameof(appSecretKey)); - TempPath = tempPath ?? throw new ArgumentNullException(nameof(tempPath)); - } - - /// - /// Update check api address. - /// - public string MainUpdateUrl { get; set; } - - /// - /// 1:ClientApp 2:UpdateApp - /// - public int AppType { get; set; } - - /// - /// Update check api address. - /// - public string UpdateUrl { get; set; } - - /// - /// Need to start the name of the app. - /// - public string AppName { get; set; } - - /// - /// The name of the main application, without .exe. - /// - public string MainAppName { get; set; } - - /// - /// Update package file format(Defult format is Zip). - /// - public string Format { get; set; } - - /// - /// Whether an update is required to upgrade the application. - /// - public bool IsUpgradeUpdate { get; set; } - - /// - /// Whether the main application needs to be updated. - /// - public bool IsMainUpdate { get; set; } - - /// - /// Update log web address. - /// - public string UpdateLogUrl { get; set; } - - /// - /// Version information that needs to be updated. - /// - public List UpdateVersions { get; set; } - - /// - /// The encoding format for file operations. - /// - public Encoding Encoding { get; set; } - - /// - /// Time-out event for file download. - /// - public int DownloadTimeOut { get; set; } - - /// - /// application key - /// - public string AppSecretKey { get; set; } - - /// - /// Client current version. - /// - public string ClientVersion { get; set; } - - /// - /// The latest version. - /// - public string LastVersion { get; set; } - - /// - /// installation path (for update file logic). - /// - public string InstallPath { get; set; } - - /// - /// Download file temporary storage path (for update file logic). - /// - public string TempPath { get; set; } - - /// - /// Configuration parameters for upgrading the terminal program. - /// - public string ProcessBase64 { get; set; } - - /// - /// The platform to which the current strategy belongs. - /// - public string Platform { get; set; } - - /// - /// Files in the blacklist will skip the update. - /// - public List BlackFiles { get; set; } - - /// - /// File formats in the blacklist will skip the update. - /// - public List BlackFormats { get; set; } - - /// - /// Whether to enable the driver upgrade function. - /// - public bool DriveEnabled { get; set; } - - /// - /// Whether open note function, if you want to start needs to be synchronized to deploy 'GeneralUpdate. SystemService' service. - /// - public bool WillMessageEnabled { get; set; } - } -} \ No newline at end of file diff --git a/src/c#/GeneralUpdate.Common/Shared/Object/ParamsOSS.cs b/src/c#/GeneralUpdate.Common/Shared/Object/ParamsOSS.cs index 3f861905..e8675c17 100644 --- a/src/c#/GeneralUpdate.Common/Shared/Object/ParamsOSS.cs +++ b/src/c#/GeneralUpdate.Common/Shared/Object/ParamsOSS.cs @@ -2,7 +2,7 @@ namespace GeneralUpdate.Common.Shared.Object { - public class ParamsOSS : Entity + public class ParamsOSS { public string Url { get; set; } diff --git a/src/c#/GeneralUpdate.Common/Shared/Object/ProcessInfo.cs b/src/c#/GeneralUpdate.Common/Shared/Object/ProcessInfo.cs index 00062bdd..aacfb604 100644 --- a/src/c#/GeneralUpdate.Common/Shared/Object/ProcessInfo.cs +++ b/src/c#/GeneralUpdate.Common/Shared/Object/ProcessInfo.cs @@ -2,104 +2,141 @@ using System.Collections.Generic; using System.IO; using System.Text; +using System.Text.Json.Serialization; namespace GeneralUpdate.Common.Shared.Object { - public class ProcessInfo : Entity + public class ProcessInfo { - public ProcessInfo() - { } + public ProcessInfo() { } - public ProcessInfo(string appName, string installPath, string currentVersion, string lastVersion, string logUrl, Encoding compressEncoding, string compressFormat, int downloadTimeOut, string appSecretKey, List updateVersions) + public ProcessInfo(string appName + , string installPath + , string currentVersion + , string lastVersion + , string updateLogUrl + , Encoding compressEncoding + , string compressFormat + , int downloadTimeOut + , string appSecretKey + , List updateVersions + , string reportUrl) { AppName = appName ?? throw new ArgumentNullException(nameof(appName)); if (!Directory.Exists(installPath)) throw new ArgumentException($"{nameof(installPath)} path does not exist ! {installPath}."); InstallPath = installPath ?? throw new ArgumentNullException(nameof(installPath)); CurrentVersion = currentVersion ?? throw new ArgumentNullException(nameof(currentVersion)); LastVersion = lastVersion ?? throw new ArgumentNullException(nameof(lastVersion)); - LogUrl = logUrl; - compressEncoding = compressEncoding ?? Encoding.Default; + UpdateLogUrl = updateLogUrl; CompressEncoding = ToEncodingType(compressEncoding); CompressFormat = compressFormat; if (downloadTimeOut < 0) throw new ArgumentException("Timeout must be greater than 0 !"); DownloadTimeOut = downloadTimeOut; AppSecretKey = appSecretKey ?? throw new ArgumentNullException(nameof(appSecretKey)); if (updateVersions == null || updateVersions.Count == 0) throw new ArgumentException("Collection cannot be null or has 0 elements !"); - UpdateVersions = VersionAssembler.ToEntitys(updateVersions); - } - - private int ToEncodingType(Encoding encoding) - { - int type = -1; - if (encoding == Encoding.UTF8) - { - type = 1; - } - else if (encoding == Encoding.UTF7) - { - type = 2; - } - else if (encoding == Encoding.UTF32) - { - type = 3; - } - else if (encoding == Encoding.Unicode) - { - type = 4; - } - else if (encoding == Encoding.BigEndianUnicode) - { - type = 5; - } - else if (encoding == Encoding.ASCII) - { - type = 6; - } - else if (encoding == Encoding.Default) - { - type = 7; - } - return type; + UpdateVersions = updateVersions; + ReportUrl = reportUrl ?? throw new ArgumentNullException(nameof(reportUrl)); } - /// - /// 1:MainApp 2:UpdateApp - /// - public int AppType { get; set; } - /// /// Need to start the name of the app. /// + [JsonPropertyName("AppName")] public string AppName { get; set; } /// /// Installation directory (the path where the update package is decompressed). /// + [JsonPropertyName("InstallPath")] public string InstallPath { get; set; } + /// + /// Current version. + /// + [JsonPropertyName("CurrentVersion")] public string CurrentVersion { get; set; } + /// + /// The version of the last update. + /// + [JsonPropertyName("LastVersion")] public string LastVersion { get; set; } /// /// Update log web address. /// - public string LogUrl { get; set; } + [JsonPropertyName("UpdateLogUrl")] + public string UpdateLogUrl { get; set; } + /// + /// The encoding type of the update package. + /// + [JsonPropertyName("CompressEncoding")] public int CompressEncoding { get; set; } + /// + /// The compression format of the update package. + /// + [JsonPropertyName("CompressFormat")] public string CompressFormat { get; set; } + /// + /// The timeout of the download. + /// + [JsonPropertyName("DownloadTimeOut")] public int DownloadTimeOut { get; set; } /// /// application key /// + [JsonPropertyName("AppSecretKey")] public string AppSecretKey { get; set; } /// /// One or more version update information. /// - public List UpdateVersions { get; set; } + [JsonPropertyName("UpdateVersions")] + public List UpdateVersions { get; set; } + + /// + /// update report web address + /// + [JsonPropertyName("ReportUrl")] + public string ReportUrl { get; set; } + + private static int ToEncodingType(Encoding encoding) + { + var type = -1; + if (Equals(encoding, Encoding.UTF8)) + { + type = 1; + } + else if (Equals(encoding, Encoding.UTF7)) + { + type = 2; + } + else if (Equals(encoding, Encoding.UTF32)) + { + type = 3; + } + else if (Equals(encoding, Encoding.Unicode)) + { + type = 4; + } + else if (Equals(encoding, Encoding.BigEndianUnicode)) + { + type = 5; + } + else if (Equals(encoding, Encoding.ASCII)) + { + type = 6; + } + else if (Equals(encoding, Encoding.Default)) + { + type = 7; + } + + return type; + } } } \ No newline at end of file diff --git a/src/c#/GeneralUpdate.Common/Shared/Object/VersionConfigDO.cs b/src/c#/GeneralUpdate.Common/Shared/Object/VersionConfigDO.cs deleted file mode 100644 index edeca18b..00000000 --- a/src/c#/GeneralUpdate.Common/Shared/Object/VersionConfigDO.cs +++ /dev/null @@ -1,64 +0,0 @@ -using System; - -namespace GeneralUpdate.Common.Shared.Object -{ - public class VersionConfigDO - { - /// - /// Product branch ID (Used to distinguish multiple branches under the same product). - /// - public string Guid { get; set; } - - /// - /// Update package download location. - /// - public string Url { get; set; } - - /// - /// Hash verification code - /// - public string Hash { get; set; } - - /// - /// Update the package name. - /// - public string Name { get; set; } - - /// - /// Update the package file format. - /// - public string Format { get; set; } - - /// - /// The version number that will be updated. - /// - public string Version { get; set; } - - /// - /// Update package release time. - /// - public long PubTime { get; set; } - - /// - /// Init version config infomation. - /// - /// - /// - /// - /// - /// - /// - /// - /// - public VersionConfigDO(string guid, string url, string hash, string name, string format, string version, long pubTime) - { - Guid = guid ?? throw new ArgumentNullException(nameof(guid)); - Url = url ?? throw new ArgumentNullException(nameof(url)); - Hash = hash ?? throw new ArgumentNullException(nameof(hash)); - Name = name ?? throw new ArgumentNullException(nameof(name)); - Format = format ?? throw new ArgumentNullException(nameof(format)); - Version = version ?? throw new ArgumentNullException(nameof(version)); - PubTime = pubTime; - } - } -} \ No newline at end of file diff --git a/src/c#/GeneralUpdate.Common/Shared/Object/VersionInfo.cs b/src/c#/GeneralUpdate.Common/Shared/Object/VersionInfo.cs index e118cbbf..ebe6bb5d 100644 --- a/src/c#/GeneralUpdate.Common/Shared/Object/VersionInfo.cs +++ b/src/c#/GeneralUpdate.Common/Shared/Object/VersionInfo.cs @@ -2,7 +2,7 @@ namespace GeneralUpdate.Common.Shared.Object { - public class VersionInfo : Entity + public class VersionInfo { public VersionInfo() { } @@ -14,7 +14,6 @@ public VersionInfo(long pubTime, string name, string hash, string version, strin Hash = hash ?? throw new ArgumentNullException(nameof(hash)); Version = version ?? throw new ArgumentNullException(nameof(version)); Url = url ?? throw new ArgumentNullException(nameof(Url)); - if (!IsURL(Url)) throw new Exception($"Illegal url {nameof(Url)}"); } /// diff --git a/src/c#/GeneralUpdate.Common/Shared/Service/VersionService.cs b/src/c#/GeneralUpdate.Common/Shared/Service/VersionService.cs index 52e74ada..61a2c83d 100644 --- a/src/c#/GeneralUpdate.Common/Shared/Service/VersionService.cs +++ b/src/c#/GeneralUpdate.Common/Shared/Service/VersionService.cs @@ -1,72 +1,83 @@ using System; +using System.Collections.Generic; +using System.IO; using System.Net.Http; using System.Security.Cryptography.X509Certificates; using System.Net.Security; +using System.Text; +using System.Text.Json; +using System.Text.Json.Serialization; using System.Threading.Tasks; using GeneralUpdate.Common.Shared.Object; -using Newtonsoft.Json; namespace GeneralUpdate.Common.Shared.Service { public class VersionService { - private static readonly HttpClient _httpClient; - - static VersionService() + /// + /// Report the result of this update: whether it was successful. + /// + /// + /// + /// + /// + /// + public static async Task> Report(string httpUrl + , int recordId + , int status + , int? type) { - _httpClient = new HttpClient(new HttpClientHandler + var parameters = new Dictionary { - ServerCertificateCustomValidationCallback = CheckValidationResult - }); - _httpClient.Timeout = TimeSpan.FromSeconds(15); - _httpClient.DefaultRequestHeaders.Accept.ParseAdd("text/html, application/xhtml+xml, */*"); + { "RecordId", recordId }, + { "Status", status }, + { "Type", type } + }; + return await PostTaskAsync>(httpUrl, parameters); } - public async Task ValidationVersion(string url) + /// + /// Verify whether the current version needs an update. + /// + /// + /// + /// + /// + /// + /// + /// + public static async Task Validate(string httpUrl + , string version + , int appType + , string appKey + , int platform, + string productId) { - var updateResp = await GetTaskAsync(url); - if (updateResp == null || updateResp.Body == null) - { - throw new ArgumentNullException( - nameof(updateResp), - "The verification request is abnormal, please check the network or parameter configuration!" - ); - } - - if (updateResp.Code == 200) - { - return updateResp; - } - else + var parameters = new Dictionary { - throw new HttpRequestException( - $"Request failed, Code: {updateResp.Code}, Message: {updateResp.Message}!" - ); - } + { "Version", version }, + { "AppType", appType }, + { "AppKey", appKey }, + { "Platform", platform }, + { "ProductId", productId } + }; + return await PostTaskAsync(httpUrl, parameters); } - private async Task GetTaskAsync(string url, string headerKey = null, string headerValue = null) + private static async Task PostTaskAsync(string httpUrl, Dictionary parameters) { - try + var uri = new Uri(httpUrl); + using var httpClient = new HttpClient(new HttpClientHandler { - var request = new HttpRequestMessage(HttpMethod.Get, url); - if (!string.IsNullOrEmpty(headerKey) && !string.IsNullOrEmpty(headerValue)) - { - request.Headers.Add(headerKey, headerValue); - } - - var response = await _httpClient.SendAsync(request); - response.EnsureSuccessStatusCode(); // Throw if not a success code. - var responseContent = await response.Content.ReadAsStringAsync(); - var result = JsonConvert.DeserializeObject(responseContent); - - return result; - } - catch (Exception ex) - { - // Log the exception here as needed - return default; - } + ServerCertificateCustomValidationCallback = CheckValidationResult + }); + httpClient.Timeout = TimeSpan.FromSeconds(15); + httpClient.DefaultRequestHeaders.Accept.ParseAdd("text/html, application/xhtml+xml, */*"); + string parametersJson = JsonSerializer.Serialize(parameters); + var stringContent = new StringContent(parametersJson, Encoding.UTF8, "application/json"); + var result = await httpClient.PostAsync(uri, stringContent); + var reseponseJson = await result.Content.ReadAsStringAsync(); + return JsonSerializer.Deserialize(reseponseJson); } private static bool CheckValidationResult( diff --git a/src/c#/GeneralUpdate.Core/Bootstrap/AbstractBootstrap.cs b/src/c#/GeneralUpdate.Core/Bootstrap/AbstractBootstrap.cs deleted file mode 100644 index 637f4677..00000000 --- a/src/c#/GeneralUpdate.Core/Bootstrap/AbstractBootstrap.cs +++ /dev/null @@ -1,223 +0,0 @@ -using GeneralUpdate.Core.ContentProvider; -using GeneralUpdate.Core.Domain.Entity; -using GeneralUpdate.Core.Domain.Enum; -using GeneralUpdate.Core.Download; -using GeneralUpdate.Core.Events; -using GeneralUpdate.Core.Events.CommonArgs; -using GeneralUpdate.Core.Events.MultiEventArgs; -using GeneralUpdate.Core.Strategys; -using System; -using System.Collections.Concurrent; -using System.Collections.Generic; -using System.Diagnostics.Contracts; -using System.IO; -using System.Text; - -namespace GeneralUpdate.Core.Bootstrap -{ - public abstract class AbstractBootstrap - where TBootstrap : AbstractBootstrap - where TStrategy : IStrategy - { - #region Private Members - - private readonly ConcurrentDictionary _options; - private volatile Func _strategyFactory; - private Packet _packet; - private IStrategy _strategy; - private const string EXECUTABLE_FILE = ".exe"; - - #endregion Private Members - - #region Constructors - - protected internal AbstractBootstrap() => this._options = new ConcurrentDictionary(); - - #endregion Constructors - - #region Public Properties - - public Packet Packet - { - get { return _packet ?? (_packet = new Packet()); } - set { _packet = value; } - } - - #endregion Public Properties - - #region Methods - - /// - /// Launch udpate. - /// - /// - public virtual TBootstrap LaunchAsync() - { - try - { - InitStrategy(); - //When the upgrade stops and does not need to be updated, the client needs to be updated. Start the upgrade assistant directly. - if (!Packet.IsUpgradeUpdate && Packet.IsMainUpdate) _strategy.StartApp(Packet.AppName, Packet.AppType); - Packet.Format = $".{GetOption(UpdateOption.Format) ?? Format.ZIP}"; - Packet.Encoding = GetOption(UpdateOption.Encoding) ?? Encoding.Default; - Packet.DownloadTimeOut = GetOption(UpdateOption.DownloadTimeOut); - Packet.AppName = $"{Packet.AppName ?? GetOption(UpdateOption.MainApp)}{EXECUTABLE_FILE}"; - Packet.TempPath = $"{FileProvider.GetTempDirectory(Packet.LastVersion)}{Path.DirectorySeparatorChar}"; - Packet.DriveEnabled = GetOption(UpdateOption.Drive) ?? false; - Packet.WillMessageEnabled = GetOption(UpdateOption.WillMessage) ?? false; - var manager = new DownloadManager(Packet.TempPath, Packet.Format, Packet.DownloadTimeOut); - manager.MultiAllDownloadCompleted += OnMultiAllDownloadCompleted; - manager.MultiDownloadCompleted += OnMultiDownloadCompleted; - manager.MultiDownloadError += OnMultiDownloadError; - manager.MultiDownloadProgressChanged += OnMultiDownloadProgressChanged; - manager.MultiDownloadStatistics += OnMultiDownloadStatistics; - Packet.UpdateVersions.ForEach((v) => manager.Add(new DownloadTask(manager, v))); - manager.LaunchTaskAsync(); - } - catch (Exception ex) - { - EventManager.Instance.Dispatch>(this, new ExceptionEventArgs(ex)); - } - return (TBootstrap)this; - } - - #region Strategy - - protected IStrategy InitStrategy() - { - if (_strategy == null) - { - Validate(); - _strategy = _strategyFactory(); - Packet.Platform = _strategy.GetPlatform(); - _strategy.Create(Packet); - } - return _strategy; - } - - protected string GetPlatform() => _strategy.GetPlatform(); - - protected IStrategy ExecuteStrategy() - { - if (_strategy != null) _strategy.Execute(); - return _strategy; - } - - public virtual TBootstrap Validate() - { - if (this._strategyFactory == null) throw new InvalidOperationException("Strategy or strategy factory not set."); - return (TBootstrap)this; - } - - public virtual TBootstrap Strategy() where T : TStrategy, new() => this.StrategyFactory(() => new T()); - - public TBootstrap StrategyFactory(Func strategyFactory) - { - this._strategyFactory = strategyFactory; - return (TBootstrap)this; - } - - #endregion Strategy - - #region Config option. - - /// - /// Files in the blacklist will skip the update. - /// - /// blacklist file name - /// - public virtual TBootstrap SetBlacklist(List files = null, List fileFormats = null) - { - Packet.BlackFiles = files; - Packet.BlackFormats = fileFormats; - return (TBootstrap)this; - } - - /// - /// Setting update configuration. - /// - /// - /// Configuration Action Enumeration. - /// Value - /// - public virtual TBootstrap Option(UpdateOption option, T value) - { - Contract.Requires(option != null); - if (value == null) - { - this._options.TryRemove(option, out _); - } - else - { - this._options[option] = new UpdateOptionValue(option, value); - } - return (TBootstrap)this; - } - - public virtual T GetOption(UpdateOption option) - { - try - { - if (_options == null || _options.Count == 0) return default(T); - var val = _options[option]; - if (val != null) return (T)val.GetValue(); - return default(T); - } - catch - { - return default(T); - } - } - - #endregion Config option. - - #region Callback event. - - public TBootstrap AddListenerMultiAllDownloadCompleted(Action callbackAction) => AddListener(callbackAction); - - public TBootstrap AddListenerMultiDownloadProgress(Action callbackAction) => AddListener(callbackAction); - - public TBootstrap AddListenerMultiDownloadCompleted(Action callbackAction) => AddListener(callbackAction); - - public TBootstrap AddListenerMultiDownloadError(Action callbackAction) => AddListener(callbackAction); - - public TBootstrap AddListenerMultiDownloadStatistics(Action callbackAction) => AddListener(callbackAction); - - public TBootstrap AddListenerException(Action callbackAction) => AddListener(callbackAction); - - protected TBootstrap AddListener(Action callbackAction) where TArgs : EventArgs - { - if (callbackAction != null) EventManager.Instance.AddListener(callbackAction); - return (TBootstrap)this; - } - - private void OnMultiDownloadStatistics(object sender, MultiDownloadStatisticsEventArgs e) - => EventManager.Instance.Dispatch>(sender, e); - - private void OnMultiDownloadProgressChanged(object sender, MultiDownloadProgressChangedEventArgs e) - => EventManager.Instance.Dispatch>(sender, e); - - private void OnMultiDownloadCompleted(object sender, MultiDownloadCompletedEventArgs e) - => EventManager.Instance.Dispatch>(sender, e); - - private void OnMultiDownloadError(object sender, MultiDownloadErrorEventArgs e) - => EventManager.Instance.Dispatch>(sender, e); - - private void OnMultiAllDownloadCompleted(object sender, MultiAllDownloadCompletedEventArgs e) - { - try - { - EventManager.Instance.Dispatch>(sender, e); - ExecuteStrategy(); - } - catch (Exception ex) - { - EventManager.Instance.Dispatch>(this, new ExceptionEventArgs(ex)); - } - } - - #endregion Callback event. - - #endregion Methods - } -} \ No newline at end of file diff --git a/src/c#/GeneralUpdate.Core/Bootstrap/UpdateEventArgs.cs b/src/c#/GeneralUpdate.Core/Bootstrap/UpdateEventArgs.cs deleted file mode 100644 index 13c09a3b..00000000 --- a/src/c#/GeneralUpdate.Core/Bootstrap/UpdateEventArgs.cs +++ /dev/null @@ -1,112 +0,0 @@ -using GeneralUpdate.Core.Domain.Enum; -using System; -using System.Collections.Generic; -using System.ComponentModel; - -namespace GeneralUpdate.Core.Bootstrap -{ - public class DownloadProgressChangedEventArgsEx : EventArgs - { - public long BytesReceived { get; private set; } - - public long TotalBytesToReceive { get; private set; } - - public float ProgressPercentage { get; private set; } - - public object UserState { get; set; } - - public DownloadProgressChangedEventArgsEx(long received, long toReceive, float progressPercentage, object userState) - { - BytesReceived = received; - TotalBytesToReceive = toReceive; - ProgressPercentage = progressPercentage; - UserState = userState; - } - } - - public class ExceptionEventArgs : EventArgs - { - public Exception Exception { get; set; } - - public ExceptionEventArgs(Exception exception) - { - Exception = exception; - } - } - - #region Muti - - public class MutiDownloadStatisticsEventArgs : EventArgs - { - public MutiDownloadStatisticsEventArgs(object version,DateTime remaining,string speed) - { - Version = version; - Remaining = remaining; - Speed = speed; - } - - public object Version { get; set; } - - public DateTime Remaining { get; set; } - - public string Speed { get; set; } - } - - public class MutiDownloadProgressChangedEventArgs : DownloadProgressChangedEventArgsEx - { - public ProgressType Type { get; set; } - - public object Version { get; set; } - - public string Message { get; set; } - - public double ProgressValue { get; set; } - - public MutiDownloadProgressChangedEventArgs(object version, ProgressType type, string message, long received = 0, long toReceive = 0, float progressPercentage = 0, object userState = null) - : base(received, toReceive, progressPercentage, userState) - { - ProgressValue = progressPercentage; - Version = version; - Message = message; - Type = type; - } - } - - public class MutiDownloadCompletedEventArgs : AsyncCompletedEventArgs - { - public object Version { get; set; } - - public MutiDownloadCompletedEventArgs(object version, Exception error, bool cancelled, object userState) : base(error, cancelled, userState) - { - Version = version; - } - } - - public class MutiAllDownloadCompletedEventArgs : EventArgs - { - public bool IsAllDownloadCompleted { get; set; } - - public IList> FailedVersions { get; set; } - - public MutiAllDownloadCompletedEventArgs(bool isAllDownloadCompleted, IList> failedVersions) - { - IsAllDownloadCompleted = isAllDownloadCompleted; - FailedVersions = failedVersions; - } - } - - public class MutiDownloadErrorEventArgs : EventArgs - { - public Exception Exception { get; set; } - - public object Version { get; set; } - - public MutiDownloadErrorEventArgs(Exception exception, object updateVersion) - { - Exception = exception; - Version = updateVersion; - } - } - - #endregion Muti -} \ No newline at end of file diff --git a/src/c#/GeneralUpdate.Core/Bootstrap/UpdateOption.cs b/src/c#/GeneralUpdate.Core/Bootstrap/UpdateOption.cs deleted file mode 100644 index 46e3c09a..00000000 --- a/src/c#/GeneralUpdate.Core/Bootstrap/UpdateOption.cs +++ /dev/null @@ -1,233 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Diagnostics.Contracts; -using System.Text; -using System.Threading; - -namespace GeneralUpdate.Core.Bootstrap -{ - public abstract class UpdateOption : AbstractConstant - { - private class UpdateOptionPool : ConstantPool - { - protected override IConstant NewConstant(int id, string name) => new UpdateOption(id, name); - } - - private static readonly UpdateOptionPool Pool = new UpdateOptionPool(); - - public static UpdateOption ValueOf(string name) => (UpdateOption)Pool.ValueOf(name); - - #region parameter configuration - - /// - /// Update the file format of the package. - /// - public static readonly UpdateOption Format = ValueOf("COMPRESSFORMAT"); - - /// - /// Compress encoding. - /// - public static readonly UpdateOption Encoding = ValueOf("COMPRESSENCODING"); - - /// - /// Main program name. - /// - public static readonly UpdateOption MainApp = ValueOf("MAINAPP"); - - /// - /// Timeout period (unit: second). If this parameter is not specified, the default timeout period is 30 seconds. - /// - public static readonly UpdateOption DownloadTimeOut = ValueOf("DOWNLOADTIMEOUT"); - - /// - /// Whether to enable the driver upgrade function. - /// - public static readonly UpdateOption Drive = ValueOf("DRIVE"); - - /// - /// Whether open note function, if you want to start needs to be synchronized to deploy 'GeneralUpdate. SystemService' service. - /// - public static readonly UpdateOption WillMessage = ValueOf("WILLMESSAGE"); - - #endregion parameter configuration - - internal UpdateOption(int id, string name) - : base(id, name) { } - - public abstract bool Set(IUpdateConfiguration configuration, object value); - } - - public sealed class UpdateOption : UpdateOption - { - internal UpdateOption(int id, string name) - : base(id, name) - { - } - - public void Validate(T value) => Contract.Requires(value != null); - - public override bool Set(IUpdateConfiguration configuration, object value) => configuration.SetOption(this, (T)value); - } - - public abstract class ConstantPool - { - private readonly Dictionary constants = new Dictionary(); - private int nextId = 1; - - /// Shortcut of this.ValueOf(firstNameComponent.Name + "#" + secondNameComponent). - public IConstant ValueOf(Type firstNameComponent, string secondNameComponent) - { - Contract.Requires(firstNameComponent != null); - Contract.Requires(secondNameComponent != null); - return this.ValueOf(firstNameComponent.Name + '#' + secondNameComponent); - } - - /// - /// Returns the which is assigned to the specified name. - /// If there's no such , a new one will be created and returned. - /// Once created, the subsequent calls with the same name will always return the previously created one - /// (i.e. singleton.) - /// - /// the name of the - public IConstant ValueOf(string name) - { - IConstant constant; - lock (this.constants) - { - if (this.constants.TryGetValue(name, out constant)) - { - return constant; - } - else - { - constant = this.NewInstance0(name); - } - } - return constant; - } - - /// Returns true if a exists for the given name. - public bool Exists(string name) - { - CheckNotNullAndNotEmpty(name); - lock (this.constants) - return this.constants.ContainsKey(name); - } - - /// - /// Creates a new for the given name or fail with an - /// if a for the given name exists. - /// - public IConstant NewInstance(string name) - { - if (this.Exists(name)) throw new ArgumentException($"'{name}' is already in use"); - IConstant constant = this.NewInstance0(name); - return constant; - } - - // Be careful that this dose not check whether the argument is null or empty. - private IConstant NewInstance0(string name) - { - lock (this.constants) - { - IConstant constant = this.NewConstant(this.nextId, name); - this.constants[name] = constant; - this.nextId++; - return constant; - } - } - - private static void CheckNotNullAndNotEmpty(string name) => Contract.Requires(!string.IsNullOrEmpty(name)); - - protected abstract IConstant NewConstant(int id, string name); - - [Obsolete] - public int NextId() - { - lock (this.constants) - { - int id = this.nextId; - this.nextId++; - return id; - } - } - } - - public interface IConstant - { - /// Returns the unique number assigned to this . - int Id { get; } - - /// Returns the name of this . - string Name { get; } - } - - public interface IUpdateConfiguration - { - T GetOption(UpdateOption option); - - bool SetOption(UpdateOption option, object value); - - bool SetOption(UpdateOption option, T value); - } - - public abstract class AbstractConstant : IConstant - { - private static long nextUniquifier; - private long volatileUniquifier; - - protected AbstractConstant(int id, string name) - { - this.Id = id; - this.Name = name; - } - - public int Id { get; } - - public string Name { get; } - - public override sealed string ToString() => this.Name; - - protected long Uniquifier - { - get - { - long result; - if ((result = Volatile.Read(ref this.volatileUniquifier)) == 0) - { - result = Interlocked.Increment(ref nextUniquifier); - long previousUniquifier = Interlocked.CompareExchange(ref this.volatileUniquifier, result, 0); - if (previousUniquifier != 0) result = previousUniquifier; - } - return result; - } - } - } - - public abstract class AbstractConstant : AbstractConstant, IComparable, IEquatable - where T : AbstractConstant - { - /// Creates a new instance. - protected AbstractConstant(int id, string name) - : base(id, name) { } - - public override sealed int GetHashCode() => base.GetHashCode(); - - public override sealed bool Equals(object obj) => base.Equals(obj); - - public bool Equals(T other) => ReferenceEquals(this, other); - - public int CompareTo(T o) - { - if (ReferenceEquals(this, o)) return 0; - AbstractConstant other = o; - int returnCode = this.GetHashCode() - other.GetHashCode(); - if (returnCode != 0) return returnCode; - long thisUV = this.Uniquifier; - long otherUV = other.Uniquifier; - if (thisUV < otherUV) return -1; - if (thisUV > otherUV) return 1; - throw new Exception("failed to compare two different constants"); - } - } -} \ No newline at end of file diff --git a/src/c#/GeneralUpdate.Core/Bootstrap/UpdateOptionValue.cs b/src/c#/GeneralUpdate.Core/Bootstrap/UpdateOptionValue.cs deleted file mode 100644 index e5d50689..00000000 --- a/src/c#/GeneralUpdate.Core/Bootstrap/UpdateOptionValue.cs +++ /dev/null @@ -1,29 +0,0 @@ -namespace GeneralUpdate.Core.Bootstrap -{ - public abstract class UpdateOptionValue - { - public abstract UpdateOption Option { get; } - - public abstract bool Set(IUpdateConfiguration config); - - public abstract object GetValue(); - } - - public sealed class UpdateOptionValue : UpdateOptionValue - { - public override UpdateOption Option { get; } - private readonly T value; - - public UpdateOptionValue(UpdateOption option, T value) - { - this.Option = option; - this.value = value; - } - - public override object GetValue() => this.value; - - public override bool Set(IUpdateConfiguration config) => config.SetOption(this.Option, this.value); - - public override string ToString() => this.value.ToString(); - } -} \ No newline at end of file diff --git a/src/c#/GeneralUpdate.Core/ContentProvider/FileNode.cs b/src/c#/GeneralUpdate.Core/ContentProvider/FileNode.cs deleted file mode 100644 index b74a0594..00000000 --- a/src/c#/GeneralUpdate.Core/ContentProvider/FileNode.cs +++ /dev/null @@ -1,148 +0,0 @@ -using System; - -namespace GeneralUpdate.Core.ContentProvider -{ - public class FileNode - { - #region Public Properties - - public long Id { get; set; } - - public string Name { get; set; } - - public string FullName { get; set; } - - public string Path { get; set; } - - public string Hash { get; set; } - - public FileNode Left { get; set; } - - public FileNode Right { get; set; } - - public int LeftType { get; set; } - - public int RightType { get; set; } - - public string RelativePath { get; set; } - - #endregion Public Properties - - #region Constructors - - public FileNode() - { } - - public FileNode(int id) - { - Id = id; - } - - #endregion Constructors - - #region Public Methods - - public void Add(FileNode node) - { - if (node == null) return; - - if (node.Id < Id) - { - if (Left == null) - { - Left = node; - } - else - { - Left.Add(node); - } - } - else - { - if (Right == null) - { - Right = node; - } - else - { - Right.Add(node); - } - } - } - - public void InfixOrder() - { - if (Left != null) - { - Left.InfixOrder(); - } - if (Right != null) - { - Right.InfixOrder(); - } - } - - public FileNode Search(long id) - { - if (id == Id) - { - return this; - } - else if (id < Id) - { - if (Left == null) return null; - return Left.Search(id); - } - else - { - if (Right == null) return null; - return Right.Search(id); - } - } - - /// - /// Find the parent node of the node that you want to delete. - /// - /// - /// - public FileNode SearchParent(long id) - { - if (Left != null && Left.Id == id || Right != null && Right.Id == id) - { - return this; - } - else - { - if (id < Id && Left != null) - { - return Left.SearchParent(id); - } - else if (id >= Id && Right != null) - { - return Right.SearchParent(id); - } - else - { - return null; - } - } - } - - /// - /// Compare tree nodes equally by Hash and file names. - /// - /// - /// - public override bool Equals(object obj) - { - if (obj == null) return false; - var tempNode = obj as FileNode; - if (tempNode == null) throw new ArgumentException(nameof(tempNode)); - return string.Equals(Hash, tempNode.Hash, StringComparison.OrdinalIgnoreCase) && string.Equals(Name, tempNode.Name, StringComparison.OrdinalIgnoreCase); - } - - public override int GetHashCode() => base.GetHashCode(); - - #endregion Public Methods - } -} \ No newline at end of file diff --git a/src/c#/GeneralUpdate.Core/ContentProvider/FileProvider-Comparer.cs b/src/c#/GeneralUpdate.Core/ContentProvider/FileProvider-Comparer.cs deleted file mode 100644 index be5f91e7..00000000 --- a/src/c#/GeneralUpdate.Core/ContentProvider/FileProvider-Comparer.cs +++ /dev/null @@ -1,67 +0,0 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; - -namespace GeneralUpdate.Core.ContentProvider -{ - public partial class FileProvider - { - private string _directoryA; - private string _directoryB; - - public List Comparer(string directoryA, string directoryB) - { - _directoryA = directoryA.TrimEnd(Path.DirectorySeparatorChar) + Path.DirectorySeparatorChar; - _directoryB = directoryB.TrimEnd(Path.DirectorySeparatorChar) + Path.DirectorySeparatorChar; - var filesInDirectoryA = new HashSet(GetAllFiles(_directoryA).Select(file => file.Substring(_directoryA.Length)), StringComparer.InvariantCultureIgnoreCase); - var missingFilesPath = GetAllFiles(_directoryB).Where(fileB => !filesInDirectoryA.Contains(fileB.Substring(_directoryB.Length))).ToList(); - var missingFiles = missingFilesPath.Select(path => new FileInfo(path)).ToList(); - return missingFiles; - } - - private IEnumerable GetAllFiles(string directoryPath) - { - var directories = new Stack(); - directories.Push(directoryPath); - - while (directories.Count > 0) - { - var currentDirectory = directories.Pop(); - - if (Directory.EnumerateFiles(currentDirectory, "*.inf").Any()) - continue; - - IEnumerable currentFiles; - try - { - currentFiles = Directory.EnumerateFiles(currentDirectory); - } - catch - { - continue; - } - - foreach (var file in currentFiles) - { - yield return file; - } - - IEnumerable subDirectories; - try - { - subDirectories = Directory.EnumerateDirectories(currentDirectory); - } - catch - { - continue; - } - - foreach (var subDirectory in subDirectories) - { - directories.Push(subDirectory); - } - } - } - } -} \ No newline at end of file diff --git a/src/c#/GeneralUpdate.Core/ContentProvider/FileProvider-Filter.cs b/src/c#/GeneralUpdate.Core/ContentProvider/FileProvider-Filter.cs deleted file mode 100644 index 6fe01323..00000000 --- a/src/c#/GeneralUpdate.Core/ContentProvider/FileProvider-Filter.cs +++ /dev/null @@ -1,45 +0,0 @@ -using System.Collections.Generic; - -namespace GeneralUpdate.Core.ContentProvider -{ - public partial class FileProvider - { - private static List _blackFiles, - _blackFileFormats; - private static readonly List DefaultBlackFileFormats = new List(6) - { - ".patch", - ".7z", - ".zip", - ".rar", - ".tar", - ".json" - }; - private static readonly List DefaultBlackFiles = new List(1) { "Newtonsoft.Json.dll" }; - - /// - /// Set a blacklist. - /// - /// A collection of blacklist files that are skipped when updated. - /// A collection of blacklist file name extensions that are skipped on update. - public static void SetBlacklist(List blackFiles, List blackFileFormats) - { - _blackFiles = blackFiles; - _blackFileFormats = blackFileFormats; - } - - /// - /// These files will be skipped when updating. - /// - /// - public static List GetBlackFiles() => - _blackFiles ?? DefaultBlackFiles; - - /// - /// These files that contain the file suffix will be skipped when updating. - /// - /// - public static List GetBlackFileFormats() => - _blackFileFormats ?? DefaultBlackFileFormats; - } -} diff --git a/src/c#/GeneralUpdate.Core/ContentProvider/FileProvider-Manage.cs b/src/c#/GeneralUpdate.Core/ContentProvider/FileProvider-Manage.cs deleted file mode 100644 index 97580db8..00000000 --- a/src/c#/GeneralUpdate.Core/ContentProvider/FileProvider-Manage.cs +++ /dev/null @@ -1,49 +0,0 @@ -using System; -using System.Collections.Generic; -using System.IO; - -namespace GeneralUpdate.Core.ContentProvider -{ - public partial class FileProvider - { - public static string GetTempDirectory(string name) - { - var path = $"generalupdate_{DateTime.Now.ToString("yyyy-MM-dd")}_{name}"; - var tempDir = Path.Combine(Path.GetTempPath(), path); - if (!Directory.Exists(tempDir)) - { - Directory.CreateDirectory(tempDir); - } - return tempDir; - } - - public static List GetAllfiles(string path) - { - try - { - var files = new List(); - files.AddRange(new DirectoryInfo(path).GetFiles()); - var tmpDir = new DirectoryInfo(path).GetDirectories(); - foreach (var dic in tmpDir) - { - files.AddRange(GetAllfiles(dic.FullName)); - } - return files; - } - catch (Exception) - { - return null; - } - } - - /// - /// Delete the backup file directory and recursively delete all backup content. - /// - public static void DeleteDir(string path) - { - if (string.IsNullOrWhiteSpace(path)) return; - if (Directory.Exists(path)) - Directory.Delete(path, true); - } - } -} \ No newline at end of file diff --git a/src/c#/GeneralUpdate.Core/ContentProvider/FileProvider-Serialization.cs b/src/c#/GeneralUpdate.Core/ContentProvider/FileProvider-Serialization.cs deleted file mode 100644 index 9dd15143..00000000 --- a/src/c#/GeneralUpdate.Core/ContentProvider/FileProvider-Serialization.cs +++ /dev/null @@ -1,63 +0,0 @@ -using Newtonsoft.Json; -using System; -using System.IO; -using System.Text; - -namespace GeneralUpdate.Core.ContentProvider -{ - public partial class FileProvider - { - public static void CreateJson(string targetPath, T obj) - { - var folderPath = Path.GetDirectoryName(targetPath) ?? - throw new ArgumentException("invalid path", nameof(targetPath)); - if (!Directory.Exists(folderPath)) - { - Directory.CreateDirectory(folderPath); - } - - var jsonString = JsonConvert.SerializeObject(obj); - File.WriteAllText(targetPath, jsonString); - } - - public static T GetJson(string path) - { - if (File.Exists(path)) - { - var json = File.ReadAllText(path); - return JsonConvert.DeserializeObject(json); - } - return default(T); - } - - /// - /// Convert object to base64 string. - /// - /// - /// - public static string Serialize(object obj) - { - if (obj == null) return string.Empty; - var json = JsonConvert.SerializeObject(obj); - var bytes = Encoding.Default.GetBytes(json); - var base64str = Convert.ToBase64String(bytes); - return base64str; - } - - /// - /// Convert base64 object to string. - /// - /// - /// - /// - public static T Deserialize(string str) - { - var obj = default(T); - if (string.IsNullOrEmpty(str)) return obj; - byte[] bytes = Convert.FromBase64String(str); - var json = Encoding.Default.GetString(bytes); - var result = JsonConvert.DeserializeObject(json); - return result; - } - } -} \ No newline at end of file diff --git a/src/c#/GeneralUpdate.Core/ContentProvider/FileProvider.cs b/src/c#/GeneralUpdate.Core/ContentProvider/FileProvider.cs deleted file mode 100644 index 5a89c1d1..00000000 --- a/src/c#/GeneralUpdate.Core/ContentProvider/FileProvider.cs +++ /dev/null @@ -1,115 +0,0 @@ -using GeneralUpdate.Core.HashAlgorithms; -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Threading; -using System.Threading.Tasks; - -namespace GeneralUpdate.Core.ContentProvider -{ - public partial class FileProvider - { - private long _fileCount = 0; - - #region Public Methods - - /// - /// Compare two binary trees with different children. - /// - /// Left tree folder path. - /// Right tree folder path. - /// ValueTuple(leftFileNodes,rightFileNodes, differentTreeNode) - public async Task, IEnumerable, IEnumerable>> Compare(string leftPath, string rightPath) - { - return await Task.Run(() => - { - ResetId(); - var leftFileNodes = Read(leftPath); - var rightFileNodes = Read(rightPath); - var leftTree = new FileTree(leftFileNodes); - var rightTree = new FileTree(rightFileNodes); - var differentTreeNode = new List(); - leftTree.Compare(leftTree.GetRoot(), rightTree.GetRoot(), ref differentTreeNode); - return ValueTuple.Create(leftFileNodes, rightFileNodes, differentTreeNode); - }); - } - - /// - /// Using the list on the left as a baseline, find the set of differences between the two file lists. - /// - /// Previous version file list path - /// The current version file list path - /// Except collection - public async Task> Except(string leftPath, string rightPath) - { - return await Task.Run(() => - { - var leftFileNodes = Read(leftPath); - var rightFileNodes = Read(rightPath); - var rightNodeDic = rightFileNodes.ToDictionary(x => x.RelativePath, x => x); - var filesOnlyInLeft = leftFileNodes.Where(f => !rightNodeDic.ContainsKey(f.RelativePath)).ToList(); - return filesOnlyInLeft; - }); - } - - #endregion Public Methods - - #region Private Methods - - /// - /// Recursively read all files in the folder path. - /// - /// folder path. - /// folder root path. - /// different chalders. - private IEnumerable Read(string path, string rootPath = null) - { - var resultFiles = new List(); - if (string.IsNullOrEmpty(rootPath)) rootPath = path; - if (!rootPath.EndsWith("/")) rootPath += "/"; - Uri rootUri = new Uri(rootPath); - foreach (var subPath in Directory.GetFiles(path)) - { - if (IsMatchBlacklist(subPath)) continue; - - var hashAlgorithm = new Sha256HashAlgorithm(); - var hash = hashAlgorithm.ComputeHash(subPath); - var subFileInfo = new FileInfo(subPath); - Uri subUri = new Uri(subFileInfo.FullName); - resultFiles.Add(new FileNode() { Id = GetId(), Path = path, Name = subFileInfo.Name, Hash = hash, FullName = subFileInfo.FullName, RelativePath = rootUri.MakeRelativeUri(subUri).ToString() }); - } - foreach (var subPath in Directory.GetDirectories(path)) - { - resultFiles.AddRange(Read(subPath, rootPath)); - } - return resultFiles; - } - - /// - /// Self-growing file tree node ID. - /// - /// - private long GetId() => Interlocked.Increment(ref _fileCount); - - private void ResetId() => Interlocked.Exchange(ref _fileCount, 0); - - /// - /// Whether the file name in the file path can match the blacklisted file. - /// - /// - /// - private bool IsMatchBlacklist(string subPath) - { - var blackList = GetBlackFiles(); - if (blackList == null) return false; - foreach (var file in blackList) - { - if (subPath.Contains(file)) return true; - } - return false; - } - - #endregion Private Methods - } -} \ No newline at end of file diff --git a/src/c#/GeneralUpdate.Core/CustomAwaiter/IAwaitable.cs b/src/c#/GeneralUpdate.Core/CustomAwaiter/IAwaitable.cs deleted file mode 100644 index 0c854044..00000000 --- a/src/c#/GeneralUpdate.Core/CustomAwaiter/IAwaitable.cs +++ /dev/null @@ -1,12 +0,0 @@ -namespace GeneralUpdate.Core.CustomAwaiter -{ - public interface IAwaitable where TAwaiter : IAwaiter - { - TAwaiter GetAwaiter(); - } - - public interface IAwaitable where TAwaiter : IAwaiter - { - TAwaiter GetAwaiter(); - } -} \ No newline at end of file diff --git a/src/c#/GeneralUpdate.Core/CustomAwaiter/IAwaiter.cs b/src/c#/GeneralUpdate.Core/CustomAwaiter/IAwaiter.cs deleted file mode 100644 index 42255ef0..00000000 --- a/src/c#/GeneralUpdate.Core/CustomAwaiter/IAwaiter.cs +++ /dev/null @@ -1,18 +0,0 @@ -using System.Runtime.CompilerServices; - -namespace GeneralUpdate.Core.CustomAwaiter -{ - public interface IAwaiter : INotifyCompletion - { - bool IsCompleted { get; } - - void GetResult(); - } - - public interface IAwaiter : INotifyCompletion - { - bool IsCompleted { get; } - - TResult GetResult(); - } -} \ No newline at end of file diff --git a/src/c#/GeneralUpdate.Core/CustomAwaiter/ICriticalAwaiter.cs b/src/c#/GeneralUpdate.Core/CustomAwaiter/ICriticalAwaiter.cs deleted file mode 100644 index f4876ca4..00000000 --- a/src/c#/GeneralUpdate.Core/CustomAwaiter/ICriticalAwaiter.cs +++ /dev/null @@ -1,12 +0,0 @@ -using System.Runtime.CompilerServices; - -namespace GeneralUpdate.Core.CustomAwaiter -{ - public interface ICriticalAwaiter : IAwaiter, ICriticalNotifyCompletion - { - } - - public interface ICriticalAwaiter : IAwaiter, ICriticalNotifyCompletion - { - } -} \ No newline at end of file diff --git a/src/c#/GeneralUpdate.Core/Domain/DO/Assembler/VersionAssembler.cs b/src/c#/GeneralUpdate.Core/Domain/DO/Assembler/VersionAssembler.cs deleted file mode 100644 index 867c325f..00000000 --- a/src/c#/GeneralUpdate.Core/Domain/DO/Assembler/VersionAssembler.cs +++ /dev/null @@ -1,23 +0,0 @@ -using GeneralUpdate.Core.Domain.Entity; -using System.Collections.Generic; - -namespace GeneralUpdate.Core.Domain.DO.Assembler -{ - public class VersionAssembler - { - public static List ToDataObjects(List versionDTO) - { - List entitys = new List(); - versionDTO.ForEach((v) => - { - entitys.Add(ToDataObject(v)); - }); - return entitys; - } - - public static VersionInfo ToDataObject(VersionConfigDO versionDO) - { - return new VersionInfo(versionDO.PubTime, versionDO.Name, versionDO.Hash, versionDO.Version, versionDO.Url); - } - } -} \ No newline at end of file diff --git a/src/c#/GeneralUpdate.Core/Domain/DO/VersionConfigDO.cs b/src/c#/GeneralUpdate.Core/Domain/DO/VersionConfigDO.cs deleted file mode 100644 index a9829bd6..00000000 --- a/src/c#/GeneralUpdate.Core/Domain/DO/VersionConfigDO.cs +++ /dev/null @@ -1,64 +0,0 @@ -using System; - -namespace GeneralUpdate.Core.Domain.DO -{ - public class VersionConfigDO - { - /// - /// Product branch ID (Used to distinguish multiple branches under the same product). - /// - public string Guid { get; set; } - - /// - /// Update package download location. - /// - public string Url { get; set; } - - /// - /// Hash verification code - /// - public string Hash { get; set; } - - /// - /// Update the package name. - /// - public string Name { get; set; } - - /// - /// Update the package file format. - /// - public string Format { get; set; } - - /// - /// The version number that will be updated. - /// - public string Version { get; set; } - - /// - /// Update package release time. - /// - public long PubTime { get; set; } - - /// - /// Init version config infomation. - /// - /// - /// - /// - /// - /// - /// - /// - /// - public VersionConfigDO(string guid, string url, string hash, string name, string format, string version, long pubTime) - { - Guid = guid ?? throw new ArgumentNullException(nameof(guid)); - Url = url ?? throw new ArgumentNullException(nameof(url)); - Hash = hash ?? throw new ArgumentNullException(nameof(hash)); - Name = name ?? throw new ArgumentNullException(nameof(name)); - Format = format ?? throw new ArgumentNullException(nameof(format)); - Version = version ?? throw new ArgumentNullException(nameof(version)); - PubTime = pubTime; - } - } -} \ No newline at end of file diff --git a/src/c#/GeneralUpdate.Core/Domain/DTO/Assembler/VersionAssembler.cs b/src/c#/GeneralUpdate.Core/Domain/DTO/Assembler/VersionAssembler.cs deleted file mode 100644 index ac850e2b..00000000 --- a/src/c#/GeneralUpdate.Core/Domain/DTO/Assembler/VersionAssembler.cs +++ /dev/null @@ -1,23 +0,0 @@ -using GeneralUpdate.Core.Domain.Entity; -using System.Collections.Generic; - -namespace GeneralUpdate.Core.Domain.DTO.Assembler -{ - public class VersionAssembler - { - public static List ToEntitys(List versionDTO) - { - List entitys = new List(); - versionDTO.ForEach((v) => - { - entitys.Add(ToEntity(v)); - }); - return entitys; - } - - public static VersionInfo ToEntity(VersionDTO versionDTO) - { - return new VersionInfo(versionDTO.PubTime, versionDTO.Name, versionDTO.Hash, versionDTO.Version, versionDTO.Url); - } - } -} \ No newline at end of file diff --git a/src/c#/GeneralUpdate.Core/Domain/DTO/BaseResponseDTO.cs b/src/c#/GeneralUpdate.Core/Domain/DTO/BaseResponseDTO.cs deleted file mode 100644 index 3ebb1f93..00000000 --- a/src/c#/GeneralUpdate.Core/Domain/DTO/BaseResponseDTO.cs +++ /dev/null @@ -1,11 +0,0 @@ -namespace GeneralUpdate.Core.Domain.DTO -{ - public class BaseResponseDTO - { - public int Code { get; set; } - - public TBody Body { get; set; } - - public string Message { get; set; } - } -} \ No newline at end of file diff --git a/src/c#/GeneralUpdate.Core/Domain/DTO/UploadReapDTO.cs b/src/c#/GeneralUpdate.Core/Domain/DTO/UploadReapDTO.cs deleted file mode 100644 index c3c59264..00000000 --- a/src/c#/GeneralUpdate.Core/Domain/DTO/UploadReapDTO.cs +++ /dev/null @@ -1,8 +0,0 @@ -using GeneralUpdate.Core.Domain.DTO; - -namespace GeneralUpdate.AspNetCore.DTO -{ - public class UploadReapDTO : BaseResponseDTO - { - } -} \ No newline at end of file diff --git a/src/c#/GeneralUpdate.Core/Domain/DTO/VersionDTO.cs b/src/c#/GeneralUpdate.Core/Domain/DTO/VersionDTO.cs deleted file mode 100644 index 6f070e7b..00000000 --- a/src/c#/GeneralUpdate.Core/Domain/DTO/VersionDTO.cs +++ /dev/null @@ -1,24 +0,0 @@ -namespace GeneralUpdate.Core.Domain.DTO -{ - public class VersionDTO - { - public VersionDTO(string hash, long pubTime, string version, string url, string name) - { - Hash = hash; - PubTime = pubTime; - Version = version; - Url = url; - Name = name; - } - - public string Hash { get; set; } - - public long PubTime { get; set; } - - public string Version { get; set; } - - public string Url { get; set; } - - public string Name { get; set; } - } -} \ No newline at end of file diff --git a/src/c#/GeneralUpdate.Core/Domain/DTO/VersionRespDTO.cs b/src/c#/GeneralUpdate.Core/Domain/DTO/VersionRespDTO.cs deleted file mode 100644 index eda2a878..00000000 --- a/src/c#/GeneralUpdate.Core/Domain/DTO/VersionRespDTO.cs +++ /dev/null @@ -1,27 +0,0 @@ -using System.Collections.Generic; - -namespace GeneralUpdate.Core.Domain.DTO -{ - public class VersionRespDTO : BaseResponseDTO - { } - - public class VersionBodyDTO - { - public bool IsUpdate { get; set; } - - /// - /// Is forcibly update. - /// - public bool IsForcibly { get; set; } - - /// - /// 1:ClientApp 2:UpdateApp - /// - public int ClientType { get; set; } - - /// - /// Returns information about all versions that are different from the latest version based on the current version of the client. - /// - public List Versions { get; set; } - } -} \ No newline at end of file diff --git a/src/c#/GeneralUpdate.Core/Domain/Entity/Assembler/ProcessAssembler.cs b/src/c#/GeneralUpdate.Core/Domain/Entity/Assembler/ProcessAssembler.cs deleted file mode 100644 index 88eb236c..00000000 --- a/src/c#/GeneralUpdate.Core/Domain/Entity/Assembler/ProcessAssembler.cs +++ /dev/null @@ -1,74 +0,0 @@ -using GeneralUpdate.Core.ContentProvider; -using System; -using System.Text; - -namespace GeneralUpdate.Core.Domain.Entity.Assembler -{ - public class ProcessAssembler - { - public static string ToBase64(ProcessInfo info) - { - if (info == null) throw new ArgumentNullException(nameof(info)); - return FileProvider.Serialize(info); - } - - public static string ToBase64(ParamsOSS info) - { - if (info == null) throw new ArgumentNullException(nameof(info)); - return FileProvider.Serialize(info); - } - - public static Packet ToPacket(ProcessInfo info) - { - var packet = new Packet(); - packet.AppName = info.AppName; - packet.AppSecretKey = info.AppSecretKey; - packet.AppType = info.AppType; - packet.InstallPath = info.InstallPath; - packet.ClientVersion = info.CurrentVersion; - packet.LastVersion = info.LastVersion; - packet.UpdateLogUrl = info.LogUrl; - packet.Encoding = ToEncoding(info.CompressEncoding); - packet.Format = info.CompressFormat; - packet.DownloadTimeOut = info.DownloadTimeOut; - packet.UpdateVersions = info.UpdateVersions; - return packet; - } - - private static Encoding ToEncoding(int type) - { - Encoding encoding = Encoding.Default; - switch (type) - { - case 1: - encoding = Encoding.UTF8; - break; - - case 2: - encoding = Encoding.UTF7; - break; - - case 3: - encoding = Encoding.UTF32; - break; - - case 4: - encoding = Encoding.Unicode; - break; - - case 5: - encoding = Encoding.BigEndianUnicode; - break; - - case 6: - encoding = Encoding.ASCII; - break; - - case 7: - encoding = Encoding.Default; - break; - } - return encoding; - } - } -} \ No newline at end of file diff --git a/src/c#/GeneralUpdate.Core/Domain/Entity/Configinfo.cs b/src/c#/GeneralUpdate.Core/Domain/Entity/Configinfo.cs deleted file mode 100644 index 4e4560e7..00000000 --- a/src/c#/GeneralUpdate.Core/Domain/Entity/Configinfo.cs +++ /dev/null @@ -1,66 +0,0 @@ -using System; -using System.IO; - -namespace GeneralUpdate.Core.Domain.Entity -{ - public class Configinfo : Entity - { - public Configinfo() - { } - - public Configinfo(int appType, string appName, string appSecretKey, string clientVersion, string updateUrl, string updateLogUrl, string installPath, string mainUpdateUrl, string mainAppName) - { - AppType = appType; - AppName = appName ?? throw new ArgumentNullException(nameof(appName)); - AppSecretKey = appSecretKey ?? throw new ArgumentNullException(nameof(appSecretKey)); - ClientVersion = clientVersion ?? throw new ArgumentNullException(nameof(clientVersion)); - UpdateUrl = updateUrl ?? throw new ArgumentNullException(nameof(updateUrl)); - UpdateLogUrl = updateLogUrl ?? throw new ArgumentNullException(nameof(updateLogUrl)); - InstallPath = installPath ?? Directory.GetCurrentDirectory(); - MainUpdateUrl = mainUpdateUrl ?? throw new ArgumentNullException(nameof(mainUpdateUrl)); - MainAppName = mainAppName ?? throw new ArgumentNullException(nameof(mainAppName)); - } - - /// - /// 1:ClientApp 2:UpdateApp - /// - public int AppType { get; set; } - - /// - /// Need to start the name of the app. - /// - public string AppName { get; set; } - - /// - /// application key - /// - public string AppSecretKey { get; set; } - - /// - /// Client current version. - /// - public string ClientVersion { get; set; } - - /// - /// Update check api address. - /// - public string UpdateUrl { get; set; } - - /// - /// Update log web address. - /// - public string UpdateLogUrl { get; set; } - - /// - /// installation path (for update file logic). - /// - public string InstallPath { get; set; } - - /// - /// Update check api address. - /// - public string MainUpdateUrl { get; set; } - - public string MainAppName { get; set; } - } -} \ No newline at end of file diff --git a/src/c#/GeneralUpdate.Core/Domain/Entity/Entity.cs b/src/c#/GeneralUpdate.Core/Domain/Entity/Entity.cs deleted file mode 100644 index a33975ed..00000000 --- a/src/c#/GeneralUpdate.Core/Domain/Entity/Entity.cs +++ /dev/null @@ -1,31 +0,0 @@ -using System; -using System.Text.RegularExpressions; - -namespace GeneralUpdate.Core.Domain.Entity -{ - public class Entity - { - /// - /// 委派标识 - /// - protected string Identity { get; set; } - - public string ID - { - get { return this.Identity; } - protected set { this.Identity = value; } - } - - protected bool IsURL(string url) - { - string check = @"((http|ftp|https)://)(([a-zA-Z0-9\._-]+\.[a-zA-Z]{2,6})|([0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}))(:[0-9]{1,4})*(/[a-zA-Z0-9\&%_\./-~-]*)?"; - var regex = new Regex(check); - return regex.IsMatch(url); - } - - protected bool IsVersion(string version) - { - return Version.TryParse(version, out var ver); - } - } -} \ No newline at end of file diff --git a/src/c#/GeneralUpdate.Core/Domain/Entity/Packet.cs b/src/c#/GeneralUpdate.Core/Domain/Entity/Packet.cs deleted file mode 100644 index 8b5e76a1..00000000 --- a/src/c#/GeneralUpdate.Core/Domain/Entity/Packet.cs +++ /dev/null @@ -1,145 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Text; - -namespace GeneralUpdate.Core.Domain.Entity -{ - public class Packet : Entity - { - public Packet() - { } - - public Packet(string mainUpdateUrl, int appType, string updateUrl, string appName, string mainAppName, string format, bool isUpdate, string updateLogUrl, Encoding encoding, int downloadTimeOut, string appSecretKey, string tempPath) - { - if (!IsURL(mainUpdateUrl)) throw new Exception($"Illegal url {nameof(mainUpdateUrl)}"); - MainUpdateUrl = mainUpdateUrl ?? throw new ArgumentNullException(nameof(MainUpdateUrl)); - if (!IsURL(updateUrl)) throw new Exception($"Illegal url {nameof(UpdateUrl)}"); - UpdateUrl = updateUrl ?? throw new ArgumentNullException(nameof(updateUrl)); - UpdateLogUrl = updateLogUrl ?? throw new ArgumentNullException(nameof(updateLogUrl)); - AppType = appType; - AppName = appName ?? throw new ArgumentNullException(nameof(appName)); - MainAppName = mainAppName ?? throw new ArgumentNullException(nameof(mainAppName)); - Format = format ?? throw new ArgumentNullException(nameof(format)); - IsUpgradeUpdate = isUpdate; - Encoding = encoding ?? throw new ArgumentNullException(nameof(encoding)); - DownloadTimeOut = downloadTimeOut; - AppSecretKey = appSecretKey ?? throw new ArgumentNullException(nameof(appSecretKey)); - TempPath = tempPath ?? throw new ArgumentNullException(nameof(tempPath)); - } - - /// - /// Update check api address. - /// - public string MainUpdateUrl { get; set; } - - /// - /// 1:ClientApp 2:UpdateApp - /// - public int AppType { get; set; } - - /// - /// Update check api address. - /// - public string UpdateUrl { get; set; } - - /// - /// Need to start the name of the app. - /// - public string AppName { get; set; } - - /// - /// The name of the main application, without .exe. - /// - public string MainAppName { get; set; } - - /// - /// Update package file format(Defult format is Zip). - /// - public string Format { get; set; } - - /// - /// Whether an update is required to upgrade the application. - /// - public bool IsUpgradeUpdate { get; set; } - - /// - /// Whether the main application needs to be updated. - /// - public bool IsMainUpdate { get; set; } - - /// - /// Update log web address. - /// - public string UpdateLogUrl { get; set; } - - /// - /// Version information that needs to be updated. - /// - public List UpdateVersions { get; set; } - - /// - /// The encoding format for file operations. - /// - public Encoding Encoding { get; set; } - - /// - /// Time-out event for file download. - /// - public int DownloadTimeOut { get; set; } - - /// - /// application key - /// - public string AppSecretKey { get; set; } - - /// - /// Client current version. - /// - public string ClientVersion { get; set; } - - /// - /// The latest version. - /// - public string LastVersion { get; set; } - - /// - /// installation path (for update file logic). - /// - public string InstallPath { get; set; } - - /// - /// Download file temporary storage path (for update file logic). - /// - public string TempPath { get; set; } - - /// - /// Configuration parameters for upgrading the terminal program. - /// - public string ProcessBase64 { get; set; } - - /// - /// The platform to which the current strategy belongs. - /// - public string Platform { get; set; } - - /// - /// Files in the blacklist will skip the update. - /// - public List BlackFiles { get; set; } - - /// - /// File formats in the blacklist will skip the update. - /// - public List BlackFormats { get; set; } - - /// - /// Whether to enable the driver upgrade function. - /// - public bool DriveEnabled { get; set; } - - /// - /// Whether open note function, if you want to start needs to be synchronized to deploy 'GeneralUpdate. SystemService' service. - /// - public bool WillMessageEnabled { get; set; } - } -} \ No newline at end of file diff --git a/src/c#/GeneralUpdate.Core/Domain/Entity/ParamsOSS.cs b/src/c#/GeneralUpdate.Core/Domain/Entity/ParamsOSS.cs deleted file mode 100644 index 8283cd8a..00000000 --- a/src/c#/GeneralUpdate.Core/Domain/Entity/ParamsOSS.cs +++ /dev/null @@ -1,23 +0,0 @@ -using System; - -namespace GeneralUpdate.Core.Domain.Entity -{ - public class ParamsOSS : Entity - { - public string Url { get; set; } - - public string AppName { get; set; } - - public string CurrentVersion { get; set; } - - public string VersionFileName { get; set; } - - public ParamsOSS(string url, string appName, string currentVersion, string versionFileName) - { - Url = url ?? throw new ArgumentNullException(nameof(url)); - AppName = appName ?? throw new ArgumentNullException(nameof(appName)); - CurrentVersion = currentVersion ?? throw new ArgumentNullException(nameof(currentVersion)); - VersionFileName = versionFileName ?? "versions.json"; - } - } -} \ No newline at end of file diff --git a/src/c#/GeneralUpdate.Core/Domain/Entity/ProcessInfo.cs b/src/c#/GeneralUpdate.Core/Domain/Entity/ProcessInfo.cs deleted file mode 100644 index 4082dd9f..00000000 --- a/src/c#/GeneralUpdate.Core/Domain/Entity/ProcessInfo.cs +++ /dev/null @@ -1,107 +0,0 @@ -using GeneralUpdate.Core.Domain.DTO; -using GeneralUpdate.Core.Domain.DTO.Assembler; -using System; -using System.Collections.Generic; -using System.IO; -using System.Text; - -namespace GeneralUpdate.Core.Domain.Entity -{ - public class ProcessInfo : Entity - { - public ProcessInfo() - { } - - public ProcessInfo(string appName, string installPath, string currentVersion, string lastVersion, string logUrl, Encoding compressEncoding, string compressFormat, int downloadTimeOut, string appSecretKey, List updateVersions) - { - AppName = appName ?? throw new ArgumentNullException(nameof(appName)); - if (!Directory.Exists(installPath)) throw new ArgumentException($"{nameof(installPath)} path does not exist ! {installPath}."); - InstallPath = installPath ?? throw new ArgumentNullException(nameof(installPath)); - CurrentVersion = currentVersion ?? throw new ArgumentNullException(nameof(currentVersion)); - LastVersion = lastVersion ?? throw new ArgumentNullException(nameof(lastVersion)); - LogUrl = logUrl; - compressEncoding = compressEncoding ?? Encoding.Default; - CompressEncoding = ToEncodingType(compressEncoding); - CompressFormat = compressFormat; - if (downloadTimeOut < 0) throw new ArgumentException("Timeout must be greater than 0 !"); - DownloadTimeOut = downloadTimeOut; - AppSecretKey = appSecretKey ?? throw new ArgumentNullException(nameof(appSecretKey)); - if (updateVersions == null || updateVersions.Count == 0) throw new ArgumentException("Collection cannot be null or has 0 elements !"); - UpdateVersions = VersionAssembler.ToEntitys(updateVersions); - } - - private int ToEncodingType(Encoding encoding) - { - int type = -1; - if (encoding == Encoding.UTF8) - { - type = 1; - } - else if (encoding == Encoding.UTF7) - { - type = 2; - } - else if (encoding == Encoding.UTF32) - { - type = 3; - } - else if (encoding == Encoding.Unicode) - { - type = 4; - } - else if (encoding == Encoding.BigEndianUnicode) - { - type = 5; - } - else if (encoding == Encoding.ASCII) - { - type = 6; - } - else if (encoding == Encoding.Default) - { - type = 7; - } - return type; - } - - /// - /// 1:MainApp 2:UpdateApp - /// - public int AppType { get; set; } - - /// - /// Need to start the name of the app. - /// - public string AppName { get; set; } - - /// - /// Installation directory (the path where the update package is decompressed). - /// - public string InstallPath { get; set; } - - public string CurrentVersion { get; set; } - - public string LastVersion { get; set; } - - /// - /// Update log web address. - /// - public string LogUrl { get; set; } - - public int CompressEncoding { get; set; } - - public string CompressFormat { get; set; } - - public int DownloadTimeOut { get; set; } - - /// - /// application key - /// - public string AppSecretKey { get; set; } - - /// - /// One or more version update information. - /// - public List UpdateVersions { get; set; } - } -} \ No newline at end of file diff --git a/src/c#/GeneralUpdate.Core/Domain/Entity/VersionInfo.cs b/src/c#/GeneralUpdate.Core/Domain/Entity/VersionInfo.cs deleted file mode 100644 index e1d611b7..00000000 --- a/src/c#/GeneralUpdate.Core/Domain/Entity/VersionInfo.cs +++ /dev/null @@ -1,50 +0,0 @@ -using System; - -namespace GeneralUpdate.Core.Domain.Entity -{ - public class VersionInfo : Entity - { - public VersionInfo() - { } - - public VersionInfo(long pubTime, string name, string hash, string version, string url) - { - PubTime = pubTime; - Name = name ?? throw new ArgumentNullException(nameof(name)); - Hash = hash ?? throw new ArgumentNullException(nameof(hash)); - Version = version ?? throw new ArgumentNullException(nameof(version)); - Url = url ?? throw new ArgumentNullException(nameof(Url)); - if (!IsURL(Url)) throw new Exception($"Illegal url {nameof(Url)}"); - } - - /// - /// Update package release time. - /// - public long PubTime { get; set; } - - /// - /// Update package name. - /// - public string Name { get; set; } - - /// - /// Compare and verify with the downloaded update package. - /// - public string Hash { get; set; } - - /// - /// The version number. - /// - public string Version { get; set; } - - /// - /// Remote service url address. - /// - public string Url { get; set; } - - public override string ToString() - { - return Version; - } - } -} \ No newline at end of file diff --git a/src/c#/GeneralUpdate.Core/Domain/Enum/AppType.cs b/src/c#/GeneralUpdate.Core/Domain/Enum/AppType.cs deleted file mode 100644 index b983ff24..00000000 --- a/src/c#/GeneralUpdate.Core/Domain/Enum/AppType.cs +++ /dev/null @@ -1,15 +0,0 @@ -namespace GeneralUpdate.Core.Domain.Enum -{ - public class AppType - { - /// - /// main program - /// - public const int ClientApp = 1; - - /// - /// upgrade program. - /// - public const int UpgradeApp = 2; - } -} \ No newline at end of file diff --git a/src/c#/GeneralUpdate.Core/Domain/Enum/Format.cs b/src/c#/GeneralUpdate.Core/Domain/Enum/Format.cs deleted file mode 100644 index 081e69fc..00000000 --- a/src/c#/GeneralUpdate.Core/Domain/Enum/Format.cs +++ /dev/null @@ -1,8 +0,0 @@ -namespace GeneralUpdate.Core.Domain.Enum -{ - public class Format - { - public const string ZIP = "zip"; - public const string SEVENZIP = "7z"; - } -} \ No newline at end of file diff --git a/src/c#/GeneralUpdate.Core/Domain/Enum/HttpStatus.cs b/src/c#/GeneralUpdate.Core/Domain/Enum/HttpStatus.cs deleted file mode 100644 index 3ee8cc30..00000000 --- a/src/c#/GeneralUpdate.Core/Domain/Enum/HttpStatus.cs +++ /dev/null @@ -1,12 +0,0 @@ -namespace GeneralUpdate.Core.Domain.Enum -{ - public class HttpStatus - { - public const int OK = 200; - public const int BAD_REQUEST = 400; - public const int FORBIDDEN = 403; - public const int NOT_FOUND = 404; - public const int REQUEST_TIMEOUT = 408; - public const int SERVICE_UNAVAILABLE = 500; - } -} \ No newline at end of file diff --git a/src/c#/GeneralUpdate.Core/Domain/Enum/PlatformType.cs b/src/c#/GeneralUpdate.Core/Domain/Enum/PlatformType.cs deleted file mode 100644 index fb1e8aee..00000000 --- a/src/c#/GeneralUpdate.Core/Domain/Enum/PlatformType.cs +++ /dev/null @@ -1,48 +0,0 @@ -namespace GeneralUpdate.Core.Domain.Enum -{ - /// - /// Adapt to the update process on different platforms. - /// - public class PlatformType - { - /// - /// Update on mac platform. - /// - public const string Mac = "MAC_PLATFORM"; - - /// - /// Update on windows platform. - /// - public const string Windows = "WIN_PLATFORM"; - - /// - /// Update on iOS platform. - /// - public const string iOS = "IOS_PLATFORM"; - - /// - /// Update on android platform. - /// - public const string Android = "ANDROID_PLATFORM"; - - /// - /// Update on linux platform. - /// - public const string Linux = "LINUX_PLATFORM"; - - /// - /// Update on IoT platform. - /// - //public const string IoT = "IOT_PLATFORM"; - - /// - /// Update on Tizen platform. - /// - //public const string Tizen = "TIZEN_PLATFORM"; - - /// - /// Update on Blazor platform. - /// - //public const string Blazor = "BLAZOR_PLATFORM"; - } -} \ No newline at end of file diff --git a/src/c#/GeneralUpdate.Core/Domain/Enum/ProgressType.cs b/src/c#/GeneralUpdate.Core/Domain/Enum/ProgressType.cs deleted file mode 100644 index 027268be..00000000 --- a/src/c#/GeneralUpdate.Core/Domain/Enum/ProgressType.cs +++ /dev/null @@ -1,45 +0,0 @@ -namespace GeneralUpdate.Core.Domain.Enum -{ - public enum ProgressType - { - /// - /// Check for updates - /// - Check, - - /// - /// Download the update package - /// - Download, - - /// - /// update file - /// - Updatefile, - - /// - /// update completed - /// - Done, - - /// - /// Update failed - /// - Fail, - - /// - /// Update config - /// - Config, - - /// - /// Update patch - /// - Patch, - - /// - /// Hash code - /// - Hash - } -} \ No newline at end of file diff --git a/src/c#/GeneralUpdate.Core/Domain/PO/Assembler/VersionAssembler.cs b/src/c#/GeneralUpdate.Core/Domain/PO/Assembler/VersionAssembler.cs deleted file mode 100644 index 57cea11a..00000000 --- a/src/c#/GeneralUpdate.Core/Domain/PO/Assembler/VersionAssembler.cs +++ /dev/null @@ -1,23 +0,0 @@ -using GeneralUpdate.Core.Domain.Entity; -using System.Collections.Generic; - -namespace GeneralUpdate.Core.Domain.PO.Assembler -{ - public class VersionAssembler - { - public static List ToDataObjects(List versionDTO) - { - List entitys = new List(); - versionDTO.ForEach((v) => - { - entitys.Add(ToDataObject(v)); - }); - return entitys; - } - - public static VersionInfo ToDataObject(VersionPO versionDO) - { - return new VersionInfo(versionDO.PubTime, versionDO.Name, versionDO.Hash, versionDO.Version, versionDO.Url); - } - } -} \ No newline at end of file diff --git a/src/c#/GeneralUpdate.Core/Domain/PO/VersionPO.cs b/src/c#/GeneralUpdate.Core/Domain/PO/VersionPO.cs deleted file mode 100644 index bca517a3..00000000 --- a/src/c#/GeneralUpdate.Core/Domain/PO/VersionPO.cs +++ /dev/null @@ -1,33 +0,0 @@ -namespace GeneralUpdate.Core.Domain.PO -{ - /// - /// Version data persistence. - /// - public class VersionPO - { - /// - /// Update package release time. - /// - public long PubTime { get; set; } - - /// - /// Update package name. - /// - public string Name { get; set; } - - /// - /// Compare and verify with the downloaded update package. - /// - public string Hash { get; set; } - - /// - /// The version number. - /// - public string Version { get; set; } - - /// - /// Remote service url address. - /// - public string Url { get; set; } - } -} \ No newline at end of file diff --git a/src/c#/GeneralUpdate.Core/Domain/PO/WillMessagePO.cs b/src/c#/GeneralUpdate.Core/Domain/PO/WillMessagePO.cs deleted file mode 100644 index 30dca502..00000000 --- a/src/c#/GeneralUpdate.Core/Domain/PO/WillMessagePO.cs +++ /dev/null @@ -1,81 +0,0 @@ -using System; -using System.Collections.Generic; - -namespace GeneralUpdate.Core.Domain.PO -{ - public enum WillMessageStatus - { - /// - /// Processing has not yet begun. - /// - NotStarted, - - /// - /// Processing completed. - /// - Completed, - - /// - /// Processing failure. - /// - Failed - } - - public class BackupPO - { - public string AppPath { get; set; } - - public string BackupPath { get; set; } - - public string Version { get; set; } - - public string Hash { get; set; } - - public int AppType { get; set; } - } - - public class WillMessagePO - { - public Stack Message { get; private set; } - public WillMessageStatus Status { get; private set; } - public DateTime CreateTime { get; private set; } - public DateTime ChangeTime { get; private set; } - - private WillMessagePO() - { } - - public class Builder - { - private readonly WillMessagePO _messagePO = new WillMessagePO(); - - public Builder SetMessage(Stack message) - { - _messagePO.Message = message ?? throw new ArgumentNullException($"{nameof(message)} cannot be null"); - return this; - } - - public Builder SetStatus(WillMessageStatus status) - { - _messagePO.Status = status; - return this; - } - - public Builder SetCreateTime(DateTime createTime) - { - _messagePO.CreateTime = createTime; - return this; - } - - public Builder SetChangeTime(DateTime changeTime) - { - _messagePO.ChangeTime = changeTime; - return this; - } - - public WillMessagePO Build() - { - return _messagePO; - } - } - } -} \ No newline at end of file diff --git a/src/c#/GeneralUpdate.Core/Domain/Service/VersionService.cs b/src/c#/GeneralUpdate.Core/Domain/Service/VersionService.cs deleted file mode 100644 index 4c3af355..00000000 --- a/src/c#/GeneralUpdate.Core/Domain/Service/VersionService.cs +++ /dev/null @@ -1,103 +0,0 @@ -using GeneralUpdate.Core.Domain.DTO; -using GeneralUpdate.Core.Domain.Enum; -using Newtonsoft.Json; -using System; -using System.IO; -using System.Net; -using System.Net.Http; -using System.Net.Security; -using System.Security.Cryptography.X509Certificates; -using System.Text; -using System.Threading.Tasks; -using GeneralUpdate.Core.Events; -using GeneralUpdate.Core.Events.CommonArgs; - -namespace GeneralUpdate.Core.Domain.Service -{ - public class VersionService - { - public async Task ValidationVersion(string url) - { - var updateResp = await GetTaskAsync(url); - if (updateResp == null || updateResp.Body == null) - { - throw new ArgumentNullException( - nameof(updateResp), - "The verification request is abnormal, please check the network or parameter configuration!" - ); - } - - if (updateResp.Code == HttpStatus.OK) - { - return updateResp; - } - else - { - throw new WebException( - $"Request failed , Code :{updateResp.Code}, Message:{updateResp.Message} !" - ); - } - } - - private async Task GetTaskAsync( - string httpUrl, - string headerKey = null, - string headerValue = null - ) - { - HttpWebResponse response = null; - try - { - ServicePointManager.ServerCertificateValidationCallback = CheckValidationResult; - var request = (HttpWebRequest)WebRequest.Create(httpUrl); - request.Method = "GET"; - request.Accept = "text/html, application/xhtml+xml, */*"; - request.ContentType = "application/x-www-form-urlencoded"; - request.Timeout = 15000; - if (!string.IsNullOrEmpty(headerKey) && !string.IsNullOrEmpty(headerValue)) - { - request.Headers[headerKey] = headerValue; - } - response = (HttpWebResponse)await request.GetResponseAsync(); - if (response.StatusCode != HttpStatusCode.OK) - { - throw new WebException( - $"Response status code does not indicate success: {response.StatusCode}!" - ); - } - var responseStream = response.GetResponseStream(); - if (responseStream == null) - { - throw new WebException( - "Response stream is null, please check the network or parameter configuration!" - ); - } - using (var reader = new StreamReader(responseStream, Encoding.UTF8)) - { - var tempStr = await reader.ReadToEndAsync(); - var respContent = JsonConvert.DeserializeObject(tempStr); - return respContent; - } - } - catch (Exception ex) - { - EventManager.Instance.Dispatch>( - this, - new ExceptionEventArgs(ex) - ); - return default; - } - finally - { - response?.Close(); - } - } - - private static bool CheckValidationResult( - object sender, - X509Certificate certificate, - X509Chain chain, - SslPolicyErrors sslPolicyErrors - ) => true; - } -} \ No newline at end of file diff --git a/src/c#/GeneralUpdate.Core/Domain/VO/FileVO.cs b/src/c#/GeneralUpdate.Core/Domain/VO/FileVO.cs deleted file mode 100644 index a8156c49..00000000 --- a/src/c#/GeneralUpdate.Core/Domain/VO/FileVO.cs +++ /dev/null @@ -1,28 +0,0 @@ -namespace GeneralUpdate.Core.Domain.VO -{ - /// - /// file object value. - /// - public class FileVO - { - /// - /// Client current version. - /// - public string ClientVersion { get; set; } - - /// - /// The latest version. - /// - public string LastVersion { get; set; } - - /// - /// installation path (for update file logic). - /// - public string InstallPath { get; set; } - - /// - /// Download file temporary storage path (for update file logic). - /// - public string TempPath { get; set; } - } -} \ No newline at end of file diff --git a/src/c#/GeneralUpdate.Core/Download/AbstractTask.cs b/src/c#/GeneralUpdate.Core/Download/AbstractTask.cs deleted file mode 100644 index 746c40fa..00000000 --- a/src/c#/GeneralUpdate.Core/Download/AbstractTask.cs +++ /dev/null @@ -1,339 +0,0 @@ -using GeneralUpdate.Core.Events.MultiEventArgs; -using GeneralUpdate.Core.Exceptions.CustomArgs; -using GeneralUpdate.Core.Exceptions.CustomException; -using System; -using System.Collections.Specialized; -using System.ComponentModel; -using System.IO; -using System.Net; -using System.Net.Http; -using System.Threading; - -namespace GeneralUpdate.Core.Download -{ - public abstract class AbstractTask : WebClient, ITask - { - #region Private Members - - private DownloadFileRangeState _fileRange; - private long _beforBytes; - private long _receivedBytes; - private long _totalBytes; - private int _timeOut; - - #endregion Private Members - - #region Public Properties - - public delegate void MultiDownloadProgressChangedEventHandler(object sender, MultiDownloadProgressChangedEventArgs e); - - public event MultiDownloadProgressChangedEventHandler MultiDownloadProgressChanged; - - public delegate void MultiAsyncCompletedEventHandler(object sender, AsyncCompletedEventArgs e); - - public event MultiAsyncCompletedEventHandler MultiDownloadFileCompleted; - - protected Timer SpeedTimer { get; set; } - protected DateTime StartTime { get; set; } - - public long BeforBytes - { - get - { - return Interlocked.Read(ref _beforBytes); - } - - set - { - Interlocked.Exchange(ref _beforBytes, value); - } - } - - public long ReceivedBytes - { - get - { - return Interlocked.Read(ref _receivedBytes); - } - - set - { - Interlocked.Exchange(ref _receivedBytes, value); - } - } - - public long TotalBytes - { - get - { - return Interlocked.Read(ref _totalBytes); - } - set - { - Interlocked.Exchange(ref _totalBytes, value); - } - } - - #endregion Public Properties - - #region Public Methods - - public void InitTimeOut(int timeout) - { - if (timeout <= 0) timeout = 30; - _timeOut = 1000 * timeout; - } - - protected override WebRequest GetWebRequest(Uri address) - { - HttpWebRequest request; - if (address.Scheme == "https") - { - ServicePointManager.ServerCertificateValidationCallback = (a, b, c, d) => { return true; }; - request = (HttpWebRequest)base.GetWebRequest(address); - request.ProtocolVersion = HttpVersion.Version10; - } - else - { - request = (HttpWebRequest)base.GetWebRequest(address); - } - - request.Timeout = _timeOut; - request.ReadWriteTimeout = _timeOut; - request.AllowAutoRedirect = false; - request.AllowWriteStreamBuffering = true; - - var cookieContainer = new CookieContainer(); - var collection = new NameValueCollection - { - { "Accept-Language", "zh-cn,zh;q=0.5" }, - { "Accept-Encoding", "gzip,deflate" }, - { "Accept-Charset", "GB2312,utf-8;q=0.7,*;q=0.7" }, - { "Keep-Alive", "115" } - }; - request.Accept = "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"; - request.UserAgent = "Mozilla/5.0 (Windows; U; Windows NT 5.1; zh-CN; rv:1.9.2.13) Gecko/20101203 Firefox/3.6.13"; - request.Headers.Add(collection); - request.CookieContainer = cookieContainer; - request.ServicePoint.BindIPEndPointDelegate = (servicePoint, remoteEndPoint, retryCount) => - { - if (remoteEndPoint.AddressFamily == System.Net.Sockets.AddressFamily.InterNetworkV6) - return new IPEndPoint(IPAddress.IPv6Any, 0); - else - return new IPEndPoint(IPAddress.Any, 0); - }; - return request; - } - - public new void CancelAsync() - { - base.CancelAsync(); - if (_fileRange != null && _fileRange.IsRangeDownload) _fileRange.IsRangeDownload = false; - } - - public void DownloadFileRange(string url, string path, object userState) - { - if (_fileRange != null && _fileRange.IsRangeDownload) return; - _fileRange = new DownloadFileRangeState(path, userState, this); - _fileRange.OnCompleted = () => MultiDownloadFileCompleted; - _fileRange.IsRangeDownload = true; - long startPos = CheckFile(_fileRange); - if (startPos == -1) return; - try - { - _fileRange.Request = (HttpWebRequest)GetWebRequest(new Uri(url)); - _fileRange.Request.ReadWriteTimeout = _timeOut; - _fileRange.Request.Timeout = _timeOut; - _fileRange.Respone = _fileRange.Request.GetResponse(); - _fileRange.Stream = _fileRange.Respone.GetResponseStream(); - if (_fileRange.Respone.ContentLength == startPos) - { - _fileRange.Close(); - File.Move(_fileRange.TempPath, _fileRange.Path); - _fileRange.Done(true); - return; - } - if (startPos > 0) _fileRange.Request.AddRange((int)startPos); - long totalBytesReceived = _fileRange.Respone.ContentLength + startPos; - long bytesReceived = startPos; - if (totalBytesReceived != 0 && bytesReceived >= totalBytesReceived) - { - _fileRange.Close(); - try - { - if (File.Exists(_fileRange.Path)) File.Delete(_fileRange.Path); - File.Move(_fileRange.TempPath, _fileRange.Path); - } - catch (Exception e) - { - _fileRange.Exception = e; - _fileRange.Close(); - } - } - else - { - WriteFile(_fileRange, startPos); - } - } - catch (HttpRequestException ex) - { - throw new GeneralUpdateException(new HttpExceptionArgs(url, 400, "Download file failed."), ex.Message, ex.InnerException); - } - catch (Exception e) - { - _fileRange.Exception = e; - throw new Exception($"'DownloadFileRange' This function has an internal exception : {e.Message} .", e.InnerException); - } - finally - { - if (_fileRange != null) _fileRange.Close(); - } - } - - #endregion Public Methods - - #region Private Methods - - private long CheckFile(DownloadFileRangeState state) - { - long startPos = 0; - if (File.Exists(state.TempPath)) - { - state.FileStream = File.OpenWrite(state.TempPath); - startPos = state.FileStream.Length; - state.FileStream.Seek(startPos, SeekOrigin.Current); - } - else - { - try - { - string direName = Path.GetDirectoryName(state.TempPath); - if (!Directory.Exists(direName)) Directory.CreateDirectory(direName); - state.FileStream = new FileStream(state.TempPath, FileMode.Create); - } - catch (Exception e) - { - state.Exception = e; - startPos = -1; - state.Close(); - } - } - return startPos; - } - - private void WriteFile(DownloadFileRangeState state, long startPos) - { - var bytesReceived = startPos; - byte[] bytes = new byte[1024]; - bool isDownloadCompleted = false; - var totalBytesReceived = state.Respone.ContentLength + startPos; - int readSize = state.Stream.Read(bytes, 0, 1024); - while (readSize > 0 && state.IsRangeDownload) - { - if (state == null || state.FileStream == null) break; - lock (state.FileStream) - { - if (MultiDownloadProgressChanged != null) - MultiDownloadProgressChanged(this, new MultiDownloadProgressChangedEventArgs(bytesReceived, totalBytesReceived, ((float)bytesReceived / totalBytesReceived), state.UserState)); - state.FileStream.Write(bytes, 0, readSize); - bytesReceived += readSize; - if (totalBytesReceived != 0 && bytesReceived >= totalBytesReceived) - { - try - { - state.Close(); - if (File.Exists(state.Path)) File.Delete(state.Path); - File.Move(state.TempPath, state.Path); - isDownloadCompleted = true; - state.Done(isDownloadCompleted); - } - catch (Exception e) - { - state.Exception = e; - state.Done(false); - } - } - else - { - readSize = state.Stream.Read(bytes, 0, 1024); - } - } - } - if (!isDownloadCompleted) state.Exception = new Exception("Request for early closure"); - } - - #endregion Private Methods - - private class DownloadFileRangeState - { - #region Private Members - - private const string tmpSuffix = ".temp"; - private Func _onDownloadCompleted = null; - private HttpWebRequest _request = null; - private WebResponse _respone = null; - private Stream _stream = null; - private FileStream _fileStream = null; - private Exception _exception = null; - private bool _isRangeDownload; - private string _tempPath; - private string _path; - private object _userState; - private object _sender; - - #endregion Private Members - - #region Constructors - - public DownloadFileRangeState(string path, object userState, object sender) - { - _path = path; - _userState = userState; - _tempPath = _path + tmpSuffix; - _sender = sender; - } - - #endregion Constructors - - #region Public Properties - - public Func OnCompleted { get => _onDownloadCompleted; set => _onDownloadCompleted = value; } - public HttpWebRequest Request { get => _request; set => _request = value; } - public WebResponse Respone { get => _respone; set => _respone = value; } - public Stream Stream { get => _stream; set => _stream = value; } - public FileStream FileStream { get => _fileStream; set => _fileStream = value; } - public Exception Exception { get => _exception; set => _exception = value; } - public bool IsRangeDownload { get => _isRangeDownload; set => _isRangeDownload = value; } - public string TempPath { get => _tempPath; } - public string Path { get => _path; } - public object UserState { get => _userState; } - public object Sender { get => _sender; } - - #endregion Public Properties - - #region Public Methods - - public void Close() - { - if (_fileStream != null) - { - _fileStream.Flush(); - _fileStream.Close(); - _fileStream = null; - } - if (_stream != null) _stream.Close(); - if (_respone != null) _respone.Close(); - if (_request != null) _request.Abort(); - if (_exception != null) throw new Exception(_exception.Message); - } - - public void Done(bool isCompleted) - { - if (_exception != null) throw new Exception(_exception.Message); - _onDownloadCompleted()(Sender, new AsyncCompletedEventArgs(_exception, isCompleted, _userState)); - } - - #endregion Public Methods - } - } -} \ No newline at end of file diff --git a/src/c#/GeneralUpdate.Core/Download/AbstractTaskManager.cs b/src/c#/GeneralUpdate.Core/Download/AbstractTaskManager.cs deleted file mode 100644 index aa4d2921..00000000 --- a/src/c#/GeneralUpdate.Core/Download/AbstractTaskManager.cs +++ /dev/null @@ -1,13 +0,0 @@ -namespace GeneralUpdate.Core.Download -{ - /// - /// Abstract task manager class. - /// - /// 'T' is the download task. - public abstract class AbstractTaskManager : ITaskManger> - { - public abstract void Remove(ITask task); - - public abstract void Add(ITask task); - } -} \ No newline at end of file diff --git a/src/c#/GeneralUpdate.Core/Download/DownloadManager.cs b/src/c#/GeneralUpdate.Core/Download/DownloadManager.cs deleted file mode 100644 index f22c7cbb..00000000 --- a/src/c#/GeneralUpdate.Core/Download/DownloadManager.cs +++ /dev/null @@ -1,164 +0,0 @@ -using GeneralUpdate.Core.Events.MultiEventArgs; -using System; -using System.Collections.Generic; -using System.Collections.Immutable; -using System.Reflection; -using System.Threading.Tasks; - -namespace GeneralUpdate.Core.Download -{ - /// - /// download task manager. - /// - /// update version information. - public sealed class DownloadManager : AbstractTaskManager - { - #region Private Members - - private string _path; - private string _format; - private int _timeOut; - private IList<(object, string)> _failedVersions; - private ImmutableList>.Builder _downloadTasksBuilder; - private ImmutableList> _downloadTasks; - - #endregion Private Members - - #region Constructors - - /// - /// download manager constructors. - /// - /// - /// - /// - public DownloadManager(string path, string format, int timeOut) - { - _path = path; - _format = format; - _timeOut = timeOut; - _failedVersions = new List>(); - _downloadTasksBuilder = ImmutableList.Create>().ToBuilder(); - } - - #endregion Constructors - - #region Public Properties - - /// - /// Record download exception information for all versions. - /// object: is 'UpdateVersion' , string: is error information. - /// - public IList<(object, string)> FailedVersions { get => _failedVersions; } - - public string Path { get => _path; } - - public string Format { get => _format; } - - public int TimeOut { get => _timeOut; } - - public ImmutableList> DownloadTasks { get => _downloadTasks ?? (_downloadTasksBuilder.ToImmutable()); private set => _downloadTasks = value; } - - public delegate void MultiAllDownloadCompletedEventHandler(object sender, MultiAllDownloadCompletedEventArgs e); - - public event MultiAllDownloadCompletedEventHandler MultiAllDownloadCompleted; - - public delegate void MultiDownloadProgressChangedEventHandler(object sender, MultiDownloadProgressChangedEventArgs e); - - public event MultiDownloadProgressChangedEventHandler MultiDownloadProgressChanged; - - public delegate void MultiAsyncCompletedEventHandler(object sender, MultiDownloadCompletedEventArgs e); - - public event MultiAsyncCompletedEventHandler MultiDownloadCompleted; - - public delegate void MultiDownloadErrorEventHandler(object sender, MultiDownloadErrorEventArgs e); - - public event MultiDownloadErrorEventHandler MultiDownloadError; - - public delegate void MultiDownloadStatisticsEventHandler(object sender, MultiDownloadStatisticsEventArgs e); - - public event MultiDownloadStatisticsEventHandler MultiDownloadStatistics; - - #endregion Public Properties - - #region Public Methods - - /// - /// launch update. - /// - /// - /// - /// - public void LaunchTaskAsync() - { - try - { - var downloadTasks = new List(); - foreach (var task in DownloadTasks) - { - var downloadTask = (task as DownloadTask); - downloadTasks.Add(downloadTask.Launch()); - } - Task.WaitAll(downloadTasks.ToArray()); - MultiAllDownloadCompleted(this, new MultiAllDownloadCompletedEventArgs(true, _failedVersions)); - } - catch (ObjectDisposedException ex) - { - throw new ArgumentNullException("Download manager launch abnormally ! exception is 'ObjectDisposedException'.", ex); - } - catch (AggregateException ex) - { - throw new ArgumentNullException("Download manager launch abnormally ! exception is 'AggregateException'.", ex); - } - catch (ArgumentNullException ex) - { - throw new ArgumentNullException("Download manager launch abnormally ! exception is 'ArgumentNullException'.", ex); - } - catch (AmbiguousMatchException ex) - { - throw new AmbiguousMatchException("Download manager launch abnormally ! exception is 'AmbiguousMatchException'.", ex); - } - catch (Exception ex) - { - throw new Exception($"Download manager error : {ex.Message} !", ex.InnerException); - } - finally - { - if (_failedVersions.Count > 0) MultiAllDownloadCompleted(this, new MultiAllDownloadCompletedEventArgs(true, _failedVersions)); - } - } - - public void OnMultiDownloadStatistics(object sender, MultiDownloadStatisticsEventArgs e) - { - if (MultiDownloadStatistics != null) this.MultiDownloadStatistics(sender, e); - } - - public void OnMultiDownloadProgressChanged(object sender, MultiDownloadProgressChangedEventArgs e) - { - if (MultiDownloadProgressChanged != null) this.MultiDownloadProgressChanged(sender, e); - } - - public void OnMultiAsyncCompleted(object sender, MultiDownloadCompletedEventArgs e) - { - if (MultiDownloadCompleted != null) this.MultiDownloadCompleted(sender, e); - } - - public void OnMultiDownloadError(object sender, MultiDownloadErrorEventArgs e) - { - if (MultiDownloadError != null) this.MultiDownloadError(sender, e); - _failedVersions.Add((e.Version, e.Exception.Message)); - } - - public override void Remove(ITask task) - { - if (task != null && _downloadTasksBuilder.Contains(task)) _downloadTasksBuilder.Remove(task); - } - - public override void Add(ITask task) - { - if (task != null && !_downloadTasksBuilder.Contains(task)) _downloadTasksBuilder.Add(task); - } - - #endregion Public Methods - } -} \ No newline at end of file diff --git a/src/c#/GeneralUpdate.Core/Download/DownloadTask.cs b/src/c#/GeneralUpdate.Core/Download/DownloadTask.cs deleted file mode 100644 index 146ec545..00000000 --- a/src/c#/GeneralUpdate.Core/Download/DownloadTask.cs +++ /dev/null @@ -1,216 +0,0 @@ -using GeneralUpdate.Core.CustomAwaiter; -using GeneralUpdate.Core.Events.MultiEventArgs; -using GeneralUpdate.Core.Exceptions.CustomArgs; -using GeneralUpdate.Core.Exceptions.CustomException; -using System; -using System.Globalization; -using System.Reflection; -using System.Runtime.ExceptionServices; -using System.Threading; -using System.Threading.Tasks; - -namespace GeneralUpdate.Core.Download -{ - /// - /// Download task class. - /// - /// 'T' is the version information that needs to be downloaded. - public sealed class DownloadTask : AbstractTask, IAwaiter> - { - #region Private Members - - private Exception _exception; - private DownloadManager _manager; - private const int DEFAULT_DELTA = 1048576;//1024*1024 - private TVersion _version; - - #endregion Private Members - - #region Constructors - - public DownloadTask(DownloadManager manger, TVersion version) - { - _manager = manger; - _version = version; - } - - #endregion Constructors - - #region Public Properties - - public bool IsCompleted { get; private set; } - - #endregion Public Properties - - #region Public Methods - - /// - /// Launch the current download task. - /// - /// - public async Task Launch() - { - try - { - var url = GetPropertyValue(_version, "Url"); - var name = GetPropertyValue(_version, "Name"); - InitTimeOut(_manager.TimeOut); - InitStatisticsEvent(); - InitProgressEvent(); - InitCompletedEvent(); - var installPath = $"{_manager.Path}{name}{_manager.Format}"; - DownloadFileRange(url, installPath, null); - await this; - } - catch (Exception ex) - { - _manager.OnMultiDownloadError(this, new MultiDownloadErrorEventArgs(ex, _version)); - _exception = new GeneralUpdateException("'download task' The executes abnormally !", ex); - } - } - - public DownloadTask GetResult() - { - if (_exception != null) ExceptionDispatchInfo.Capture(_exception).Throw(); - return this; - } - - public void OnCompleted(Action continuation) - { - if (IsCompleted) continuation?.Invoke(); - } - - public DownloadTask GetAwaiter() => this; - - public async Task AsTask(DownloadTask awaiter) => await awaiter; - - #endregion Public Methods - - #region Private Methods - - private void InitStatisticsEvent() - { - if (SpeedTimer != null) return; - - SpeedTimer = new Timer(_ => - { - try - { - var interval = DateTime.Now - StartTime; - var downLoadSpeed = interval.Seconds < 1 - ? ToUnit(ReceivedBytes - BeforBytes) - : ToUnit(ReceivedBytes - BeforBytes / interval.Seconds); - var size = (TotalBytes - ReceivedBytes) / DEFAULT_DELTA; - var remainingTime = new DateTime().AddSeconds(Convert.ToDouble(size)); - _manager.OnMultiDownloadStatistics(this, new MultiDownloadStatisticsEventArgs(_version, remainingTime, downLoadSpeed)); - StartTime = DateTime.Now; - BeforBytes = ReceivedBytes; - } - catch (Exception exception) - { - _manager.OnMultiDownloadError(this, new MultiDownloadErrorEventArgs(exception, _version)); - } - }, null, 0, 1000); - } - - private void InitProgressEvent() - { - MultiDownloadProgressChanged += ((sender, e) => - { - try - { - ReceivedBytes = e.BytesReceived; - TotalBytes = e.TotalBytesToReceive; - - var eventArgs = new MultiDownloadProgressChangedEventArgs(_version, - e.BytesReceived / DEFAULT_DELTA, - e.TotalBytesToReceive / DEFAULT_DELTA, - e.ProgressPercentage, - e.UserState); - - _manager.OnMultiDownloadProgressChanged(this, eventArgs); - } - catch (Exception exception) - { - _manager.OnMultiDownloadError(this, new MultiDownloadErrorEventArgs(exception, _version)); - } - }); - } - - private void InitCompletedEvent() - { - MultiDownloadFileCompleted += ((sender, e) => - { - try - { - if (SpeedTimer != null) - { - SpeedTimer.Dispose(); - SpeedTimer = null; - } - var eventArgs = new MultiDownloadCompletedEventArgs(_version, e.Error, e.Cancelled, e.UserState); - _manager.OnMultiAsyncCompleted(this, eventArgs); - Dispose(); - } - catch (Exception exception) - { - _manager.FailedVersions.Add(new ValueTuple { }); - _manager.OnMultiDownloadError(this, new MultiDownloadErrorEventArgs(exception, _version)); - } - finally - { - IsCompleted = true; - } - }); - } - - private TResult GetPropertyValue(TVersion entity, string propertyName) - { - TResult result = default(TResult); - Type entityType = typeof(TVersion); - try - { - PropertyInfo info = entityType.GetProperty(propertyName); - result = (TResult)info.GetValue(entity); - } - catch (ArgumentNullException ex) - { - throw _exception = new ArgumentNullException("'GetPropertyValue' The method executes abnormally !", ex); - } - catch (AmbiguousMatchException ex) - { - throw _exception = new AmbiguousMatchException("'GetPropertyValue' The method executes abnormally !", ex); - } - catch (Exception ex) - { - throw new GeneralUpdateException($"Download task GetPropertyValue error : {ex.Message}", ex.InnerException); - } - return result; - } - - private string ToUnit(long byteSize) - { - string result; - var tempSize = Convert.ToSingle(byteSize) / 1024; - if (tempSize > 1) - { - var tempMbyte = tempSize / 1024; - if (tempMbyte > 1) - { - result = $"{tempMbyte.ToString("##0.00", CultureInfo.InvariantCulture)}MB/S"; - } - else - { - result = $"{tempSize.ToString("##0.00", CultureInfo.InvariantCulture)}KB/S"; - } - } - else - { - result = $"{byteSize.ToString(CultureInfo.InvariantCulture)}B/S"; - } - return result; - } - - #endregion Private Methods - } -} \ No newline at end of file diff --git a/src/c#/GeneralUpdate.Core/Download/ITask.cs b/src/c#/GeneralUpdate.Core/Download/ITask.cs deleted file mode 100644 index f1d2856f..00000000 --- a/src/c#/GeneralUpdate.Core/Download/ITask.cs +++ /dev/null @@ -1,5 +0,0 @@ -namespace GeneralUpdate.Core.Download -{ - public interface ITask - { } -} \ No newline at end of file diff --git a/src/c#/GeneralUpdate.Core/Download/ITaskManger.cs b/src/c#/GeneralUpdate.Core/Download/ITaskManger.cs deleted file mode 100644 index c6502641..00000000 --- a/src/c#/GeneralUpdate.Core/Download/ITaskManger.cs +++ /dev/null @@ -1,21 +0,0 @@ -namespace GeneralUpdate.Core.Download -{ - /// - /// Download task interface. - /// - /// 'T' is the version information that needs to be downloaded. - internal interface ITaskManger - { - /// - /// Add download task . - /// - /// - void Add(T task); - - /// - /// Delete download task . - /// - /// - void Remove(T task); - } -} \ No newline at end of file diff --git a/src/c#/GeneralUpdate.Core/Driver/BackupDriverCommand.cs b/src/c#/GeneralUpdate.Core/Driver/BackupDriverCommand.cs index a98efe95..8b22450b 100644 --- a/src/c#/GeneralUpdate.Core/Driver/BackupDriverCommand.cs +++ b/src/c#/GeneralUpdate.Core/Driver/BackupDriverCommand.cs @@ -1,4 +1,8 @@ -using System.IO; +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Linq; using System.Text; namespace GeneralUpdate.Core.Driver @@ -6,43 +10,114 @@ namespace GeneralUpdate.Core.Driver /// /// When the /export-driver command backs up a driver, it backs up the driver package along with all its dependencies, such as associated library files and other related files. /// - public class BackupDriverCommand : IDriverCommand + public class BackupDriverCommand(DriverInformation information) : DriverCommand { - private DriverInformation _information; + private readonly string _driverExtension = $"*{information.DriverFileExtension}"; - public BackupDriverCommand(DriverInformation information) => _information = information; - - public void Execute() + public override void Execute() { + var uninstalledDrivers = Directory.GetFiles(information.DriverDirectory, _driverExtension, SearchOption.AllDirectories).ToList(); + var installedDrivers = GetInstalledDrivers(information.FieldMappings); + var tempDrivers = installedDrivers.Where(a => uninstalledDrivers.Any(b => string.Equals(a.OriginalName, Path.GetFileName(b)))).ToList(); + information.Drivers = tempDrivers; + + //Export the backup according to the driver name. + if (Directory.Exists(information.OutPutDirectory)) + { + Directory.Delete(information.OutPutDirectory, true); + } + + Directory.CreateDirectory(information.OutPutDirectory); + /* * Back up the specified list of drives. */ - foreach (var driver in _information.Drivers) + foreach (var driver in tempDrivers) { - //Export the backup according to the driver name. - var outPutDirectory = Path.Combine(_information.OutPutDirectory, Path.GetFileNameWithoutExtension(driver)); - - if (Directory.Exists(outPutDirectory)) - Directory.Delete(outPutDirectory, true); - - Directory.CreateDirectory(outPutDirectory); - /* * If no test driver files are available, you can run the following command to export all installed driver files. * (1) dism /online /export-driver /destination:"D:\packet\cache\" * (2) pnputil /export-driver * D:\packet\cache * * The following code example exports the specified driver to the specified directory. - * pnputil /export-driver oem14.inf D:\packet\cache + * pnputil /export-driver oemXX.inf D:\packet\cache */ + var path = Path.Combine(information.OutPutDirectory, driver.PublishedName); var command = new StringBuilder("/c pnputil /export-driver ") - .Append(driver) + .Append(driver.PublishedName) .Append(' ') - .Append(outPutDirectory) + .Append(path) .ToString(); - + + if (!Directory.Exists(path)) + { + Directory.CreateDirectory(path); + } + CommandExecutor.ExecuteCommand(command); } } + + private IEnumerable GetInstalledDrivers(Dictionary fieldMappings) + { + var drivers = new List(); + var process = new Process(); + process.StartInfo.FileName = "pnputil"; + process.StartInfo.Arguments = "/enum-drivers"; + process.StartInfo.RedirectStandardOutput = true; + process.StartInfo.UseShellExecute = false; + process.StartInfo.CreateNoWindow = true; + process.Start(); + + var output = process.StandardOutput.ReadToEnd(); + process.WaitForExit(); + + var lines = output.Split(new[] { Environment.NewLine }, StringSplitOptions.RemoveEmptyEntries); + + DriverInfo currentDriver = null; + foreach (var line in lines) + { + if (line.StartsWith(fieldMappings["PublishedName"])) + { + if (currentDriver != null) + { + drivers.Add(currentDriver); + } + currentDriver = new (); + currentDriver.PublishedName = line.Split(new[] { ':' }, 2)[1].Trim(); + } + else if (line.StartsWith(fieldMappings["OriginalName"]) && currentDriver != null) + { + currentDriver.OriginalName = line.Split(new[] { ':' }, 2)[1].Trim(); + } + else if (line.StartsWith(fieldMappings["Provider"]) && currentDriver != null) + { + currentDriver.Provider = line.Split(new[] { ':' }, 2)[1].Trim(); + } + else if (line.StartsWith(fieldMappings["ClassName"]) && currentDriver != null) + { + currentDriver.ClassName = line.Split(new[] { ':' }, 2)[1].Trim(); + } + else if (line.StartsWith(fieldMappings["ClassGUID"]) && currentDriver != null) + { + currentDriver.ClassGUID = line.Split(new[] { ':' }, 2)[1].Trim(); + } + else if (line.StartsWith(fieldMappings["Version"]) && currentDriver != null) + { + currentDriver.Version = line.Split(new[] { ':' }, 2)[1].Trim(); + } + else if (line.StartsWith(fieldMappings["Signer"]) && currentDriver != null) + { + currentDriver.Signer = line.Split(new[] { ':' }, 2)[1].Trim(); + } + } + + if (currentDriver != null) + { + drivers.Add(currentDriver); + } + + return drivers; + } } } \ No newline at end of file diff --git a/src/c#/GeneralUpdate.Core/Driver/CommandExecutor.cs b/src/c#/GeneralUpdate.Core/Driver/CommandExecutor.cs index aa4fb115..a22284bf 100644 --- a/src/c#/GeneralUpdate.Core/Driver/CommandExecutor.cs +++ b/src/c#/GeneralUpdate.Core/Driver/CommandExecutor.cs @@ -1,5 +1,4 @@ -using GeneralUpdate.Core.Exceptions; -using System; +using System; using System.Diagnostics; namespace GeneralUpdate.Core.Driver @@ -9,6 +8,9 @@ namespace GeneralUpdate.Core.Driver /// public class CommandExecutor { + private CommandExecutor() + { } + public static void ExecuteCommand(string command) { /* @@ -29,17 +31,36 @@ Update the driver regularly to ensure that the driver is compatible with the cur WindowStyle = ProcessWindowStyle.Hidden, FileName = "cmd.exe", Arguments = command, - UseShellExecute = true, + UseShellExecute = false, + RedirectStandardOutput = true, + RedirectStandardError = true, Verb = "runas" }; - using (var process = new Process { StartInfo = processStartInfo }) + var process = new Process(); + try { + process.StartInfo = processStartInfo; process.Start(); process.WaitForExit(); + // 读取标准输出 + var output = process.StandardOutput.ReadToEnd(); + Debug.WriteLine(output); + + // 读取错误输出 + var error = process.StandardError.ReadToEnd(); + if (!string.IsNullOrEmpty(error)) + { + Debug.WriteLine("Error: " + error); + } + if (process.ExitCode != 0) - ThrowExceptionUtility.Throw($"Operation failed code: {process.ExitCode}"); + throw new ApplicationException($"Operation failed code: {process.ExitCode}"); + } + finally + { + process.Dispose(); } } } diff --git a/src/c#/GeneralUpdate.Core/Driver/DeleteDriverCommand.cs b/src/c#/GeneralUpdate.Core/Driver/DeleteDriverCommand.cs index 0d21452f..f0fe0e7a 100644 --- a/src/c#/GeneralUpdate.Core/Driver/DeleteDriverCommand.cs +++ b/src/c#/GeneralUpdate.Core/Driver/DeleteDriverCommand.cs @@ -1,23 +1,18 @@ using System.Text; -namespace GeneralUpdate.Core.Driver +namespace GeneralUpdate.Core.Driver; + +public class DeleteDriverCommand(DriverInformation information) : DriverCommand { - public class DeleteDriverCommand : IDriverCommand + public override void Execute() { - private DriverInformation _information; - - public DeleteDriverCommand(DriverInformation information) => _information = information; - - public void Execute() + //Before installing the driver, delete the driver that has been installed on the local system. Otherwise, an exception may occur. + foreach (var driver in information.Drivers) { - //Before installing the driver, delete the driver that has been installed on the local system. Otherwise, an exception may occur. - foreach (var driver in _information.Drivers) - { - var command = new StringBuilder("/c pnputil /delete-driver ") - .Append(driver) - .ToString(); - CommandExecutor.ExecuteCommand(command); - } + var command = new StringBuilder("/c pnputil /delete-driver ") + .Append(driver.PublishedName) + .ToString(); + CommandExecutor.ExecuteCommand(command); } } } \ No newline at end of file diff --git a/src/c#/GeneralUpdate.Core/Driver/DriverCommand.cs b/src/c#/GeneralUpdate.Core/Driver/DriverCommand.cs new file mode 100644 index 00000000..00cb4500 --- /dev/null +++ b/src/c#/GeneralUpdate.Core/Driver/DriverCommand.cs @@ -0,0 +1,24 @@ +using System.Collections; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using GeneralUpdate.Common.FileBasic; + +namespace GeneralUpdate.Core.Driver +{ + public abstract class DriverCommand + { + public abstract void Execute(); + + /// + /// Search for driver files. + /// + /// + /// + protected static IEnumerable SearchDrivers(string patchPath, string fileExtension) + { + var files = GeneralFileManager.GetAllfiles(patchPath); + return files.Where(x => x.FullName.EndsWith(fileExtension)).ToList(); + } + } +} \ No newline at end of file diff --git a/src/c#/GeneralUpdate.Core/Driver/DriverInfo.cs b/src/c#/GeneralUpdate.Core/Driver/DriverInfo.cs new file mode 100644 index 00000000..539cfb1b --- /dev/null +++ b/src/c#/GeneralUpdate.Core/Driver/DriverInfo.cs @@ -0,0 +1,12 @@ +namespace GeneralUpdate.Core.Driver; + +public class DriverInfo +{ + public string PublishedName { get; set; } + public string OriginalName { get; set; } + public string Provider { get; set; } + public string ClassName { get; set; } + public string ClassGUID { get; set; } + public string Version { get; set; } + public string Signer { get; set; } +} \ No newline at end of file diff --git a/src/c#/GeneralUpdate.Core/Driver/DriverInformation.cs b/src/c#/GeneralUpdate.Core/Driver/DriverInformation.cs index 3e1e1da4..e396e2a6 100644 --- a/src/c#/GeneralUpdate.Core/Driver/DriverInformation.cs +++ b/src/c#/GeneralUpdate.Core/Driver/DriverInformation.cs @@ -1,6 +1,5 @@ -using GeneralUpdate.Core.Exceptions; +using System; using System.Collections.Generic; -using System.Linq; namespace GeneralUpdate.Core.Driver { @@ -9,58 +8,59 @@ namespace GeneralUpdate.Core.Driver /// public class DriverInformation { - /// - /// Directory for storing the driver to be installed (Update the driver file in the package). - /// - public string InstallDirectory { get; private set; } - + public Dictionary FieldMappings { get; private set; } + + public string DriverFileExtension { get; private set; } + /// /// All driver backup directories. /// public string OutPutDirectory { get; private set; } + + public string DriverDirectory { get; private set; } /// /// A collection of driver files to be backed up. /// - public List Drivers { get; private set; } + public IEnumerable Drivers { get; set; } private DriverInformation() { } - + public class Builder { - private DriverInformation _information = new DriverInformation(); + private DriverInformation _information = new (); - public Builder SetInstallDirectory(string installDirectory) + public Builder SetDriverFileExtension(string fileExtension) { - _information.InstallDirectory = installDirectory; + _information.DriverFileExtension = fileExtension; return this; } - + public Builder SetOutPutDirectory(string outPutDirectory) { _information.OutPutDirectory = outPutDirectory; return this; } - - /// - /// Find the collection of driver names that need to be updated from the update package. - /// - /// - /// - public Builder SetDriverNames(List driverNames) + + public Builder SetDriverDirectory(string driverDirectory) + { + _information.DriverDirectory = driverDirectory; + return this; + } + + public Builder SetFieldMappings(Dictionary fieldMappings) { - _information.Drivers = driverNames; + _information.FieldMappings = fieldMappings; return this; } public DriverInformation Build() { - if (string.IsNullOrWhiteSpace(_information.InstallDirectory) || - string.IsNullOrWhiteSpace(_information.OutPutDirectory) || - !_information.Drivers.Any()) + if (string.IsNullOrWhiteSpace(_information.OutPutDirectory) || + string.IsNullOrWhiteSpace(_information.DriverFileExtension)) { - ThrowExceptionUtility.ThrowIfNull("Cannot create DriverInformation, not all fields are set."); + throw new ArgumentNullException("Cannot create DriverInformation, not all fields are set."); } return _information; diff --git a/src/c#/GeneralUpdate.Core/Driver/DriverProcessor.cs b/src/c#/GeneralUpdate.Core/Driver/DriverProcessor.cs index 8923af2f..3f4b848d 100644 --- a/src/c#/GeneralUpdate.Core/Driver/DriverProcessor.cs +++ b/src/c#/GeneralUpdate.Core/Driver/DriverProcessor.cs @@ -8,12 +8,9 @@ namespace GeneralUpdate.Core.Driver /// public class DriverProcessor { - private readonly List _commands = new List(); + private readonly List _commands = new (); - public void AddCommand(IDriverCommand command) - { - _commands.Add(command); - } + public void AddCommand(DriverCommand command) => _commands.Add(command); /// /// Execute all driver-related commands. diff --git a/src/c#/GeneralUpdate.Core/Driver/IDriverCommand.cs b/src/c#/GeneralUpdate.Core/Driver/IDriverCommand.cs deleted file mode 100644 index 76e24f92..00000000 --- a/src/c#/GeneralUpdate.Core/Driver/IDriverCommand.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace GeneralUpdate.Core.Driver -{ - public interface IDriverCommand - { - void Execute(); - } -} \ No newline at end of file diff --git a/src/c#/GeneralUpdate.Core/Driver/InstallDriverCommand.cs b/src/c#/GeneralUpdate.Core/Driver/InstallDriverCommand.cs index 17953cd1..cf42b8b3 100644 --- a/src/c#/GeneralUpdate.Core/Driver/InstallDriverCommand.cs +++ b/src/c#/GeneralUpdate.Core/Driver/InstallDriverCommand.cs @@ -1,5 +1,4 @@ -using GeneralUpdate.Core.Exceptions; -using System; +using System; using System.IO; using System.Text; @@ -8,17 +7,13 @@ namespace GeneralUpdate.Core.Driver /// /// Install the new driver, and if the installation fails, the backup is automatically restored. /// - public class InstallDriverCommand : IDriverCommand + public class InstallDriverCommand(DriverInformation information) : DriverCommand { - private DriverInformation _information; - - public InstallDriverCommand(DriverInformation information) => _information = information; - - public void Execute() + public override void Execute() { - try + foreach (var driver in information.Drivers) { - foreach (var driver in _information.Drivers) + try { /* * 1.It is best to ensure that the installed file is OEM INF, otherwise PnPUtil may indicate that non-OEM INF cannot perform the current operation. @@ -27,19 +22,19 @@ public void Execute() * (On Windows, an ExitCode value of 259 (STILL_ACTIVE) means that the process is still running) * If you do not remove the previous installation 259 prompt will give you a misleading impression of what is running. */ - var path = Path.Combine(_information.InstallDirectory, Path.GetFileNameWithoutExtension(driver), driver); + var path = Path.Combine(information.DriverDirectory, driver.OriginalName); var command = new StringBuilder("/c pnputil /add-driver ") .Append(path) .Append(" /install") .ToString(); CommandExecutor.ExecuteCommand(command); } - } - catch (Exception ex) - { - //restore all the drivers in the backup directory. - new RestoreDriverCommand(_information).Execute(); - ThrowExceptionUtility.Throw($"Failed to execute install command for {_information.InstallDirectory}", ex); + catch (Exception ex) + { + //restore all the drivers in the backup directory. + new RestoreDriverCommand(information).Execute(); + throw new ApplicationException($"Failed to execute driver command: {ex.Message}, details: {ex} !"); + } } } } diff --git a/src/c#/GeneralUpdate.Core/Driver/RestoreDriverCommand.cs b/src/c#/GeneralUpdate.Core/Driver/RestoreDriverCommand.cs index f05c1679..064735b0 100644 --- a/src/c#/GeneralUpdate.Core/Driver/RestoreDriverCommand.cs +++ b/src/c#/GeneralUpdate.Core/Driver/RestoreDriverCommand.cs @@ -1,33 +1,40 @@ -using GeneralUpdate.Core.Exceptions; -using System; -using System.IO; +using System; +using System.Linq; using System.Text; +using GeneralUpdate.Common.FileBasic; namespace GeneralUpdate.Core.Driver { - public class RestoreDriverCommand : IDriverCommand + public class RestoreDriverCommand(DriverInformation information) { - private DriverInformation _information; - - public RestoreDriverCommand(DriverInformation information) => _information = information; - public void Execute() { try { - foreach (var driver in _information.Drivers) + var backupFiles = GeneralFileManager.GetAllfiles(information.OutPutDirectory); + var fileExtension = information.DriverFileExtension; + var drivers = backupFiles.Where(x => x.FullName.EndsWith(fileExtension)).ToList(); + + foreach (var driver in drivers) { - //Install all drivers in the specified directory, and if the installation fails, restore all the drivers in the backup directory. - var command = new StringBuilder("/c pnputil /add-driver ") - .Append(Path.Combine(_information.OutPutDirectory, Path.GetFileNameWithoutExtension(driver), driver)) - .Append(" /install") - .ToString(); - CommandExecutor.ExecuteCommand(command); + try + { + //Install all drivers in the specified directory, and if the installation fails, restore all the drivers in the backup directory. + var command = new StringBuilder("/c pnputil /add-driver ") + .Append(driver.FullName) + .Append(" /install") + .ToString(); + CommandExecutor.ExecuteCommand(command); + } + catch (Exception e) + { + throw new ApplicationException($"Failed to execute install command for {driver.FullName}, error: {e.Message} !"); + } } } - catch (Exception ex) + catch { - ThrowExceptionUtility.Throw($"Failed to execute restore command for {_information.OutPutDirectory}", ex); + throw new ApplicationException($"Failed to execute restore command for {information.OutPutDirectory}"); } } } diff --git a/src/c#/GeneralUpdate.Core/Events/CommonArgs/ExceptionEventArgs.cs b/src/c#/GeneralUpdate.Core/Events/CommonArgs/ExceptionEventArgs.cs deleted file mode 100644 index 2b54d23d..00000000 --- a/src/c#/GeneralUpdate.Core/Events/CommonArgs/ExceptionEventArgs.cs +++ /dev/null @@ -1,18 +0,0 @@ -using System; - -namespace GeneralUpdate.Core.Events.CommonArgs -{ - public class ExceptionEventArgs : EventArgs - { - private readonly Exception _exception; - - public ExceptionEventArgs(Exception exception) - { - _exception = exception; - } - - public ExceptionEventArgs(string mesage) => _exception = new Exception(mesage); - - public Exception Exception => _exception; - } -} \ No newline at end of file diff --git a/src/c#/GeneralUpdate.Core/Events/EventManager.cs b/src/c#/GeneralUpdate.Core/Events/EventManager.cs deleted file mode 100644 index 66ee85e2..00000000 --- a/src/c#/GeneralUpdate.Core/Events/EventManager.cs +++ /dev/null @@ -1,166 +0,0 @@ -using System; -using System.Collections.Generic; -using System.ComponentModel; - -namespace GeneralUpdate.Core.Events -{ - /// - /// Manage all events in the component. - /// - public class EventManager : IEventManager, IDisposable - { - // Use interop to call the method necessary - // to clean up the unmanaged resource. - [System.Runtime.InteropServices.DllImport("Kernel32")] - private static extern Boolean CloseHandle(IntPtr handle); - - private static readonly object _lockObj = new object(); - private static EventManager _instance; - private Dictionary _dicDelegates = new Dictionary(); - - // Track whether Dispose has been called. - private bool disposed = false; - - // Pointer to an external unmanaged resource. - private IntPtr handle; - - // Other managed resource this class uses. - private Component component = null; - - private EventManager() => component = new Component(); - - // Use C# finalizer syntax for finalization code. - // This finalizer will run only if the Dispose method - // does not get called. - // It gives your base class the opportunity to finalize. - // Do not provide finalizer in types derived from this class. - ~EventManager() - { - // Do not re-create Dispose clean-up code here. - // Calling Dispose(disposing: false) is optimal in terms of - // readability and maintainability. - Dispose(disposing: false); - } - - public static EventManager Instance - { - get - { - if (_instance == null) - { - lock (_lockObj) - { - if (_instance == null) - _instance = new EventManager(); - } - } - return _instance; - } - } - - /// - /// Add listener - /// - /// Specify the delegate type. - /// Delegate to be added. - /// parameter null exception. - public void AddListener(TDelegate newDelegate) where TDelegate : Delegate - { - if (newDelegate == null) throw new ArgumentNullException(nameof(newDelegate)); - if (_dicDelegates.ContainsKey(typeof(TDelegate))) return; - handle = new IntPtr(1); - _dicDelegates.Add(typeof(TDelegate), newDelegate); - } - - /// - /// Remove listener - /// - /// Specify the delegate type. - /// Remove old delegates. - /// parameter null exception. - public void RemoveListener(TDelegate oldDelegate) where TDelegate : Delegate - { - if (oldDelegate == null) throw new ArgumentNullException(nameof(oldDelegate)); - var delegateType = oldDelegate.GetType(); - if (!delegateType.IsInstanceOfType(typeof(TDelegate))) return; - Delegate tempDelegate = null; - if (_dicDelegates.TryGetValue(delegateType, out tempDelegate)) - { - if (tempDelegate == null) - { - _dicDelegates.Remove(delegateType); - } - else - { - _dicDelegates[delegateType] = tempDelegate; - } - } - } - - /// - /// Triggers a delegate of the same type. - /// - /// - /// trigger source object. - /// event args. - /// parameter null exception. - public void Dispatch(object sender, EventArgs eventArgs) where TDelegate : Delegate - { - if (sender == null) throw new ArgumentNullException(nameof(sender)); - if (eventArgs == null) throw new ArgumentNullException(nameof(eventArgs)); - if (!_dicDelegates.ContainsKey(typeof(TDelegate))) return; - _dicDelegates[typeof(TDelegate)].DynamicInvoke(sender, eventArgs); - } - - /// - /// Clear all listeners. - /// - public void Clear() => _dicDelegates.Clear(); - - // Implement IDisposable. - // Do not make this method virtual. - // A derived class should not be able to override this method. - public void Dispose() - { - Dispose(disposing: true); - // This object will be cleaned up by the Dispose method. - // Therefore, you should call GC.SuppressFinalize to - // take this object off the finalization queue - // and prevent finalization code for this object - // from executing a second time. - GC.SuppressFinalize(this); - } - - // Dispose(bool disposing) executes in two distinct scenarios. - // If disposing equals true, the method has been called directly - // or indirectly by a user's code. Managed and unmanaged resources - // can be disposed. - // If disposing equals false, the method has been called by the - // runtime from inside the finalizer and you should not reference - // other objects. Only unmanaged resources can be disposed. - protected virtual void Dispose(bool disposing) - { - // Check to see if Dispose has already been called. - if (!this.disposed) - { - // If disposing equals true, dispose all managed - // and unmanaged resources. - if (disposing) - { - // Dispose managed resources. - component.Dispose(); - } - - // Call the appropriate methods to clean up - // unmanaged resources here. - // If disposing is false, - // only the following code is executed. - CloseHandle(handle); - handle = IntPtr.Zero; - - // Note disposing has been done. - disposed = true; - } - } - } -} \ No newline at end of file diff --git a/src/c#/GeneralUpdate.Core/Events/IEventManager.cs b/src/c#/GeneralUpdate.Core/Events/IEventManager.cs deleted file mode 100644 index 6bf07c60..00000000 --- a/src/c#/GeneralUpdate.Core/Events/IEventManager.cs +++ /dev/null @@ -1,37 +0,0 @@ -using System; - -namespace GeneralUpdate.Core.Events -{ - /// - /// Event manager interface. - /// - public interface IEventManager - { - /// - /// Adding Event Listeners. - /// - /// Generic delegate. - /// New delegate that needs to be injected. - void AddListener(TDelegate newDelegate) where TDelegate : Delegate; - - /// - /// Removing Event Listening. - /// - /// Generic delegate. - /// Need to remove an existing delegate. - void RemoveListener(TDelegate oldDelegate) where TDelegate : Delegate; - - /// - /// Triggers notifications of the same event type based on the listening event type. - /// - /// generic delegate. - /// Event handler. - /// Event args. - void Dispatch(object sender, EventArgs eventArgs) where TDelegate : Delegate; - - /// - /// Remove all injected delegates. - /// - void Clear(); - } -} \ No newline at end of file diff --git a/src/c#/GeneralUpdate.Core/Events/MultiEventArgs/MutiAllDownloadCompletedEventArgs.cs b/src/c#/GeneralUpdate.Core/Events/MultiEventArgs/MutiAllDownloadCompletedEventArgs.cs deleted file mode 100644 index e1951169..00000000 --- a/src/c#/GeneralUpdate.Core/Events/MultiEventArgs/MutiAllDownloadCompletedEventArgs.cs +++ /dev/null @@ -1,21 +0,0 @@ -using System; -using System.Collections.Generic; - -namespace GeneralUpdate.Core.Events.MultiEventArgs -{ - public class MultiAllDownloadCompletedEventArgs : EventArgs - { - public MultiAllDownloadCompletedEventArgs() - { } - - public MultiAllDownloadCompletedEventArgs(bool isAllDownloadCompleted, IList<(object, string)> failedVersions) - { - IsAllDownloadCompleted = isAllDownloadCompleted; - FailedVersions = failedVersions; - } - - public bool IsAllDownloadCompleted { get; set; } - - public IList> FailedVersions { get; set; } - } -} \ No newline at end of file diff --git a/src/c#/GeneralUpdate.Core/Events/MultiEventArgs/MutiDownloadCompletedEventArgs.cs b/src/c#/GeneralUpdate.Core/Events/MultiEventArgs/MutiDownloadCompletedEventArgs.cs deleted file mode 100644 index cdf8bd3e..00000000 --- a/src/c#/GeneralUpdate.Core/Events/MultiEventArgs/MutiDownloadCompletedEventArgs.cs +++ /dev/null @@ -1,19 +0,0 @@ -using System; -using System.ComponentModel; - -namespace GeneralUpdate.Core.Events.MultiEventArgs -{ - public class MultiDownloadCompletedEventArgs : AsyncCompletedEventArgs - { - public MultiDownloadCompletedEventArgs(Exception error, bool cancelled, object userState) : base(error, cancelled, userState) - { - } - - public MultiDownloadCompletedEventArgs(object version, Exception error, bool cancelled, object userState) : base(error, cancelled, userState) - { - Version = version; - } - - public object Version { get; set; } - } -} \ No newline at end of file diff --git a/src/c#/GeneralUpdate.Core/Events/MultiEventArgs/MutiDownloadErrorEventArgs.cs b/src/c#/GeneralUpdate.Core/Events/MultiEventArgs/MutiDownloadErrorEventArgs.cs deleted file mode 100644 index dbecc3ea..00000000 --- a/src/c#/GeneralUpdate.Core/Events/MultiEventArgs/MutiDownloadErrorEventArgs.cs +++ /dev/null @@ -1,17 +0,0 @@ -using System; - -namespace GeneralUpdate.Core.Events.MultiEventArgs -{ - public class MultiDownloadErrorEventArgs : EventArgs - { - public MultiDownloadErrorEventArgs(Exception exception, object version) - { - Exception = exception; - Version = version; - } - - public Exception Exception { get; set; } - - public object Version { get; set; } - } -} \ No newline at end of file diff --git a/src/c#/GeneralUpdate.Core/Events/MultiEventArgs/MutiDownloadProgressChangedEventArgs.cs b/src/c#/GeneralUpdate.Core/Events/MultiEventArgs/MutiDownloadProgressChangedEventArgs.cs deleted file mode 100644 index 08dc8e35..00000000 --- a/src/c#/GeneralUpdate.Core/Events/MultiEventArgs/MutiDownloadProgressChangedEventArgs.cs +++ /dev/null @@ -1,55 +0,0 @@ -using GeneralUpdate.Core.Domain.Enum; -using System; - -namespace GeneralUpdate.Core.Events.MultiEventArgs -{ - public class MultiDownloadProgressChangedEventArgs : EventArgs - { - public MultiDownloadProgressChangedEventArgs(long bytesReceived, long totalBytesToReceive, float progressPercentage, object userState) - { - BytesReceived = bytesReceived; - TotalBytesToReceive = totalBytesToReceive; - ProgressPercentage = progressPercentage; - UserState = userState; - } - - public MultiDownloadProgressChangedEventArgs(object version, long bytesReceived, long totalBytesToReceive, float progressPercentage, object userState, string message = null) - { - BytesReceived = bytesReceived; - TotalBytesToReceive = totalBytesToReceive; - ProgressPercentage = progressPercentage; - UserState = userState; - Version = version; - Message = message; - } - - public MultiDownloadProgressChangedEventArgs(object version, string message) - { - Version = version; - Message = message; - } - - public MultiDownloadProgressChangedEventArgs(object version, ProgressType type, string message) - { - Version = version; - Type = type; - Message = message; - } - - public ProgressType Type { get; set; } - - public long BytesReceived { get; private set; } - - public long TotalBytesToReceive { get; private set; } - - public float ProgressPercentage { get; private set; } - - public object UserState { get; set; } - - public object Version { get; private set; } - - public string Message { get; private set; } - - public double ProgressValue { get; set; } - } -} \ No newline at end of file diff --git a/src/c#/GeneralUpdate.Core/Events/MultiEventArgs/MutiDownloadStatisticsEventArgs.cs b/src/c#/GeneralUpdate.Core/Events/MultiEventArgs/MutiDownloadStatisticsEventArgs.cs deleted file mode 100644 index 183c6b72..00000000 --- a/src/c#/GeneralUpdate.Core/Events/MultiEventArgs/MutiDownloadStatisticsEventArgs.cs +++ /dev/null @@ -1,20 +0,0 @@ -using System; - -namespace GeneralUpdate.Core.Events.MultiEventArgs -{ - public class MultiDownloadStatisticsEventArgs : EventArgs - { - public object Version { get; set; } - - public DateTime Remaining { get; set; } - - public string Speed { get; set; } - - public MultiDownloadStatisticsEventArgs(object version, DateTime remaining, string speed) - { - Version = version ?? throw new ArgumentNullException(nameof(version)); - Remaining = remaining; - Speed = speed ?? throw new ArgumentNullException(nameof(speed)); - } - } -} \ No newline at end of file diff --git a/src/c#/GeneralUpdate.Core/Events/OSSArgs/OSSDownloadArgs.cs b/src/c#/GeneralUpdate.Core/Events/OSSArgs/OSSDownloadArgs.cs deleted file mode 100644 index 44cb3264..00000000 --- a/src/c#/GeneralUpdate.Core/Events/OSSArgs/OSSDownloadArgs.cs +++ /dev/null @@ -1,23 +0,0 @@ -using System; - -namespace GeneralUpdate.Core.Events.OSSArgs -{ - public class OSSDownloadArgs : EventArgs - { - /// - /// The number of file bytes read when the file was downloaded. - /// - public long ReadLength { get; set; } - - /// - /// The total number of bytes of the file that needs to be downloaded. - /// - public long TotalLength { get; set; } - - public OSSDownloadArgs(long readLength, long totalLength) - { - ReadLength = readLength; - TotalLength = totalLength; - } - } -} \ No newline at end of file diff --git a/src/c#/GeneralUpdate.Core/Exceptions/CustomArgs/ExceptionArgs.cs b/src/c#/GeneralUpdate.Core/Exceptions/CustomArgs/ExceptionArgs.cs deleted file mode 100644 index fac82b79..00000000 --- a/src/c#/GeneralUpdate.Core/Exceptions/CustomArgs/ExceptionArgs.cs +++ /dev/null @@ -1,11 +0,0 @@ -using System; - -namespace GeneralUpdate.Core.Exceptions.CustomArgs -{ - [Serializable] - public abstract class ExceptionArgs - { - public virtual string Message - { get { return String.Empty; } } - } -} \ No newline at end of file diff --git a/src/c#/GeneralUpdate.Core/Exceptions/CustomArgs/HttpExceptionArgs.cs b/src/c#/GeneralUpdate.Core/Exceptions/CustomArgs/HttpExceptionArgs.cs deleted file mode 100644 index 46d976b1..00000000 --- a/src/c#/GeneralUpdate.Core/Exceptions/CustomArgs/HttpExceptionArgs.cs +++ /dev/null @@ -1,35 +0,0 @@ -using System; - -namespace GeneralUpdate.Core.Exceptions.CustomArgs -{ - [Serializable] - public sealed class HttpExceptionArgs : ExceptionArgs - { - private readonly String _url, _errorMessage; - private readonly int _code; - - public HttpExceptionArgs(String url, int code, string errorMessage) - { - _url = url; - _code = code; - _errorMessage = errorMessage; - } - - public String Url - { get { return _url; } } - - public String ErrorMessage - { get { return _errorMessage; } } - - public int Code - { get { return _code; } } - - public override string Message - { - get - { - return (_url == null) ? base.Message : $"Failed to request this address {_url} , status code {_code} , mssage : {_errorMessage}"; - } - } - } -} \ No newline at end of file diff --git a/src/c#/GeneralUpdate.Core/Exceptions/CustomArgs/PatchDirtyExceptionArgs.cs b/src/c#/GeneralUpdate.Core/Exceptions/CustomArgs/PatchDirtyExceptionArgs.cs deleted file mode 100644 index f9bb6e16..00000000 --- a/src/c#/GeneralUpdate.Core/Exceptions/CustomArgs/PatchDirtyExceptionArgs.cs +++ /dev/null @@ -1,24 +0,0 @@ -using System; - -namespace GeneralUpdate.Core.Exceptions.CustomArgs -{ - [Serializable] - public sealed class PatchDirtyExceptionArgs : ExceptionArgs - { - private readonly String _patchPath; - - public PatchDirtyExceptionArgs(String patchPath) - { _patchPath = patchPath; } - - public String PatchPath - { get { return _patchPath; } } - - public override string Message - { - get - { - return (_patchPath == null) ? base.Message : $"Patch file path {_patchPath}"; - } - } - } -} \ No newline at end of file diff --git a/src/c#/GeneralUpdate.Core/Exceptions/CustomArgs/UnZipExceptionArgs.cs b/src/c#/GeneralUpdate.Core/Exceptions/CustomArgs/UnZipExceptionArgs.cs deleted file mode 100644 index eeecb054..00000000 --- a/src/c#/GeneralUpdate.Core/Exceptions/CustomArgs/UnZipExceptionArgs.cs +++ /dev/null @@ -1,24 +0,0 @@ -using System; - -namespace GeneralUpdate.Core.Exceptions.CustomArgs -{ - [Serializable] - internal class UnZipExceptionArgs : ExceptionArgs - { - private readonly String _filePath; - - public UnZipExceptionArgs(String filePath) - { _filePath = filePath; } - - public String FilePath - { get { return _filePath; } } - - public override string Message - { - get - { - return (_filePath == null) ? base.Message : $"Unzip file failed : {_filePath} !"; - } - } - } -} \ No newline at end of file diff --git a/src/c#/GeneralUpdate.Core/Exceptions/CustomArgs/UpdateExceptionArgs.cs b/src/c#/GeneralUpdate.Core/Exceptions/CustomArgs/UpdateExceptionArgs.cs deleted file mode 100644 index 16c1fb06..00000000 --- a/src/c#/GeneralUpdate.Core/Exceptions/CustomArgs/UpdateExceptionArgs.cs +++ /dev/null @@ -1,32 +0,0 @@ -using GeneralUpdate.Core.Domain.Entity; -using System; - -namespace GeneralUpdate.Core.Exceptions.CustomArgs -{ - [Serializable] - internal class UpdateExceptionArgs : ExceptionArgs - { - private readonly VersionInfo _versionInfo; - private readonly String _excptionMessage; - - public UpdateExceptionArgs(VersionInfo info, String excptionMessage) - { - _versionInfo = info; - _excptionMessage = excptionMessage; - } - - public VersionInfo VersionInfo - { get { return _versionInfo; } } - - public String ExcptionMessage - { get { return _excptionMessage; } } - - public override string Message - { - get - { - return (_versionInfo == null) ? base.Message : $"An exception occurred updating the file {_versionInfo.Name} ,The version number is {_versionInfo.Version}. error message : {_excptionMessage} !"; - } - } - } -} \ No newline at end of file diff --git a/src/c#/GeneralUpdate.Core/Exceptions/CustomException/GeneralUpdateException.cs b/src/c#/GeneralUpdate.Core/Exceptions/CustomException/GeneralUpdateException.cs deleted file mode 100644 index 7e2d6059..00000000 --- a/src/c#/GeneralUpdate.Core/Exceptions/CustomException/GeneralUpdateException.cs +++ /dev/null @@ -1,54 +0,0 @@ -using GeneralUpdate.Core.Exceptions.CustomArgs; -using System; -using System.Runtime.Serialization; -using System.Security.Permissions; - -namespace GeneralUpdate.Core.Exceptions.CustomException -{ - /// - /// Exception of GeneralUpdate framework. - /// - [Serializable] - public sealed class GeneralUpdateException : Exception, ISerializable - where TExceptionArgs : ExceptionArgs - { - private const String c_args = "Args"; - private readonly TExceptionArgs m_args; - - public TExceptionArgs Args => m_args; - - public GeneralUpdateException(String message = null, Exception innerException = null) : this(null, message, innerException) - { - } - - public GeneralUpdateException(TExceptionArgs args, String message = null, Exception innerException = null) : base(message, innerException) => m_args = args; - - [SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.SerializationFormatter)] - private GeneralUpdateException(SerializationInfo info, StreamingContext context) : base(info, context) => m_args = (TExceptionArgs)info.GetValue(c_args, typeof(TExceptionArgs)); - - [SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.SerializationFormatter)] - public override void GetObjectData(SerializationInfo info, StreamingContext context) - { - info.AddValue(c_args, typeof(TExceptionArgs)); - base.GetObjectData(info, context); - } - - public override string Message - { - get - { - String baseMsg = base.Message; - return (m_args == null) ? baseMsg : $"{baseMsg}({m_args.Message})"; - } - } - - public override bool Equals(object obj) - { - GeneralUpdateException other = obj as GeneralUpdateException; - if (other == null) return false; - return Object.Equals(m_args, other.m_args) && base.Equals(obj); - } - - public override int GetHashCode() => base.GetHashCode(); - } -} \ No newline at end of file diff --git a/src/c#/GeneralUpdate.Core/Exceptions/ThrowExceptionUtility.cs b/src/c#/GeneralUpdate.Core/Exceptions/ThrowExceptionUtility.cs deleted file mode 100644 index 25c310d0..00000000 --- a/src/c#/GeneralUpdate.Core/Exceptions/ThrowExceptionUtility.cs +++ /dev/null @@ -1,57 +0,0 @@ -using GeneralUpdate.Core.Exceptions.CustomArgs; -using System; -using System.IO; - -namespace GeneralUpdate.Core.Exceptions -{ - internal sealed class ThrowExceptionUtility - { - public static void ThrowGeneralUpdateException(ExceptionArgs args) - => Throw(args.ToString(), args); - - #region Common - - public static void ThrowFileNotFound(string file) => Throw($"File cannot be accessed {file}!"); - - public static void ThrowIfNull(string errorMessage = null) - { - errorMessage = errorMessage ?? "Parameter cannot be null"; - Throw(errorMessage); - } - - /// - /// Checks if an object is empty and throws an exception if it is - /// - /// - /// - /// - public static void ThrowIfNull(object obj, string paramName) - { - if (obj == null) - Throw(paramName); - } - - /// - /// Checks if the string is empty or blank, and throws an exception if it is. - /// - /// - /// - /// - public static void ThrowIfNullOrWhiteSpace(string str, string paramName) - { - if (string.IsNullOrWhiteSpace(str)) - Throw("Parameter cannot be null or whitespace", paramName); - } - - /// - /// Basic method of exception declaration. - /// - /// - /// - /// - public static void Throw(string message, params object[] args) where T : Exception, new() - => throw (T)Activator.CreateInstance(typeof(T), message, args); - - #endregion Common - } -} \ No newline at end of file diff --git a/src/c#/GeneralUpdate.Core/GeneralUpdate.Core.csproj b/src/c#/GeneralUpdate.Core/GeneralUpdate.Core.csproj index cf581a51..4294f519 100644 --- a/src/c#/GeneralUpdate.Core/GeneralUpdate.Core.csproj +++ b/src/c#/GeneralUpdate.Core/GeneralUpdate.Core.csproj @@ -10,7 +10,7 @@ GeneralUpdate.ico GeneralUpdate128.png False - Copyright © 2023 + Copyright © 2024 This section describes how to upgrade client applications. Provides high-performance, low-loss, resume-breakpoint, version-by-version update, binary differential update, incremental update function, configuration file retention update and other features. https://github.com/JusterZhu/GeneralUpdate @@ -21,33 +21,10 @@ enable - - - - - - - - - - - - - + + - - - - - - - - - - - - \ No newline at end of file diff --git a/src/c#/GeneralUpdate.Core/GeneralUpdateBootstrap.cs b/src/c#/GeneralUpdate.Core/GeneralUpdateBootstrap.cs index 67913d54..0efe0a6f 100644 --- a/src/c#/GeneralUpdate.Core/GeneralUpdateBootstrap.cs +++ b/src/c#/GeneralUpdate.Core/GeneralUpdateBootstrap.cs @@ -1,42 +1,159 @@ -using GeneralUpdate.Core.Bootstrap; -using GeneralUpdate.Core.ContentProvider; -using GeneralUpdate.Core.Domain.Entity; -using GeneralUpdate.Core.Domain.Entity.Assembler; -using GeneralUpdate.Core.Domain.Enum; -using GeneralUpdate.Core.Strategys; -using System; +using System; +using System.Collections.Generic; +using System.Diagnostics; using System.IO; +using System.Runtime.InteropServices; +using System.Text; +using System.Text.Json; using System.Threading.Tasks; +using GeneralUpdate.Common.FileBasic; +using GeneralUpdate.Common.Download; +using GeneralUpdate.Common.Internal; +using GeneralUpdate.Common.Internal.Bootstrap; +using GeneralUpdate.Common.Internal.Event; +using GeneralUpdate.Common.Internal.Strategy; +using GeneralUpdate.Common.Shared.Object; +using GeneralUpdate.Core.Strategys; namespace GeneralUpdate.Core { public class GeneralUpdateBootstrap : AbstractBootstrap { - public GeneralUpdateBootstrap() : base() => Remote(); + private readonly GlobalConfigInfo _configInfo; + private IStrategy? _strategy; - /// - /// Gets values from system environment variables (ClientParameter object to base64 string). - /// - private void Remote() + public GeneralUpdateBootstrap() { - try + var json = Environment.GetEnvironmentVariable("ProcessInfo", EnvironmentVariableTarget.User); + if (string.IsNullOrWhiteSpace(json)) + throw new ArgumentException("json environment variable is not defined"); + + var processInfo = JsonSerializer.Deserialize(json); + if (processInfo == null) + throw new ArgumentException("ProcessInfo object cannot be null!"); + + _configInfo = new() { - var base64 = Environment.GetEnvironmentVariable("ProcessBase64", EnvironmentVariableTarget.User); - var processInfo = FileProvider.Deserialize(base64); - Packet = ProcessAssembler.ToPacket(processInfo); - Packet.AppType = AppType.UpgradeApp; - Packet.TempPath = $"{FileProvider.GetTempDirectory(processInfo.LastVersion)}{Path.DirectorySeparatorChar}"; - } - catch (Exception ex) + MainAppName = processInfo.AppName, + InstallPath = processInfo.InstallPath, + ClientVersion = processInfo.CurrentVersion, + LastVersion = processInfo.LastVersion, + UpdateLogUrl = processInfo.UpdateLogUrl, + Encoding = ToEncoding(processInfo.CompressEncoding), + Format = processInfo.CompressFormat, + DownloadTimeOut = processInfo.DownloadTimeOut, + AppSecretKey = processInfo.AppSecretKey, + UpdateVersions = processInfo.UpdateVersions, + TempPath = GeneralFileManager.GetTempDirectory("upgrade_temp"), + ReportUrl = processInfo.ReportUrl + }; + } + + public override async Task LaunchAsync() + { + StrategyFactory(); + var manager = new DownloadManager(_configInfo.TempPath, _configInfo.Format, _configInfo.DownloadTimeOut); + manager.MultiAllDownloadCompleted += OnMultiAllDownloadCompleted; + manager.MultiDownloadCompleted += OnMultiDownloadCompleted; + manager.MultiDownloadError += OnMultiDownloadError; + manager.MultiDownloadProgressChanged += OnMultiDownloadProgressChanged; + manager.MultiDownloadStatistics += OnMultiDownloadStatistics; + foreach (var versionInfo in _configInfo.UpdateVersions) { - throw new ArgumentException($"Client parameter json conversion failed, please check whether the parameter content is legal : {ex.Message},{ex.StackTrace}."); + manager.Add(new DownloadTask(manager, versionInfo)); } + await manager.LaunchTasksAsync(); + return this; } - /// - /// Start the update. - /// - /// - public Task LaunchTaskAsync() => Task.Run(() => base.LaunchAsync()); + #region public method + + public GeneralUpdateBootstrap SetFieldMappings(Dictionary fieldMappings) + { + _configInfo.FieldMappings = fieldMappings; + return this; + } + + public GeneralUpdateBootstrap AddListenerMultiAllDownloadCompleted( + Action callbackAction) + => AddListener(callbackAction); + + public GeneralUpdateBootstrap AddListenerMultiDownloadProgress( + Action callbackAction) + => AddListener(callbackAction); + + public GeneralUpdateBootstrap AddListenerMultiDownloadCompleted( + Action callbackAction) + => AddListener(callbackAction); + + public GeneralUpdateBootstrap AddListenerMultiDownloadError( + Action callbackAction) + => AddListener(callbackAction); + + public GeneralUpdateBootstrap AddListenerMultiDownloadStatistics( + Action callbackAction) + => AddListener(callbackAction); + + public GeneralUpdateBootstrap AddListenerException(Action callbackAction) + => AddListener(callbackAction); + + #endregion + + protected override Task ExecuteStrategyAsync()=> throw new NotImplementedException(); + + protected override void ExecuteStrategy() + { + _strategy?.Create(_configInfo); + _strategy?.Execute(); + } + + protected override GeneralUpdateBootstrap StrategyFactory() + { + if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + _strategy = new WindowsStrategy(); + else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) + _strategy = new LinuxStrategy(); + else + throw new PlatformNotSupportedException("The current operating system is not supported!"); + + return this; + } + + private GeneralUpdateBootstrap AddListener(Action callbackAction) where TArgs : EventArgs + { + Debug.Assert(callbackAction!= null); + EventManager.Instance.AddListener(callbackAction); + return this; + } + + private void OnMultiDownloadStatistics(object sender, MultiDownloadStatisticsEventArgs e) + => EventManager.Instance.Dispatch(sender, e); + + private void OnMultiDownloadProgressChanged(object sender, MultiDownloadProgressChangedEventArgs e) + => EventManager.Instance.Dispatch(sender, e); + + private void OnMultiDownloadCompleted(object sender, MultiDownloadCompletedEventArgs e) + => EventManager.Instance.Dispatch(sender, e); + + private void OnMultiDownloadError(object sender, MultiDownloadErrorEventArgs e) + => EventManager.Instance.Dispatch(sender, e); + + private void OnMultiAllDownloadCompleted(object sender, MultiAllDownloadCompletedEventArgs e) + { + EventManager.Instance.Dispatch(sender, e); + ExecuteStrategy(); + } + + private static Encoding ToEncoding(int encodingType) => encodingType switch + { + 1 => Encoding.UTF8, + 2 => Encoding.UTF7, + 3 => Encoding.UTF32, + 4 => Encoding.Unicode, + 5 => Encoding.BigEndianUnicode, + 6 => Encoding.ASCII, + 7 => Encoding.Default, + _ => throw new ArgumentException("Encoding type is not supported!") + }; } } \ No newline at end of file diff --git a/src/c#/GeneralUpdate.Core/GeneralUpdateOSS.cs b/src/c#/GeneralUpdate.Core/GeneralUpdateOSS.cs index d6525c47..55d6af4d 100644 --- a/src/c#/GeneralUpdate.Core/GeneralUpdateOSS.cs +++ b/src/c#/GeneralUpdate.Core/GeneralUpdateOSS.cs @@ -1,12 +1,14 @@ -using GeneralUpdate.Core.Domain.Entity; -using GeneralUpdate.Core.Events; -using GeneralUpdate.Core.Events.CommonArgs; -using GeneralUpdate.Core.Events.MultiEventArgs; -using GeneralUpdate.Core.Events.OSSArgs; -using GeneralUpdate.Core.Strategys; -using System; -using System.Text; +using System; +using System.Diagnostics.Contracts; +using System.Runtime.InteropServices; using System.Threading.Tasks; +using GeneralUpdate.Common.Download; +using GeneralUpdate.Common.Internal; +using GeneralUpdate.Common.Internal.Event; +using GeneralUpdate.Common.Internal.Strategy; +using GeneralUpdate.Common.Shared.Object; +using GeneralUpdate.Core.Internal; +using GeneralUpdate.Core.Strategys; namespace GeneralUpdate.Core { @@ -27,45 +29,31 @@ private GeneralUpdateOSS() /// /// /// - public static async Task Start(ParamsOSS parameter, Encoding encoding) where TStrategy : AbstractStrategy, new() + public static async Task Start(ParamsOSS parameter) { - await BaseStart(parameter, encoding); + await BaseStart(parameter); } public static void AddListenerMultiAllDownloadCompleted(Action callbackAction) - { - AddListener(callbackAction); - } + => AddListener(callbackAction); public static void AddListenerMultiDownloadProgress(Action callbackAction) - { - AddListener(callbackAction); - } + => AddListener(callbackAction); public static void AddListenerMultiDownloadCompleted(Action callbackAction) - { - AddListener(callbackAction); - } + => AddListener(callbackAction); public static void AddListenerMultiDownloadError(Action callbackAction) - { - AddListener(callbackAction); - } + => AddListener(callbackAction); public static void AddListenerMultiDownloadStatistics(Action callbackAction) - { - AddListener(callbackAction); - } + => AddListener(callbackAction); public static void AddListenerException(Action callbackAction) - { - AddListener(callbackAction); - } + => AddListener(callbackAction); public static void AddListenerDownloadConfigProcess(Action callbackAction) - { - AddListener(callbackAction); - } + => AddListener(callbackAction); #endregion Public Methods @@ -73,7 +61,8 @@ public static void AddListenerDownloadConfigProcess(Action(Action callbackAction) where TArgs : EventArgs { - if (callbackAction != null) EventManager.Instance.AddListener(callbackAction); + Contract.Requires(callbackAction != null); + EventManager.Instance.AddListener(callbackAction); } /// @@ -82,14 +71,25 @@ private static void AddListener(Action callbackAction) whe /// The class that needs to be injected with the corresponding platform update policy or inherits the abstract update policy. /// List of parameter. /// - private static async Task BaseStart(TParams parameter, Encoding encoding) where TStrategy : AbstractStrategy, new() where TParams : class + private static async Task BaseStart(ParamsOSS parameter) { - //Initializes and executes the policy. - var strategyFunc = new Func(() => new TStrategy()); - var strategy = strategyFunc(); - strategy.Create(parameter, encoding); + var strategy = StrategyFactory(); + //strategy.Create(parameter); //Implement different update strategies depending on the platform. - await strategy.ExecuteTaskAsync(); + await strategy.ExecuteAsync(); + } + + private static IStrategy StrategyFactory() + { + IStrategy strategy = null; + if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + strategy = new WindowsStrategy(); + else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) + strategy = new LinuxStrategy(); + else + throw new PlatformNotSupportedException("The current operating system is not supported!"); + + return strategy; } #endregion Private Methods diff --git a/src/c#/GeneralUpdate.Core/HashAlgorithms/HashAlgorithmBase.cs b/src/c#/GeneralUpdate.Core/HashAlgorithms/HashAlgorithmBase.cs deleted file mode 100644 index c9db372c..00000000 --- a/src/c#/GeneralUpdate.Core/HashAlgorithms/HashAlgorithmBase.cs +++ /dev/null @@ -1,32 +0,0 @@ -using GeneralUpdate.Core.Exceptions; -using System.IO; -using System.Security.Cryptography; -using System.Text; - -namespace GeneralUpdate.Core.HashAlgorithms -{ - public abstract class HashAlgorithmBase - { - public string ComputeHash(string fileName) - { - if (!File.Exists(fileName)) - ThrowExceptionUtility.ThrowFileNotFound(fileName); - - using (var hashAlgorithm = GetHashAlgorithm()) - { - using (var file = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.Read)) - { - var dataArray = hashAlgorithm.ComputeHash(file); - var stringBuilder = new StringBuilder(); - for (int i = 0; i < dataArray.Length; i++) - { - stringBuilder.Append(dataArray[i].ToString("x2")); - } - return stringBuilder.ToString(); - } - } - } - - protected abstract HashAlgorithm GetHashAlgorithm(); - } -} \ No newline at end of file diff --git a/src/c#/GeneralUpdate.Core/HashAlgorithms/Md5HashAlgorithm.cs b/src/c#/GeneralUpdate.Core/HashAlgorithms/Md5HashAlgorithm.cs deleted file mode 100644 index 65020343..00000000 --- a/src/c#/GeneralUpdate.Core/HashAlgorithms/Md5HashAlgorithm.cs +++ /dev/null @@ -1,9 +0,0 @@ -using System.Security.Cryptography; - -namespace GeneralUpdate.Core.HashAlgorithms -{ - public class Md5HashAlgorithm : HashAlgorithmBase - { - protected override HashAlgorithm GetHashAlgorithm() => MD5.Create(); - } -} \ No newline at end of file diff --git a/src/c#/GeneralUpdate.Core/HashAlgorithms/Sha1HashAlgorithm.cs b/src/c#/GeneralUpdate.Core/HashAlgorithms/Sha1HashAlgorithm.cs deleted file mode 100644 index cec89ba1..00000000 --- a/src/c#/GeneralUpdate.Core/HashAlgorithms/Sha1HashAlgorithm.cs +++ /dev/null @@ -1,9 +0,0 @@ -using System.Security.Cryptography; - -namespace GeneralUpdate.Core.HashAlgorithms -{ - public class Sha1HashAlgorithm : HashAlgorithmBase - { - protected override HashAlgorithm GetHashAlgorithm() => new SHA1Managed(); - } -} \ No newline at end of file diff --git a/src/c#/GeneralUpdate.Core/HashAlgorithms/Sha256HashAlgorithm.cs b/src/c#/GeneralUpdate.Core/HashAlgorithms/Sha256HashAlgorithm.cs deleted file mode 100644 index d6135eae..00000000 --- a/src/c#/GeneralUpdate.Core/HashAlgorithms/Sha256HashAlgorithm.cs +++ /dev/null @@ -1,9 +0,0 @@ -using System.Security.Cryptography; - -namespace GeneralUpdate.Core.HashAlgorithms -{ - public class Sha256HashAlgorithm : HashAlgorithmBase - { - protected override HashAlgorithm GetHashAlgorithm() => SHA256.Create(); - } -} \ No newline at end of file diff --git a/src/c#/GeneralUpdate.Core/Internal/OSSDownloadArgs.cs b/src/c#/GeneralUpdate.Core/Internal/OSSDownloadArgs.cs new file mode 100644 index 00000000..1e4fe03a --- /dev/null +++ b/src/c#/GeneralUpdate.Core/Internal/OSSDownloadArgs.cs @@ -0,0 +1,8 @@ +using System; + +namespace GeneralUpdate.Core.Internal; + +public class OSSDownloadArgs : EventArgs +{ + +} \ No newline at end of file diff --git a/src/c#/GeneralUpdate.Core/Pipeline/DriverMiddleware.cs b/src/c#/GeneralUpdate.Core/Pipeline/DriverMiddleware.cs new file mode 100644 index 00000000..0c17535e --- /dev/null +++ b/src/c#/GeneralUpdate.Core/Pipeline/DriverMiddleware.cs @@ -0,0 +1,51 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Runtime.InteropServices; +using System.Threading.Tasks; +using GeneralUpdate.Common; +using GeneralUpdate.Common.Internal.Pipeline; +using GeneralUpdate.Core.Driver; + +namespace GeneralUpdate.Core.Pipeline; + +/// +/// Driver update. +/// Use for Windows Vista/Windows 7/Windows 8/Windows 8.1/Windows 10/Windows 11/Windows Server 2008. +/// +public class DriverMiddleware : IMiddleware +{ + private const string FileExtension = ".inf"; + + public Task InvokeAsync(PipelineContext context) + { + return Task.Run(() => + { + var outPutPath = context.Get("DriverOutPut"); + if(string.IsNullOrWhiteSpace(outPutPath)) + return; + + var patchPath = context.Get("PatchPath"); + if(string.IsNullOrWhiteSpace(patchPath)) + return; + + var fieldMappings = context.Get>("FieldMappings"); + if(fieldMappings == null || fieldMappings.Count == 0) + return; + + var information = new DriverInformation.Builder() + .SetDriverFileExtension(FileExtension) + .SetOutPutDirectory(outPutPath) + .SetDriverDirectory(patchPath) + .SetFieldMappings(fieldMappings) + .Build(); + + var processor = new DriverProcessor(); + processor.AddCommand(new BackupDriverCommand(information)); + processor.AddCommand(new DeleteDriverCommand(information)); + processor.AddCommand(new InstallDriverCommand(information)); + processor.ProcessCommands(); + }); + } +} \ No newline at end of file diff --git a/src/c#/GeneralUpdate.Core/Pipeline/HashMiddleware.cs b/src/c#/GeneralUpdate.Core/Pipeline/HashMiddleware.cs new file mode 100644 index 00000000..b0cd0511 --- /dev/null +++ b/src/c#/GeneralUpdate.Core/Pipeline/HashMiddleware.cs @@ -0,0 +1,28 @@ +using System; +using System.Security.Cryptography; +using System.Threading.Tasks; +using GeneralUpdate.Common.HashAlgorithms; +using GeneralUpdate.Common.Internal.Pipeline; + +namespace GeneralUpdate.Core.Pipeline; + +public class HashMiddleware : IMiddleware +{ + public async Task InvokeAsync(PipelineContext context) + { + var path = context.Get("ZipFilePath"); + var hash = context.Get("Hash"); + var isVerify = await VerifyFileHash(path, hash); + if (!isVerify) throw new CryptographicException("Hash verification failed !"); + } + + private Task VerifyFileHash(string path, string hash) + { + return Task.Run(() => + { + var hashAlgorithm = new Sha256HashAlgorithm(); + var hashSha256 = hashAlgorithm.ComputeHash(path); + return string.Equals(hash, hashSha256, StringComparison.OrdinalIgnoreCase); + }); + } +} \ No newline at end of file diff --git a/src/c#/GeneralUpdate.Core/Pipeline/PatchMiddleware.cs b/src/c#/GeneralUpdate.Core/Pipeline/PatchMiddleware.cs new file mode 100644 index 00000000..fcf1b8c7 --- /dev/null +++ b/src/c#/GeneralUpdate.Core/Pipeline/PatchMiddleware.cs @@ -0,0 +1,22 @@ +using System.Collections.Generic; +using System.Threading.Tasks; +using GeneralUpdate.Common.FileBasic; +using GeneralUpdate.Common.Internal.Pipeline; +using GeneralUpdate.Differential; + +namespace GeneralUpdate.Core.Pipeline; + +public class PatchMiddleware : IMiddleware +{ + public async Task InvokeAsync(PipelineContext context) + { + var sourcePath = context.Get("SourcePath"); + var targetPath = context.Get("PatchPath"); + var blackFiles = context.Get>("BlackFiles"); + var blackFileFormats = context.Get>("BlackFileFormats"); + + BlackListManager.Instance.AddBlackFiles(blackFiles); + BlackListManager.Instance.AddBlackFileFormats(blackFileFormats); + await DifferentialCore.Instance?.Dirty(sourcePath, targetPath); + } +} \ No newline at end of file diff --git a/src/c#/GeneralUpdate.Core/Pipeline/ZipMiddleware.cs b/src/c#/GeneralUpdate.Core/Pipeline/ZipMiddleware.cs new file mode 100644 index 00000000..5c82b1f5 --- /dev/null +++ b/src/c#/GeneralUpdate.Core/Pipeline/ZipMiddleware.cs @@ -0,0 +1,49 @@ +using System; +using System.Text; +using System.Threading.Tasks; +using GeneralUpdate.Common.Internal; +using GeneralUpdate.Common.Internal.Event; +using GeneralUpdate.Common.Internal.Pipeline; +using GeneralUpdate.Zip; +using GeneralUpdate.Zip.Factory; + +namespace GeneralUpdate.Core.Pipeline; + +public class ZipMiddleware : IMiddleware +{ + public Task InvokeAsync(PipelineContext context) + { + return Task.Run(() => + { + try + { + var type = MatchType(context.Get("Format")); + var name = context.Get("Name"); + var sourcePath = context.Get("ZipFilePath"); + var destinationPath = context.Get("PatchPath"); + var encoding = context.Get("Encoding"); + + var generalZipfactory = new GeneralZipFactory(); + generalZipfactory.CompressProgress += (sender, args) => { }; + generalZipfactory.Completed += (sender, args) => { }; + generalZipfactory.CreateOperate(type, name, sourcePath, destinationPath, true, encoding); + generalZipfactory.UnZip(); + } + catch (Exception e) + { + EventManager.Instance.Dispatch(this, new ExceptionEventArgs(e, e.Message)); + } + }); + } + + private static OperationType MatchType(string extensionName) + { + var type = extensionName switch + { + ".zip" => OperationType.GZip, + ".7z" => OperationType.G7z, + _ => OperationType.None + }; + return type; + } +} \ No newline at end of file diff --git a/src/c#/GeneralUpdate.Core/Pipelines/Attributes/DynamicallyAccessedMemberTypes.cs b/src/c#/GeneralUpdate.Core/Pipelines/Attributes/DynamicallyAccessedMemberTypes.cs deleted file mode 100644 index 92d15256..00000000 --- a/src/c#/GeneralUpdate.Core/Pipelines/Attributes/DynamicallyAccessedMemberTypes.cs +++ /dev/null @@ -1,38 +0,0 @@ -using System; - -namespace GeneralUpdate.Core.Pipelines.Attributes -{ - [Flags] - internal enum DynamicallyAccessedMemberTypes - { - None = 0, - - PublicParameterlessConstructor = 0x0001, - - PublicConstructors = 0x0002 | PublicParameterlessConstructor, - - NonPublicConstructors = 0x0004, - - PublicMethods = 0x0008, - - NonPublicMethods = 0x0010, - - PublicFields = 0x0020, - - NonPublicFields = 0x0040, - - PublicNestedTypes = 0x0080, - - NonPublicNestedTypes = 0x0100, - - PublicProperties = 0x0200, - - NonPublicProperties = 0x0400, - - PublicEvents = 0x0800, - - NonPublicEvents = 0x1000, - - All = ~None - } -} \ No newline at end of file diff --git a/src/c#/GeneralUpdate.Core/Pipelines/Attributes/DynamicallyAccessedMembersAttribute.cs b/src/c#/GeneralUpdate.Core/Pipelines/Attributes/DynamicallyAccessedMembersAttribute.cs deleted file mode 100644 index d3a279f8..00000000 --- a/src/c#/GeneralUpdate.Core/Pipelines/Attributes/DynamicallyAccessedMembersAttribute.cs +++ /dev/null @@ -1,15 +0,0 @@ -using System; - -namespace GeneralUpdate.Core.Pipelines.Attributes -{ - [AttributeUsage( - AttributeTargets.Field | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter | - AttributeTargets.Parameter | AttributeTargets.Property | AttributeTargets.Method, - Inherited = false)] - internal sealed class DynamicallyAccessedMembersAttribute : Attribute - { - public DynamicallyAccessedMembersAttribute(DynamicallyAccessedMemberTypes memberTypes) => MemberTypes = memberTypes; - - public DynamicallyAccessedMemberTypes MemberTypes { get; } - } -} \ No newline at end of file diff --git a/src/c#/GeneralUpdate.Core/Pipelines/Context/BaseContext.cs b/src/c#/GeneralUpdate.Core/Pipelines/Context/BaseContext.cs deleted file mode 100644 index f00c56ca..00000000 --- a/src/c#/GeneralUpdate.Core/Pipelines/Context/BaseContext.cs +++ /dev/null @@ -1,88 +0,0 @@ -using GeneralUpdate.Core.Domain.Entity; -using System; -using System.Collections.Generic; -using System.Text; - -namespace GeneralUpdate.Core.Pipelines.Context -{ - /// - /// Pipeline common content. - /// - public class BaseContext - { - public VersionInfo Version { get; private set; } - public string Name { get; private set; } - public string ZipfilePath { get; private set; } - public string TargetPath { get; private set; } - public string SourcePath { get; private set; } - public string Format { get; private set; } - public int AppType { get; private set; } - public Encoding Encoding { get; private set; } - public List BlackFiles { get; private set; } - public List BlackFileFormats { get; private set; } - - private BaseContext() - { } - - public class Builder - { - private readonly BaseContext _context = new BaseContext(); - - public Builder SetVersion(VersionInfo version) - { - _context.Version = version ?? throw new ArgumentNullException($"{nameof(VersionInfo)} Cannot be empty"); - return this; - } - - public Builder SetZipfilePath(string zipfilePath) - { - _context.ZipfilePath = string.IsNullOrWhiteSpace(zipfilePath) ? throw new ArgumentNullException($"{nameof(zipfilePath)} Cannot be empty") : zipfilePath; - return this; - } - - public Builder SetTargetPath(string targetPath) - { - _context.TargetPath = string.IsNullOrWhiteSpace(targetPath) ? throw new ArgumentNullException($"{nameof(targetPath)} Cannot be empty") : targetPath; - return this; - } - - public Builder SetSourcePath(string sourcePath) - { - _context.SourcePath = string.IsNullOrWhiteSpace(sourcePath) ? throw new ArgumentNullException($"{nameof(sourcePath)} Cannot be empty") : sourcePath; - return this; - } - - public Builder SetFormat(string format) - { - _context.Format = string.IsNullOrWhiteSpace(format) ? throw new ArgumentNullException($"{nameof(format)} Cannot be empty") : format; - return this; - } - - public Builder SetEncoding(Encoding encoding) - { - _context.Encoding = encoding; - return this; - } - - public Builder SetBlackFiles(List files) - { - _context.BlackFiles = files; - return this; - } - - public Builder SetBlackFileFormats(List fileFormats) - { - _context.BlackFileFormats = fileFormats; - return this; - } - - public Builder SetAppType(int type) - { - _context.AppType = type; - return this; - } - - public BaseContext Build() => _context; - } - } -} \ No newline at end of file diff --git a/src/c#/GeneralUpdate.Core/Pipelines/Middleware/DriveMiddleware.cs b/src/c#/GeneralUpdate.Core/Pipelines/Middleware/DriveMiddleware.cs deleted file mode 100644 index 46f5ff3d..00000000 --- a/src/c#/GeneralUpdate.Core/Pipelines/Middleware/DriveMiddleware.cs +++ /dev/null @@ -1,76 +0,0 @@ -using GeneralUpdate.Core.Driver; -using GeneralUpdate.Core.Pipelines.Context; -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.IO; -using System.Threading.Tasks; - -namespace GeneralUpdate.Core.Pipelines.Middleware -{ - /// - /// Drive file processing class. - /// - public class DriveMiddleware : IMiddleware - { - public async Task InvokeAsync(BaseContext context, MiddlewareStack stack) - { - var drivers = GetAllDriverDirectories(context.TargetPath); - var information = new DriverInformation.Builder() - .SetInstallDirectory(Path.Combine(context.SourcePath, context.Version.ToString())) - .SetOutPutDirectory(Path.Combine(context.TargetPath, context.Version.ToString())) - .SetDriverNames(drivers) - .Build(); - - var processor = new DriverProcessor(); - processor.AddCommand(new BackupDriverCommand(information)); - processor.AddCommand(new DeleteDriverCommand(information)); - processor.AddCommand(new InstallDriverCommand(information)); - processor.ProcessCommands(); - - var node = stack.Pop(); - if (node != null) await node.Next.Invoke(context, stack); - } - - /// - /// Identifies all folders containing driver files in the specified directory and returns the directory collection. - /// - /// - /// - private List GetAllDriverDirectories(string path) - { - var driverDirectories = new HashSet(); - try - { - foreach (string filePath in Directory.GetFiles(path)) - { - if (IsDriverFile(filePath)) - driverDirectories.Add(filePath); - } - - foreach (string directory in Directory.GetDirectories(path)) - { - driverDirectories.UnionWith(GetAllDriverDirectories(directory)); - } - } - catch (UnauthorizedAccessException) - { - Trace.WriteLine("No access directory:" + path); - } - catch (PathTooLongException) - { - Trace.WriteLine("Path overlength:" + path); - } - - return new List(driverDirectories); - } - - /// - /// Match the driver installation boot file. - /// - /// - /// - private bool IsDriverFile(string filePath) => - string.Equals(Path.GetExtension(filePath), ".inf", StringComparison.OrdinalIgnoreCase); - } -} \ No newline at end of file diff --git a/src/c#/GeneralUpdate.Core/Pipelines/Middleware/HashMiddleware.cs b/src/c#/GeneralUpdate.Core/Pipelines/Middleware/HashMiddleware.cs deleted file mode 100644 index f4ba5cda..00000000 --- a/src/c#/GeneralUpdate.Core/Pipelines/Middleware/HashMiddleware.cs +++ /dev/null @@ -1,30 +0,0 @@ -using GeneralUpdate.Core.Domain.Enum; -using GeneralUpdate.Core.Events; -using GeneralUpdate.Core.Events.MultiEventArgs; -using GeneralUpdate.Core.HashAlgorithms; -using GeneralUpdate.Core.Pipelines.Context; -using System; -using System.Threading.Tasks; - -namespace GeneralUpdate.Core.Pipelines.Middleware -{ - public class HashMiddleware : IMiddleware - { - public async Task InvokeAsync(BaseContext context, MiddlewareStack stack) - { - EventManager.Instance.Dispatch>(this, new MultiDownloadProgressChangedEventArgs(context.Version, ProgressType.Hash, "Verify file MD5 code ...")); - var version = context.Version; - bool isVerify = VerifyFileHash(context.ZipfilePath, version.Hash); - if (!isVerify) throw new Exception($"The update package hash code is inconsistent ! version-{version.Version} hash-{version.Hash} ."); - var node = stack.Pop(); - if (node != null) await node.Next.Invoke(context, stack); - } - - private bool VerifyFileHash(string fileName, string hash) - { - var hashAlgorithm = new Sha256HashAlgorithm(); - var hashSha256 = hashAlgorithm.ComputeHash(fileName); - return string.Equals(hash, hashSha256, StringComparison.OrdinalIgnoreCase); - } - } -} \ No newline at end of file diff --git a/src/c#/GeneralUpdate.Core/Pipelines/Middleware/IMiddleware.cs b/src/c#/GeneralUpdate.Core/Pipelines/Middleware/IMiddleware.cs deleted file mode 100644 index 0ea34b58..00000000 --- a/src/c#/GeneralUpdate.Core/Pipelines/Middleware/IMiddleware.cs +++ /dev/null @@ -1,10 +0,0 @@ -using GeneralUpdate.Core.Pipelines.Context; -using System.Threading.Tasks; - -namespace GeneralUpdate.Core.Pipelines.Middleware -{ - public interface IMiddleware - { - Task InvokeAsync(BaseContext context, MiddlewareStack stack); - } -} \ No newline at end of file diff --git a/src/c#/GeneralUpdate.Core/Pipelines/Middleware/MiddlewareExtensions.cs b/src/c#/GeneralUpdate.Core/Pipelines/Middleware/MiddlewareExtensions.cs deleted file mode 100644 index a6363516..00000000 --- a/src/c#/GeneralUpdate.Core/Pipelines/Middleware/MiddlewareExtensions.cs +++ /dev/null @@ -1,64 +0,0 @@ -using GeneralUpdate.Core.Pipelines.Attributes; -using GeneralUpdate.Core.Pipelines.Context; -using GeneralUpdate.Core.Pipelines.MiddlewareResolver; -using GeneralUpdate.Core.Pipelines.Pipeline; -using System; -using System.Reflection; -using System.Threading.Tasks; - -namespace GeneralUpdate.Core.Pipelines.Middleware -{ - public static class MiddlewareExtensions - { - internal const string InvokeAsyncMethodName = "InvokeAsync"; - - private const DynamicallyAccessedMemberTypes MiddlewareAccessibility = - DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.PublicMethods; - - public static IPipelineBuilder UseMiddleware<[DynamicallyAccessedMembers(MiddlewareAccessibility)] TMiddleware>(this IPipelineBuilder pipeline) => pipeline.UseMiddleware(typeof(TMiddleware), true); - - public static IPipelineBuilder UseMiddlewareIf<[DynamicallyAccessedMembers(MiddlewareAccessibility)] TMiddleware>(this IPipelineBuilder pipeline, bool condition = false) => pipeline.UseMiddleware(typeof(TMiddleware), condition); - - public static IPipelineBuilder UseMiddleware( - this IPipelineBuilder pipeline, - [DynamicallyAccessedMembers(MiddlewareAccessibility)] Type middleware, bool condition) - { - if (!condition) return pipeline; - - if (!typeof(IMiddleware).IsAssignableFrom(middleware)) - throw new ArgumentException($"The middleware type must implement \"{typeof(IMiddleware)}\"."); - - var methods = middleware.GetMethods(BindingFlags.Instance | BindingFlags.Public); - MethodInfo invokeMethod = null; - foreach (var method in methods) - { - if (string.Equals(method.Name, InvokeAsyncMethodName, StringComparison.OrdinalIgnoreCase)) - { - if (method == null) throw new InvalidOperationException(InvokeAsyncMethodName); - invokeMethod = method; - break; - } - } - - if (invokeMethod is null) - throw new InvalidOperationException("No suitable method matched ."); - - if (!typeof(Task).IsAssignableFrom(invokeMethod.ReturnType)) - throw new InvalidOperationException($"The method is not an awaitable method {nameof(Task)} !"); - - var parameters = invokeMethod.GetParameters(); - if (parameters.Length == 0 || parameters[0].ParameterType != typeof(BaseContext)) - throw new InvalidOperationException($" The method parameter does not contain an {nameof(BaseContext)} type parameter !"); - - return pipeline.Use(((IMiddleware)ActivatorMiddlewareResolver.Resolve(middleware))); - } - - private readonly struct InvokeMiddlewareState - { - public InvokeMiddlewareState([DynamicallyAccessedMembers(MiddlewareAccessibility)] Type middleware) => Middleware = middleware; - - [DynamicallyAccessedMembers(MiddlewareAccessibility)] - public Type Middleware { get; } - } - } -} \ No newline at end of file diff --git a/src/c#/GeneralUpdate.Core/Pipelines/Middleware/MiddlewareStack.cs b/src/c#/GeneralUpdate.Core/Pipelines/Middleware/MiddlewareStack.cs deleted file mode 100644 index b66943ed..00000000 --- a/src/c#/GeneralUpdate.Core/Pipelines/Middleware/MiddlewareStack.cs +++ /dev/null @@ -1,62 +0,0 @@ -using GeneralUpdate.Core.Pipelines.Context; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; - -namespace GeneralUpdate.Core.Pipelines.Middleware -{ - public sealed class MiddlewareNode - { - /// - /// Go to the next middleware node. - /// - public Func Next { get; set; } - - public MiddlewareNode(Func next) => Next = next; - } - - /// - /// Middleware stack space. - /// - public sealed class MiddlewareStack - { - private int maxSize; - private MiddlewareNode[] stackArray; - private int top = -1; - - public MiddlewareStack(int maxSize) - { - this.maxSize = maxSize; - stackArray = new MiddlewareNode[maxSize]; - } - - public MiddlewareStack(IList nodes) - { - maxSize = nodes.Count; - top = maxSize - 1; - stackArray = nodes.Reverse().ToArray(); - } - - public bool IsFull() => top == maxSize - 1; - - public bool IsEmpty() => top == -1; - - /// - /// Add middleware. - /// - /// - public void Push(MiddlewareNode value) - { - if (IsFull()) return; - top++; - stackArray[top] = value; - } - - public MiddlewareNode Pop() - { - if (IsEmpty()) return null; - return stackArray[top--]; - } - } -} \ No newline at end of file diff --git a/src/c#/GeneralUpdate.Core/Pipelines/Middleware/PatchMiddleware.cs b/src/c#/GeneralUpdate.Core/Pipelines/Middleware/PatchMiddleware.cs deleted file mode 100644 index 5e1f8507..00000000 --- a/src/c#/GeneralUpdate.Core/Pipelines/Middleware/PatchMiddleware.cs +++ /dev/null @@ -1,22 +0,0 @@ -using GeneralUpdate.Core.Domain.Enum; -using GeneralUpdate.Core.Events; -using GeneralUpdate.Core.Events.MultiEventArgs; -using GeneralUpdate.Core.Pipelines.Context; -using GeneralUpdate.Differential; -using System; -using System.Threading.Tasks; - -namespace GeneralUpdate.Core.Pipelines.Middleware -{ - public class PatchMiddleware : IMiddleware - { - public async Task InvokeAsync(BaseContext context, MiddlewareStack stack) - { - EventManager.Instance.Dispatch>(this, new MultiDownloadProgressChangedEventArgs(context.Version, ProgressType.Patch, "Update patch file ...")); - DifferentialCore.Instance.SetBlocklist(context.BlackFiles, context.BlackFileFormats); - await DifferentialCore.Instance.Dirty(context.SourcePath, context.TargetPath); - var node = stack.Pop(); - if (node != null) await node.Next.Invoke(context, stack); - } - } -} \ No newline at end of file diff --git a/src/c#/GeneralUpdate.Core/Pipelines/Middleware/ZipMiddleware.cs b/src/c#/GeneralUpdate.Core/Pipelines/Middleware/ZipMiddleware.cs deleted file mode 100644 index 00402ca0..00000000 --- a/src/c#/GeneralUpdate.Core/Pipelines/Middleware/ZipMiddleware.cs +++ /dev/null @@ -1,68 +0,0 @@ -using GeneralUpdate.Core.Domain.Enum; -using GeneralUpdate.Core.Events; -using GeneralUpdate.Core.Events.CommonArgs; -using GeneralUpdate.Core.Events.MultiEventArgs; -using GeneralUpdate.Core.Pipelines.Context; -using GeneralUpdate.Zip; -using GeneralUpdate.Zip.Factory; -using System; -using System.Threading.Tasks; - -namespace GeneralUpdate.Core.Pipelines.Middleware -{ - public class ZipMiddleware : IMiddleware - { - public async Task InvokeAsync(BaseContext context, MiddlewareStack stack) - { - EventManager.Instance.Dispatch>(this, new MultiDownloadProgressChangedEventArgs(context.Version, ProgressType.Updatefile, "In the unzipped file ...")); - var version = context.Version; - bool isUnzip = UnZip(context); - if (!isUnzip) throw new Exception($"Unzip file failed , Version-{version.Version} Hash-{version.Hash} !"); - var node = stack.Pop(); - if (node != null) await node.Next.Invoke(context, stack); - } - - /// - /// UnZip - /// - /// - /// - /// - /// - protected bool UnZip(BaseContext context) - { - try - { - bool isComplated = false; - var generalZipfactory = new GeneralZipFactory(); - generalZipfactory.UnZipProgress += (sender, e) => - EventManager.Instance.Dispatch>(this, new MultiDownloadProgressChangedEventArgs(context.Version, ProgressType.Updatefile, "Updatting file...")); - generalZipfactory.Completed += (sender, e) => isComplated = true; - generalZipfactory.CreateOperate(MatchType(context.Format), context.Name, context.ZipfilePath, context.TargetPath, false, context.Encoding). - UnZip(); - return isComplated; - } - catch (Exception exception) - { - EventManager.Instance.Dispatch>(this, new ExceptionEventArgs(exception)); - return false; - } - } - - private OperationType MatchType(string extensionName) - { - OperationType type = OperationType.None; - switch (extensionName) - { - case ".zip": - type = OperationType.GZip; - break; - - case ".7z": - type = OperationType.G7z; - break; - } - return type; - } - } -} \ No newline at end of file diff --git a/src/c#/GeneralUpdate.Core/Pipelines/MiddlewareResolver/ActivatorMiddlewareResolver.cs b/src/c#/GeneralUpdate.Core/Pipelines/MiddlewareResolver/ActivatorMiddlewareResolver.cs deleted file mode 100644 index 55f2c79f..00000000 --- a/src/c#/GeneralUpdate.Core/Pipelines/MiddlewareResolver/ActivatorMiddlewareResolver.cs +++ /dev/null @@ -1,9 +0,0 @@ -using System; - -namespace GeneralUpdate.Core.Pipelines.MiddlewareResolver -{ - public class ActivatorMiddlewareResolver - { - public static object Resolve(Type type) => Activator.CreateInstance(type); - } -} \ No newline at end of file diff --git a/src/c#/GeneralUpdate.Core/Pipelines/Pipeline/IPipelineBuilder.cs b/src/c#/GeneralUpdate.Core/Pipelines/Pipeline/IPipelineBuilder.cs deleted file mode 100644 index 11c0e49b..00000000 --- a/src/c#/GeneralUpdate.Core/Pipelines/Pipeline/IPipelineBuilder.cs +++ /dev/null @@ -1,21 +0,0 @@ -using GeneralUpdate.Core.Pipelines.Middleware; -using System.Threading.Tasks; - -namespace GeneralUpdate.Core.Pipelines.Pipeline -{ - public interface IPipelineBuilder - { - /// - /// reference middleware. - /// - /// - /// - IPipelineBuilder Use(IMiddleware middleware); - - /// - /// start the pipeline. - /// - /// - Task Build(); - } -} \ No newline at end of file diff --git a/src/c#/GeneralUpdate.Core/Pipelines/PipelineBuilder.cs b/src/c#/GeneralUpdate.Core/Pipelines/PipelineBuilder.cs deleted file mode 100644 index 27531958..00000000 --- a/src/c#/GeneralUpdate.Core/Pipelines/PipelineBuilder.cs +++ /dev/null @@ -1,48 +0,0 @@ -using GeneralUpdate.Core.Pipelines.Context; -using GeneralUpdate.Core.Pipelines.Middleware; -using GeneralUpdate.Core.Pipelines.Pipeline; -using System; -using System.Collections.Generic; -using System.Threading.Tasks; - -namespace GeneralUpdate.Core.Pipelines -{ - public class PipelineBuilder : IPipelineBuilder where TContext : BaseContext - { - private IList nodes = new List(); - private MiddlewareStack _components; - private readonly TContext _context; - - public PipelineBuilder(TContext context) - { - if (context == null) throw new ArgumentNullException(nameof(context)); - _context = context; - } - - /// - /// Add middleware to the stack. - /// - /// - /// - /// - public IPipelineBuilder Use(IMiddleware middleware) - { - if (middleware == null) throw new ArgumentNullException(nameof(middleware)); - nodes.Add(new MiddlewareNode(middleware.InvokeAsync)); - return this; - } - - /// - /// Start the pipeline and execute the middleware sequentially. - /// - /// - /// - public async Task Build() - { - if (nodes == null || nodes.Count == 0) throw new ArgumentNullException(nameof(nodes)); - _components = new MiddlewareStack(nodes); - await _components.Pop().Next.Invoke(_context, _components); - return this; - } - } -} \ No newline at end of file diff --git a/src/c#/GeneralUpdate.Core/Strategys/AbstractStrategy.cs b/src/c#/GeneralUpdate.Core/Strategys/AbstractStrategy.cs deleted file mode 100644 index 5b7384ec..00000000 --- a/src/c#/GeneralUpdate.Core/Strategys/AbstractStrategy.cs +++ /dev/null @@ -1,23 +0,0 @@ -using System; -using System.Text; -using System.Threading.Tasks; - -namespace GeneralUpdate.Core.Strategys -{ - public abstract class AbstractStrategy : IStrategy - { - protected const string PATCHS = "patchs"; - - public virtual void Execute() => throw new NotImplementedException(); - - public virtual bool StartApp(string appName, int appType) => throw new NotImplementedException(); - - public virtual string GetPlatform() => throw new NotImplementedException(); - - public virtual Task ExecuteTaskAsync() => throw new NotImplementedException(); - - public virtual void Create(T parameter) where T : class => throw new NotImplementedException(); - - public virtual void Create(T parameter, Encoding encoding) where T : class => throw new NotImplementedException(); - } -} \ No newline at end of file diff --git a/src/c#/GeneralUpdate.Core/Strategys/IStrategy.cs b/src/c#/GeneralUpdate.Core/Strategys/IStrategy.cs deleted file mode 100644 index cc909d51..00000000 --- a/src/c#/GeneralUpdate.Core/Strategys/IStrategy.cs +++ /dev/null @@ -1,40 +0,0 @@ -using System.Threading.Tasks; - -namespace GeneralUpdate.Core.Strategys -{ - /// - /// Update the strategy, if you need to extend it, you need to inherit this interface. - /// - public interface IStrategy - { - /// - /// Execution strategy. - /// - void Execute(); - - /// - /// After the update is complete. - /// - /// - /// - /// - bool StartApp(string appName, int appType); - - /// - /// Get the platform for the current strategy. - /// - /// - string GetPlatform(); - - /// - /// Execution strategy. - /// - Task ExecuteTaskAsync(); - - /// - /// Create a strategy. - /// - /// Abstraction for updating package information. - void Create(T parameter) where T : class; - } -} \ No newline at end of file diff --git a/src/c#/GeneralUpdate.Core/Strategys/LinuxStrategy.cs b/src/c#/GeneralUpdate.Core/Strategys/LinuxStrategy.cs new file mode 100644 index 00000000..20b18e21 --- /dev/null +++ b/src/c#/GeneralUpdate.Core/Strategys/LinuxStrategy.cs @@ -0,0 +1,8 @@ +using GeneralUpdate.Common.Internal.Strategy; + +namespace GeneralUpdate.Core.Strategys +{ + public class LinuxStrategy : AbstractStrategy + { + } +} \ No newline at end of file diff --git a/src/c#/GeneralUpdate.Core/Strategys/OSSStrategy.cs b/src/c#/GeneralUpdate.Core/Strategys/OSSStrategy.cs index 10f482ba..cac3c4ee 100644 --- a/src/c#/GeneralUpdate.Core/Strategys/OSSStrategy.cs +++ b/src/c#/GeneralUpdate.Core/Strategys/OSSStrategy.cs @@ -1,13 +1,4 @@ -using GeneralUpdate.Core.ContentProvider; -using GeneralUpdate.Core.Domain.Entity; -using GeneralUpdate.Core.Domain.Enum; -using GeneralUpdate.Core.Domain.PO; -using GeneralUpdate.Core.Domain.PO.Assembler; -using GeneralUpdate.Core.Download; -using GeneralUpdate.Core.Events; -using GeneralUpdate.Core.Events.CommonArgs; -using GeneralUpdate.Core.Events.MultiEventArgs; -using GeneralUpdate.Zip; +using GeneralUpdate.Zip; using GeneralUpdate.Zip.Factory; using System; using System.Collections.Generic; @@ -15,6 +6,12 @@ using System.IO; using System.Text; using System.Threading.Tasks; +using GeneralUpdate.Common.FileBasic; +using GeneralUpdate.Common.Download; +using GeneralUpdate.Common.Internal; +using GeneralUpdate.Common.Internal.Event; +using GeneralUpdate.Common.Internal.Strategy; +using GeneralUpdate.Common.Shared.Object; namespace GeneralUpdate.Core.Strategys { @@ -25,43 +22,42 @@ public sealed class OSSStrategy : AbstractStrategy private readonly string _appPath = AppDomain.CurrentDomain.BaseDirectory; private const string _format = ".zip"; private const int _timeOut = 60; - private ParamsOSS _parameter; + private GlobalConfigInfo _parameter; private Encoding _encoding; #endregion Private Members #region Public Methods - public override void Create(T parameter, Encoding encoding) + public override void Create(GlobalConfigInfo parameter) { - _parameter = parameter as ParamsOSS; - _encoding = encoding; + _parameter = parameter; } - public override async Task ExecuteTaskAsync() + public override async Task ExecuteAsync() { await Task.Run(() => { try { //1.Download the JSON version configuration file. - var jsonPath = Path.Combine(_appPath, _parameter.VersionFileName); + var jsonPath = Path.Combine(_appPath, "version.json"); if (!File.Exists(jsonPath)) throw new FileNotFoundException(jsonPath); //2.Parse the JSON version configuration file content. - var versions = FileProvider.GetJson>(jsonPath); + var versions = GeneralFileManager.GetJson>(jsonPath); if (versions == null) throw new NullReferenceException(nameof(versions)); //3.Download version by version according to the version of the configuration file. - var versionInfo = VersionAssembler.ToDataObjects(versions); - DownloadVersions(versionInfo); - UnZip(versionInfo); + //var versionInfo = VersionAssembler.ToDataObjects(versions); + //DownloadVersions(versionInfo); + //UnZip(versionInfo); //4.Launch the main application. LaunchApp(); } catch (Exception ex) { - EventManager.Instance.Dispatch>(this, new ExceptionEventArgs(ex)); + EventManager.Instance.Dispatch(this, new ExceptionEventArgs(ex)); } finally { @@ -80,14 +76,7 @@ await Task.Run(() => /// The collection of version information to be updated as described in the configuration file. private void DownloadVersions(List versions) { - var manager = new DownloadManager(_appPath, _format, _timeOut); - manager.MultiAllDownloadCompleted += (s, e) => EventManager.Instance.Dispatch>(this, e); - manager.MultiDownloadCompleted += (s, e) => EventManager.Instance.Dispatch>(this, e); - manager.MultiDownloadError += (s, e) => EventManager.Instance.Dispatch>(this, e); - manager.MultiDownloadProgressChanged += (s, e) => EventManager.Instance.Dispatch>(this, e); - manager.MultiDownloadStatistics += (s, e) => EventManager.Instance.Dispatch>(this, e); - versions.ForEach((v) => manager.Add(new DownloadTask(manager, v))); - manager.LaunchTaskAsync(); + //TODO: download version by version } /// @@ -111,7 +100,7 @@ private bool UnZip(List versions) var zipFilePath = Path.Combine(_appPath, $"{version.Name}.zip"); var zipFactory = new GeneralZipFactory(); zipFactory.UnZipProgress += (sender, e) => - EventManager.Instance.Dispatch>(this, new MultiDownloadProgressChangedEventArgs(version, ProgressType.Updatefile, "Updating file...")); + EventManager.Instance.Dispatch(this, new MultiDownloadProgressChangedEventArgs(version, ProgressType.Updatefile, "Updating file...")); zipFactory.Completed += (sender, e) => { isCompleted = e.IsCompleted; @@ -124,7 +113,7 @@ private bool UnZip(List versions) } catch (Exception exception) { - EventManager.Instance.Dispatch>(this, new ExceptionEventArgs(exception)); + EventManager.Instance.Dispatch(this, new ExceptionEventArgs(exception)); return false; } } diff --git a/src/c#/GeneralUpdate.Core/Strategys/PlatformLinux/LinuxStrategy.cs b/src/c#/GeneralUpdate.Core/Strategys/PlatformLinux/LinuxStrategy.cs deleted file mode 100644 index 6ac653b0..00000000 --- a/src/c#/GeneralUpdate.Core/Strategys/PlatformLinux/LinuxStrategy.cs +++ /dev/null @@ -1,24 +0,0 @@ -using GeneralUpdate.Core.Domain.Enum; - -namespace GeneralUpdate.Core.Strategys.PlatformLinux -{ - public class LinuxStrategy : AbstractStrategy - { - public override string GetPlatform() => PlatformType.Linux; - - public override void Create(T parameter) - { - base.Create(parameter); - } - - public override void Execute() - { - base.Execute(); - } - - public override bool StartApp(string appName, int appType) - { - return base.StartApp(appName, appType); - } - } -} \ No newline at end of file diff --git a/src/c#/GeneralUpdate.Core/Strategys/PlatformWindows/WindowsStrategy.cs b/src/c#/GeneralUpdate.Core/Strategys/PlatformWindows/WindowsStrategy.cs deleted file mode 100644 index 34bfcbfe..00000000 --- a/src/c#/GeneralUpdate.Core/Strategys/PlatformWindows/WindowsStrategy.cs +++ /dev/null @@ -1,161 +0,0 @@ -using GeneralUpdate.Core.ContentProvider; -using GeneralUpdate.Core.Domain.Entity; -using GeneralUpdate.Core.Domain.Enum; -using GeneralUpdate.Core.Events; -using GeneralUpdate.Core.Events.CommonArgs; -using GeneralUpdate.Core.Pipelines; -using GeneralUpdate.Core.Pipelines.Context; -using GeneralUpdate.Core.Pipelines.Middleware; -using System; -using System.Diagnostics; -using System.IO; -using System.Linq; -using System.Threading; -using System.Threading.Tasks; - -namespace GeneralUpdate.Core.Strategys.PlatformWindows -{ - /// - /// Update policy based on the Windows platform. - /// - public class WindowsStrategy : AbstractStrategy - { - #region Private Members - - protected Packet Packet { get; set; } - - #endregion Private Members - - #region Public Methods - - public override void Create(T parameter) => Packet = parameter as Packet; - - public override void Execute() - { - Task.Run(async () => - { - try - { - var updateVersions = Packet.UpdateVersions.OrderBy(x => x.PubTime).ToList(); - if (updateVersions.Count > 0) - { - foreach (var version in updateVersions) - { - var patchPath = FileProvider.GetTempDirectory(PATCHS); - var zipFilePath = Path.Combine(Packet.TempPath, $"{version.Name}{Packet.Format}"); - - var context = new BaseContext.Builder() - .SetVersion(version) - .SetZipfilePath(zipFilePath) - .SetTargetPath(patchPath) - .SetSourcePath(Packet.InstallPath) - .SetFormat(Packet.Format) - .SetEncoding(Packet.Encoding) - .SetBlackFiles(Packet.BlackFiles) - .SetBlackFileFormats(Packet.BlackFormats) - .SetAppType(Packet.AppType) - .Build(); - - var pipelineBuilder = new PipelineBuilder(context) - .UseMiddleware().UseMiddleware() - .UseMiddlewareIf(Packet.DriveEnabled) - .UseMiddleware(); - await pipelineBuilder.Build(); - } - - if (!string.IsNullOrEmpty(Packet.UpdateLogUrl)) - Process.Start("explorer.exe", Packet.UpdateLogUrl); - } - - Clear(); - StartApp(Packet.AppName, Packet.AppType); - } - catch (Exception e) - { - EventManager.Instance.Dispatch>(this, new ExceptionEventArgs(e)); - } - }); - } - - public override bool StartApp(string appName, int appType) - { - try - { - var path = Path.Combine(Packet.InstallPath, appName); - switch (appType) - { - case AppType.ClientApp: - Environment.SetEnvironmentVariable("ProcessBase64", Packet.ProcessBase64, EnvironmentVariableTarget.User); - WaitForProcessToStart(path, 20); - break; - - case AppType.UpgradeApp: - WaitForProcessToStart(path, 20); - break; - } - return true; - } - catch (Exception exception) - { - EventManager.Instance.Dispatch>(this, new ExceptionEventArgs(exception)); - return false; - } - finally - { - Process.GetCurrentProcess().Kill(); - } - } - - public override string GetPlatform() => PlatformType.Windows; - - #endregion Public Methods - - #region Private Methods - - /// - /// Remove update redundant files. - /// - /// - private bool Clear() - { - try - { - if (File.Exists(Packet.TempPath)) File.Delete(Packet.TempPath); - var dirPath = Path.GetDirectoryName(Packet.TempPath); - if (Directory.Exists(dirPath)) Directory.Delete(dirPath, true); - return true; - } - catch (Exception exception) - { - EventManager.Instance.Dispatch>(this, new ExceptionEventArgs(exception)); - return false; - } - } - - /// - /// Waits for the specified process to start within a given time. - /// - /// Process objects to monitor - /// The maximum interval for waiting for the process to start (The default value is 60 seconds). - /// - private void WaitForProcessToStart(string applicationPath, int timeout, Action callbackAction = null) - { - using (var process = Process.Start(applicationPath)) - { - var startTime = DateTime.UtcNow; - var timeSpan = TimeSpan.FromSeconds(timeout); - while (DateTime.UtcNow - startTime < timeSpan) - { - Thread.Sleep(2 * 1000); - if (!process.HasExited) - { - callbackAction?.Invoke(); - return; - } - } - } - } - - #endregion Private Methods - } -} \ No newline at end of file diff --git a/src/c#/GeneralUpdate.Core/Strategys/WindowsStrategy.cs b/src/c#/GeneralUpdate.Core/Strategys/WindowsStrategy.cs new file mode 100644 index 00000000..0ecb0a25 --- /dev/null +++ b/src/c#/GeneralUpdate.Core/Strategys/WindowsStrategy.cs @@ -0,0 +1,120 @@ +using System; +using System.Diagnostics; +using System.IO; +using System.Threading.Tasks; +using GeneralUpdate.Common.FileBasic; +using GeneralUpdate.Common.Internal; +using GeneralUpdate.Common.Internal.Event; +using GeneralUpdate.Common.Internal.Pipeline; +using GeneralUpdate.Common.Internal.Strategy; +using GeneralUpdate.Common.Shared.Object; +using GeneralUpdate.Common.Shared.Service; +using GeneralUpdate.Core.Pipeline; + +namespace GeneralUpdate.Core.Strategys +{ + /// + /// Update policy based on the Windows platform. + /// + public class WindowsStrategy : AbstractStrategy + { + private GlobalConfigInfo _configinfo = new(); + + public override void Create(GlobalConfigInfo parameter) => _configinfo = parameter; + + public override void Execute() + { + Task.Run(async () => + { + try + { + var status = 0; + var patchPath = GeneralFileManager.GetTempDirectory(PATCHS); + foreach (var version in _configinfo.UpdateVersions) + { + try + { + var context = new PipelineContext(); + //Common + context.Add("ZipFilePath", + Path.Combine(_configinfo.TempPath, $"{version.Name}{_configinfo.Format}")); + //Hash middleware + context.Add("Hash", version.Hash); + //Zip middleware + context.Add("Format", _configinfo.Format); + context.Add("Name", version.Name); + context.Add("Encoding", _configinfo.Encoding); + //Patch middleware + context.Add("SourcePath", _configinfo.InstallPath); + context.Add("PatchPath", patchPath); + context.Add("BlackFiles", BlackListManager.Instance.BlackFiles); + context.Add("BlackFileFormats", BlackListManager.Instance.BlackFileFormats); + //Driver middleware + if (_configinfo.DriveEnabled == true) + { + context.Add("DriverOutPut", GeneralFileManager.GetTempDirectory("DriverOutPut")); + context.Add("FieldMappings", _configinfo.FieldMappings); + } + + var pipelineBuilder = new PipelineBuilder(context) + .UseMiddleware() + .UseMiddleware() + .UseMiddleware() + .UseMiddlewareIf(_configinfo.DriveEnabled); + await pipelineBuilder.Build(); + } + catch (Exception e) + { + status = 3; + EventManager.Instance.Dispatch(this, new ExceptionEventArgs(e, e.Message)); + } + finally + { + await VersionService.Report(_configinfo.ReportUrl, version.RecordId, status, + version.AppType); + } + } + + if (!string.IsNullOrEmpty(_configinfo.UpdateLogUrl)) + { + OpenBrowser(_configinfo.UpdateLogUrl); + } + + Clear(patchPath); + Clear(_configinfo.TempPath); + StartApp(); + } + catch (Exception e) + { + EventManager.Instance.Dispatch(this, new ExceptionEventArgs(e, e.Message)); + } + }); + } + + public override void StartApp() + { + try + { + var appPath = Path.Combine(_configinfo.InstallPath, _configinfo.MainAppName); + if (File.Exists(appPath)) + { + Process.Start(new ProcessStartInfo + { + FileName = appPath, + UseShellExecute = true + }); + } + + Environment.SetEnvironmentVariable("ProcessInfo", null, EnvironmentVariableTarget.User); + } + catch (Exception e) + { + EventManager.Instance.Dispatch(this, new ExceptionEventArgs(e, e.Message)); + } + finally + { + Process.GetCurrentProcess().Kill(); + } + } + } +} \ No newline at end of file diff --git a/src/c#/GeneralUpdate.Differential.Test/GeneralUpdate.Differential.Test.csproj b/src/c#/GeneralUpdate.Differential.Test/GeneralUpdate.Differential.Test.csproj new file mode 100644 index 00000000..085bdddf --- /dev/null +++ b/src/c#/GeneralUpdate.Differential.Test/GeneralUpdate.Differential.Test.csproj @@ -0,0 +1,23 @@ + + + + net8.0 + enable + enable + + false + true + + + + + + + + + + + + + + diff --git a/src/c#/GeneralUpdate.Differential.Test/UnitTest1.cs b/src/c#/GeneralUpdate.Differential.Test/UnitTest1.cs new file mode 100644 index 00000000..8744088a --- /dev/null +++ b/src/c#/GeneralUpdate.Differential.Test/UnitTest1.cs @@ -0,0 +1,9 @@ +namespace GeneralUpdate.Differential.Test; + +public class UnitTest1 +{ + [Fact] + public void Test1() + { + } +} \ No newline at end of file diff --git a/src/c#/GeneralUpdate.Differential/GStream/BZip2Constants.cs b/src/c#/GeneralUpdate.Differential/Binary/BZip2Constants.cs similarity index 98% rename from src/c#/GeneralUpdate.Differential/GStream/BZip2Constants.cs rename to src/c#/GeneralUpdate.Differential/Binary/BZip2Constants.cs index ad77ca19..4bbcd70e 100644 --- a/src/c#/GeneralUpdate.Differential/GStream/BZip2Constants.cs +++ b/src/c#/GeneralUpdate.Differential/Binary/BZip2Constants.cs @@ -1,4 +1,4 @@ -namespace GeneralUpdate.Differential.GStream +namespace GeneralUpdate.Differential.Binary { internal sealed class BZip2Constants { diff --git a/src/c#/GeneralUpdate.Differential/GStream/BZip2InputStream.cs b/src/c#/GeneralUpdate.Differential/Binary/BZip2InputStream.cs similarity index 99% rename from src/c#/GeneralUpdate.Differential/GStream/BZip2InputStream.cs rename to src/c#/GeneralUpdate.Differential/Binary/BZip2InputStream.cs index 8ff23140..0f067f97 100644 --- a/src/c#/GeneralUpdate.Differential/GStream/BZip2InputStream.cs +++ b/src/c#/GeneralUpdate.Differential/Binary/BZip2InputStream.cs @@ -1,7 +1,7 @@ using System; using System.IO; -namespace GeneralUpdate.Differential.GStream +namespace GeneralUpdate.Differential.Binary { public class BZip2InputStream : Stream { diff --git a/src/c#/GeneralUpdate.Differential/GStream/BZip2OutputStream.cs b/src/c#/GeneralUpdate.Differential/Binary/BZip2OutputStream.cs similarity index 99% rename from src/c#/GeneralUpdate.Differential/GStream/BZip2OutputStream.cs rename to src/c#/GeneralUpdate.Differential/Binary/BZip2OutputStream.cs index 67d5b8c5..3096f235 100644 --- a/src/c#/GeneralUpdate.Differential/GStream/BZip2OutputStream.cs +++ b/src/c#/GeneralUpdate.Differential/Binary/BZip2OutputStream.cs @@ -1,7 +1,7 @@ using System; using System.IO; -namespace GeneralUpdate.Differential.GStream +namespace GeneralUpdate.Differential.Binary { public class BZip2OutputStream : Stream { diff --git a/src/c#/GeneralUpdate.Differential/Binary/BinaryHandle.cs b/src/c#/GeneralUpdate.Differential/Binary/BinaryHandle.cs deleted file mode 100644 index 14e334fd..00000000 --- a/src/c#/GeneralUpdate.Differential/Binary/BinaryHandle.cs +++ /dev/null @@ -1,640 +0,0 @@ -using GeneralUpdate.Differential.GStream; -using System; -using System.IO; -using System.Threading.Tasks; - -namespace GeneralUpdate.Differential.Binary -{ - /// - /// File binary differential processing. - /// - public class BinaryHandle : IBinary - { - #region Private Members - - private const long c_fileSignature = 0x3034464649445342L; - private const int c_headerSize = 32; - private string _oldfilePath, _newfilePath, _patchPath; - - #endregion Private Members - - #region Public Methods - - /// - /// Clean out the files that need to be updated and generate the update package. - /// - /// Old version file path. - /// New version file path - /// Patch file generation path. - /// - /// - public async Task Clean(string oldfilePath, string newfilePath, string patchPath) - { - _oldfilePath = oldfilePath; - _newfilePath = newfilePath; - _patchPath = patchPath; - ValidationParameters(); - try - { - await Task.Run(() => - { - using (FileStream output = new FileStream(patchPath, FileMode.Create)) - { - var oldBytes = File.ReadAllBytes(_oldfilePath); - var newBytes = File.ReadAllBytes(_newfilePath); - - /* Header is - 0 8 "BSDIFF40" - 8 8 length of bzip2ed ctrl block - 16 8 length of bzip2ed diff block - 24 8 length of new file */ - /* File is - 0 32 Header - 32 ?? Bzip2ed ctrl block - ?? ?? Bzip2ed diff block - ?? ?? Bzip2ed extra block */ - byte[] header = new byte[c_headerSize]; - WriteInt64(c_fileSignature, header, 0); // "BSDIFF40" - WriteInt64(0, header, 8); - WriteInt64(0, header, 16); - WriteInt64(newBytes.Length, header, 24); - - long startPosition = output.Position; - output.Write(header, 0, header.Length); - - int[] I = SuffixSort(oldBytes); - - byte[] db = new byte[newBytes.Length]; - byte[] eb = new byte[newBytes.Length]; - - int dblen = 0; - int eblen = 0; - - using (var bz2Stream = new BZip2OutputStream(output) { IsStreamOwner = false }) - { - // compute the differences, writing ctrl as we go - int scan = 0; - int pos = 0; - int len = 0; - int lastscan = 0; - int lastpos = 0; - int lastoffset = 0; - while (scan < newBytes.Length) - { - int oldscore = 0; - - for (int scsc = scan += len; scan < newBytes.Length; scan++) - { - len = Search(I, oldBytes, newBytes, scan, 0, oldBytes.Length, out pos); - - for (; scsc < scan + len; scsc++) - { - if ((scsc + lastoffset < oldBytes.Length) && (oldBytes[scsc + lastoffset] == newBytes[scsc])) - oldscore++; - } - - if ((len == oldscore && len != 0) || (len > oldscore + 8)) - break; - - if ((scan + lastoffset < oldBytes.Length) && (oldBytes[scan + lastoffset] == newBytes[scan])) - oldscore--; - } - - if (len != oldscore || scan == newBytes.Length) - { - int s = 0; - int sf = 0; - int lenf = 0; - for (int i = 0; (lastscan + i < scan) && (lastpos + i < oldBytes.Length);) - { - if (oldBytes[lastpos + i] == newBytes[lastscan + i]) - s++; - i++; - if (s * 2 - i > sf * 2 - lenf) - { - sf = s; - lenf = i; - } - } - - int lenb = 0; - if (scan < newBytes.Length) - { - s = 0; - int sb = 0; - for (int i = 1; (scan >= lastscan + i) && (pos >= i); i++) - { - if (oldBytes[pos - i] == newBytes[scan - i]) - s++; - if (s * 2 - i > sb * 2 - lenb) - { - sb = s; - lenb = i; - } - } - } - - if (lastscan + lenf > scan - lenb) - { - int overlap = (lastscan + lenf) - (scan - lenb); - s = 0; - int ss = 0; - int lens = 0; - for (int i = 0; i < overlap; i++) - { - if (newBytes[lastscan + lenf - overlap + i] == oldBytes[lastpos + lenf - overlap + i]) - s++; - if (newBytes[scan - lenb + i] == oldBytes[pos - lenb + i]) - s--; - if (s > ss) - { - ss = s; - lens = i + 1; - } - } - - lenf += lens - overlap; - lenb -= lens; - } - - for (int i = 0; i < lenf; i++) - db[dblen + i] = (byte)(newBytes[lastscan + i] - oldBytes[lastpos + i]); - for (int i = 0; i < (scan - lenb) - (lastscan + lenf); i++) - eb[eblen + i] = newBytes[lastscan + lenf + i]; - - dblen += lenf; - eblen += (scan - lenb) - (lastscan + lenf); - - byte[] buf = new byte[8]; - WriteInt64(lenf, buf, 0); - bz2Stream.Write(buf, 0, 8); - - WriteInt64((scan - lenb) - (lastscan + lenf), buf, 0); - bz2Stream.Write(buf, 0, 8); - - WriteInt64((pos - lenb) - (lastpos + lenf), buf, 0); - bz2Stream.Write(buf, 0, 8); - - lastscan = scan - lenb; - lastpos = pos - lenb; - lastoffset = pos - scan; - } - } - } - - // compute size of compressed ctrl data - long controlEndPosition = output.Position; - WriteInt64(controlEndPosition - startPosition - c_headerSize, header, 8); - - // write compressed diff data - using (var bz2Stream = new BZip2OutputStream(output) { IsStreamOwner = false }) - { - bz2Stream.Write(db, 0, dblen); - } - - // compute size of compressed diff data - long diffEndPosition = output.Position; - WriteInt64(diffEndPosition - controlEndPosition, header, 16); - - // write compressed extra data - using (var bz2Stream = new BZip2OutputStream(output) { IsStreamOwner = false }) - { - bz2Stream.Write(eb, 0, eblen); - } - - // seek to the beginning, write the header, then seek back to end - long endPosition = output.Position; - output.Position = startPosition; - output.Write(header, 0, header.Length); - output.Position = endPosition; - } - }); - } - catch (Exception ex) - { - throw new Exception($"Clean error : {ex.Message} !", ex.InnerException); - } - } - - /// - /// Update the patch file to the client application. - /// - /// - /// - /// - /// - /// - /// - public async Task Dirty(string oldfilePath, string newfilePath, string patchPath) - { - _oldfilePath = oldfilePath; - _newfilePath = newfilePath; - _patchPath = patchPath; - ValidationParameters(); - await Task.Run(() => - { - using (FileStream input = new FileStream(_oldfilePath, FileMode.Open, FileAccess.Read, FileShare.Read)) - { - using (FileStream output = new FileStream(_newfilePath, FileMode.Create)) - { - Func openPatchStream = () => new FileStream(patchPath, FileMode.Open, FileAccess.Read, FileShare.Read); - //File format: - // 0 8 "BSDIFF40" - // 8 8 X - // 16 8 Y - // 24 8 sizeof(newfile) - // 32 X bzip2(control block) - // 32 + X Y bzip2(diff block) - // 32 + X + Y ??? bzip2(extra block) - //with control block a set of triples(x, y, z) meaning "add x bytes - //from oldfile to x bytes from the diff block; copy y bytes from the - //extra block; seek forwards in oldfile by z bytes". - // read header - long controlLength, diffLength, newSize; - using (Stream patchStream = openPatchStream()) - { - // check patch stream capabilities - if (!patchStream.CanRead) - throw new ArgumentException("Patch stream must be readable.", "openPatchStream"); - if (!patchStream.CanSeek) - throw new ArgumentException("Patch stream must be seekable.", "openPatchStream"); - - byte[] header = ReadExactly(patchStream, c_headerSize); - - // check for appropriate magic - long signature = ReadInt64(header, 0); - if (signature != c_fileSignature) - throw new InvalidOperationException("Corrupt patch."); - - // read lengths from header - controlLength = ReadInt64(header, 8); - diffLength = ReadInt64(header, 16); - newSize = ReadInt64(header, 24); - if (controlLength < 0 || diffLength < 0 || newSize < 0) - throw new InvalidOperationException("Corrupt patch."); - } - - // preallocate buffers for reading and writing - const int c_bufferSize = 1048576; - byte[] newData = new byte[c_bufferSize]; - byte[] oldData = new byte[c_bufferSize]; - - // prepare to read three parts of the patch in parallel - using (Stream compressedControlStream = openPatchStream()) - using (Stream compressedDiffStream = openPatchStream()) - using (Stream compressedExtraStream = openPatchStream()) - { - // seek to the start of each part - compressedControlStream.Seek(c_headerSize, SeekOrigin.Current); - compressedDiffStream.Seek(c_headerSize + controlLength, SeekOrigin.Current); - compressedExtraStream.Seek(c_headerSize + controlLength + diffLength, SeekOrigin.Current); - - // decompress each part (to read it) - using (BZip2InputStream controlStream = new BZip2InputStream(compressedControlStream)) - using (BZip2InputStream diffStream = new BZip2InputStream(compressedDiffStream)) - using (BZip2InputStream extraStream = new BZip2InputStream(compressedExtraStream)) - { - long[] control = new long[3]; - byte[] buffer = new byte[8]; - - int oldPosition = 0; - int newPosition = 0; - while (newPosition < newSize) - { - // read control data - for (int i = 0; i < 3; i++) - { - ReadExactly(controlStream, buffer, 0, 8); - control[i] = ReadInt64(buffer, 0); - } - - // sanity-check - if (newPosition + control[0] > newSize) - throw new InvalidOperationException("Corrupt patch."); - - // seek old file to the position that the new data is diffed against - input.Position = oldPosition; - - int bytesToCopy = (int)control[0]; - while (bytesToCopy > 0) - { - int actualBytesToCopy = Math.Min(bytesToCopy, c_bufferSize); - - // read diff string - ReadExactly(diffStream, newData, 0, actualBytesToCopy); - - // add old data to diff string - int availableInputBytes = Math.Min(actualBytesToCopy, (int)(input.Length - input.Position)); - ReadExactly(input, oldData, 0, availableInputBytes); - - for (int index = 0; index < availableInputBytes; index++) - newData[index] += oldData[index]; - - output.Write(newData, 0, actualBytesToCopy); - - // adjust counters - newPosition += actualBytesToCopy; - oldPosition += actualBytesToCopy; - bytesToCopy -= actualBytesToCopy; - } - - // sanity-check - if (newPosition + control[1] > newSize) - throw new InvalidOperationException("Corrupt patch."); - - // read extra string - bytesToCopy = (int)control[1]; - while (bytesToCopy > 0) - { - int actualBytesToCopy = Math.Min(bytesToCopy, c_bufferSize); - - ReadExactly(extraStream, newData, 0, actualBytesToCopy); - output.Write(newData, 0, actualBytesToCopy); - - newPosition += actualBytesToCopy; - bytesToCopy -= actualBytesToCopy; - } - - // adjust position - oldPosition = (int)(oldPosition + control[2]); - } - } - } - } - } - - File.Delete(_oldfilePath); - File.Move(_newfilePath, _oldfilePath); - }); - } - - #endregion Public Methods - - #region Private Methods - - private void ValidationParameters() - { - if (string.IsNullOrWhiteSpace(_oldfilePath)) throw new ArgumentNullException("'oldfilePath' This parameter cannot be empty ."); - if (string.IsNullOrWhiteSpace(_newfilePath)) throw new ArgumentNullException("'newfilePath' This parameter cannot be empty ."); - if (string.IsNullOrWhiteSpace(_patchPath)) throw new ArgumentNullException("'patchPath' This parameter cannot be empty ."); - } - - private int CompareBytes(byte[] left, int leftOffset, byte[] right, int rightOffset) - { - for (int index = 0; index < left.Length - leftOffset && index < right.Length - rightOffset; index++) - { - int diff = left[index + leftOffset] - right[index + rightOffset]; - if (diff != 0) return diff; - } - return 0; - } - - private int MatchLength(byte[] oldBytes, int oldOffset, byte[] newBytes, int newOffset) - { - int i; - for (i = 0; i < oldBytes.Length - oldOffset && i < newBytes.Length - newOffset; i++) - { - if (oldBytes[i + oldOffset] != newBytes[i + newOffset]) - break; - } - return i; - } - - private int Search(int[] I, byte[] oldBytes, byte[] newBytes, int newOffset, int start, int end, out int pos) - { - if (end - start < 2) - { - int startLength = MatchLength(oldBytes, I[start], newBytes, newOffset); - int endLength = MatchLength(oldBytes, I[end], newBytes, newOffset); - - if (startLength > endLength) - { - pos = I[start]; - return startLength; - } - else - { - pos = I[end]; - return endLength; - } - } - else - { - int midPoint = start + (end - start) / 2; - return CompareBytes(oldBytes, I[midPoint], newBytes, newOffset) < 0 ? - Search(I, oldBytes, newBytes, newOffset, midPoint, end, out pos) : - Search(I, oldBytes, newBytes, newOffset, start, midPoint, out pos); - } - } - - private void Split(int[] I, int[] v, int start, int len, int h) - { - if (len < 16) - { - int j; - for (int k = start; k < start + len; k += j) - { - j = 1; - int x = v[I[k] + h]; - for (int i = 1; k + i < start + len; i++) - { - if (v[I[k + i] + h] < x) - { - x = v[I[k + i] + h]; - j = 0; - } - if (v[I[k + i] + h] == x) - { - Swap(ref I[k + j], ref I[k + i]); - j++; - } - } - for (int i = 0; i < j; i++) - v[I[k + i]] = k + j - 1; - if (j == 1) - I[k] = -1; - } - } - else - { - int x = v[I[start + len / 2] + h]; - int jj = 0; - int kk = 0; - for (int i2 = start; i2 < start + len; i2++) - { - if (v[I[i2] + h] < x) jj++; - if (v[I[i2] + h] == x) kk++; - } - jj += start; - kk += jj; - - int i = start; - int j = 0; - int k = 0; - while (i < jj) - { - if (v[I[i] + h] < x) - { - i++; - } - else if (v[I[i] + h] == x) - { - Swap(ref I[i], ref I[jj + j]); - j++; - } - else - { - Swap(ref I[i], ref I[kk + k]); - k++; - } - } - - while (jj + j < kk) - { - if (v[I[jj + j] + h] == x) - { - j++; - } - else - { - Swap(ref I[jj + j], ref I[kk + k]); - k++; - } - } - - if (jj > start) Split(I, v, start, jj - start, h); - - for (i = 0; i < kk - jj; i++) - v[I[jj + i]] = kk - 1; - if (jj == kk - 1) I[jj] = -1; - - if (start + len > kk) Split(I, v, kk, start + len - kk, h); - } - } - - private int[] SuffixSort(byte[] oldBytes) - { - int[] buckets = new int[256]; - foreach (byte oldByte in oldBytes) - buckets[oldByte]++; - for (int i = 1; i < 256; i++) - buckets[i] += buckets[i - 1]; - for (int i = 255; i > 0; i--) - buckets[i] = buckets[i - 1]; - buckets[0] = 0; - - int[] I = new int[oldBytes.Length + 1]; - for (int i = 0; i < oldBytes.Length; i++) - I[++buckets[oldBytes[i]]] = i; - - int[] v = new int[oldBytes.Length + 1]; - for (int i = 0; i < oldBytes.Length; i++) - v[i] = buckets[oldBytes[i]]; - - for (int i = 1; i < 256; i++) - if (buckets[i] == buckets[i - 1] + 1) I[buckets[i]] = -1; - I[0] = -1; - for (int h = 1; I[0] != -(oldBytes.Length + 1); h += h) - { - int len = 0; - int i = 0; - while (i < oldBytes.Length + 1) - { - if (I[i] < 0) - { - len -= I[i]; - i -= I[i]; - } - else - { - if (len != 0) I[i - len] = -len; - len = v[I[i]] + 1 - i; - Split(I, v, i, len, h); - i += len; - len = 0; - } - } - if (len != 0) I[i - len] = -len; - } - - for (int i = 0; i < oldBytes.Length + 1; i++) - I[v[i]] = i; - - return I; - } - - private void Swap(ref int first, ref int second) - { - int temp = first; - first = second; - second = temp; - } - - private long ReadInt64(byte[] buf, int offset) - { - long value = buf[offset + 7] & 0x7F; - for (int index = 6; index >= 0; index--) - { - value *= 256; - value += buf[offset + index]; - } - if ((buf[offset + 7] & 0x80) != 0) value = -value; - return value; - } - - private void WriteInt64(long value, byte[] buf, int offset) - { - long valueToWrite = value < 0 ? -value : value; - for (int byteIndex = 0; byteIndex < 8; byteIndex++) - { - buf[offset + byteIndex] = unchecked((byte)valueToWrite); - valueToWrite >>= 8; - } - if (value < 0) buf[offset + 7] |= 0x80; - } - - /// - /// Reads exactly bytes from . - /// - /// The stream to read from. - /// The count of bytes to read. - /// A new byte array containing the data read from the stream. - private byte[] ReadExactly(Stream stream, int count) - { - if (count < 0) throw new ArgumentOutOfRangeException("count"); - byte[] buffer = new byte[count]; - ReadExactly(stream, buffer, 0, count); - return buffer; - } - - /// - /// Reads exactly bytes from into - /// , starting at the byte given by . - /// - /// The stream to read from. - /// The buffer to read data into. - /// The offset within the buffer at which data is first written. - /// The count of bytes to read. - private void ReadExactly(Stream stream, byte[] buffer, int offset, int count) - { - // check arguments - if (stream == null) throw new ArgumentNullException("stream"); - if (buffer == null) throw new ArgumentNullException("buffer"); - if (offset < 0 || offset > buffer.Length) throw new ArgumentOutOfRangeException("offset"); - if (count < 0 || buffer.Length - offset < count) throw new ArgumentOutOfRangeException("count"); - - while (count > 0) - { - // read data - int bytesRead = stream.Read(buffer, offset, count); - // check for failure to read - if (bytesRead == 0) throw new EndOfStreamException(); - // move to next block - offset += bytesRead; - count -= bytesRead; - } - } - - #endregion Private Methods - } -} \ No newline at end of file diff --git a/src/c#/GeneralUpdate.Differential/Binary/BinaryHandler.cs b/src/c#/GeneralUpdate.Differential/Binary/BinaryHandler.cs index 6247a5bb..7938f222 100644 --- a/src/c#/GeneralUpdate.Differential/Binary/BinaryHandler.cs +++ b/src/c#/GeneralUpdate.Differential/Binary/BinaryHandler.cs @@ -1,5 +1,4 @@ -using GeneralUpdate.Differential.GStream; -using System; +using System; using System.IO; using System.Threading.Tasks; @@ -12,9 +11,9 @@ public class BinaryHandler { #region Private Members - private const long FileSignature = 0x3034464649445342L; - private const int HeaderSize = 32; - private string _oldFilePath, _newFilePath, _patchPath; + private const long c_fileSignature = 0x3034464649445342L; + private const int c_headerSize = 32; + private string _oldfilePath, _newfilePath, _patchPath; #endregion Private Members @@ -23,346 +22,375 @@ public class BinaryHandler /// /// Clean out the files that need to be updated and generate the update package. /// - /// Old version file path. - /// New version file path + /// Old version file path. + /// New version file path /// Patch file generation path. /// /// - public async Task Clean(string oldFilePath, string newFilePath, string patchPath) + public async Task Clean(string oldfilePath, string newfilePath, string patchPath) { - _oldFilePath = oldFilePath; - _newFilePath = newFilePath; - _patchPath = patchPath; - ValidateParameters(); - - try - { - await Task.Run(() => GeneratePatch()); - } - catch (Exception ex) - { - throw new Exception($"Clean error: {ex.Message}", ex.InnerException); - } - } - - /// - /// Update the patch file to the client application. - /// - /// Old version file path. - /// New version file path - /// Patch file path. - /// - /// - /// - public async Task Dirty(string oldFilePath, string newFilePath, string patchPath) - { - _oldFilePath = oldFilePath; - _newFilePath = newFilePath; - _patchPath = patchPath; - ValidateParameters(); - - await Task.Run(() => ApplyPatch()); - } - - #endregion Public Methods - - #region Private Methods - - private void ValidateParameters() - { - if (string.IsNullOrWhiteSpace(_oldFilePath)) throw new ArgumentNullException(nameof(_oldFilePath), "This parameter cannot be empty."); - if (string.IsNullOrWhiteSpace(_newFilePath)) throw new ArgumentNullException(nameof(_newFilePath), "This parameter cannot be empty."); - if (string.IsNullOrWhiteSpace(_patchPath)) throw new ArgumentNullException(nameof(_patchPath), "This parameter cannot be empty."); - } - - private void GeneratePatch() - { - using (FileStream output = new FileStream(_patchPath, FileMode.Create)) + await Task.Run(() => { - var oldBytes = File.ReadAllBytes(_oldFilePath); - var newBytes = File.ReadAllBytes(_newFilePath); - - byte[] header = new byte[HeaderSize]; - WriteInt64(FileSignature, header, 0); // "BSDIFF40" - WriteInt64(0, header, 8); - WriteInt64(0, header, 16); - WriteInt64(newBytes.Length, header, 24); - - long startPosition = output.Position; - output.Write(header, 0, header.Length); - - int[] suffixArray = SuffixSort(oldBytes); - - byte[] diffBytes = new byte[newBytes.Length]; - byte[] extraBytes = new byte[newBytes.Length]; - - int diffLength = 0; - int extraLength = 0; - - using (var bz2Stream = new BZip2OutputStream(output) { IsStreamOwner = false }) + try { - ComputeDifferences(oldBytes, newBytes, suffixArray, diffBytes, extraBytes, ref diffLength, ref extraLength, bz2Stream); - } + _oldfilePath = oldfilePath; + _newfilePath = newfilePath; + _patchPath = patchPath; + ValidationParameters(); - long controlEndPosition = output.Position; - WriteInt64(controlEndPosition - startPosition - HeaderSize, header, 8); - - using (var bz2Stream = new BZip2OutputStream(output) { IsStreamOwner = false }) - { - bz2Stream.Write(diffBytes, 0, diffLength); - } + using (FileStream output = new FileStream(patchPath, FileMode.Create)) + { + var oldBytes = File.ReadAllBytes(_oldfilePath); + var newBytes = File.ReadAllBytes(_newfilePath); + + /* Header is + 0 8 "BSDIFF40" + 8 8 length of bzip2ed ctrl block + 16 8 length of bzip2ed diff block + 24 8 length of new file */ + /* File is + 0 32 Header + 32 ?? Bzip2ed ctrl block + ?? ?? Bzip2ed diff block + ?? ?? Bzip2ed extra block */ + byte[] header = new byte[c_headerSize]; + WriteInt64(c_fileSignature, header, 0); // "BSDIFF40" + WriteInt64(0, header, 8); + WriteInt64(0, header, 16); + WriteInt64(newBytes.Length, header, 24); + + long startPosition = output.Position; + output.Write(header, 0, header.Length); + + int[] I = SuffixSort(oldBytes); + + byte[] db = new byte[newBytes.Length]; + byte[] eb = new byte[newBytes.Length]; + + int dblen = 0; + int eblen = 0; + + using (var bz2Stream = new BZip2OutputStream(output) { IsStreamOwner = false }) + { + // compute the differences, writing ctrl as we go + int scan = 0; + int pos = 0; + int len = 0; + int lastscan = 0; + int lastpos = 0; + int lastoffset = 0; + while (scan < newBytes.Length) + { + int oldscore = 0; - long diffEndPosition = output.Position; - WriteInt64(diffEndPosition - controlEndPosition, header, 16); + for (int scsc = scan += len; scan < newBytes.Length; scan++) + { + len = Search(I, oldBytes, newBytes, scan, 0, oldBytes.Length, out pos); - using (var bz2Stream = new BZip2OutputStream(output) { IsStreamOwner = false }) - { - bz2Stream.Write(extraBytes, 0, extraLength); - } + for (; scsc < scan + len; scsc++) + { + if ((scsc + lastoffset < oldBytes.Length) && + (oldBytes[scsc + lastoffset] == newBytes[scsc])) + oldscore++; + } - long endPosition = output.Position; - output.Position = startPosition; - output.Write(header, 0, header.Length); - output.Position = endPosition; - } - } + if ((len == oldscore && len != 0) || (len > oldscore + 8)) + break; - private void ComputeDifferences(byte[] oldBytes, byte[] newBytes, int[] suffixArray, byte[] diffBytes, byte[] extraBytes, ref int diffLength, ref int extraLength, BZip2OutputStream bz2Stream) - { - int scan = 0; - int pos = 0; - int len = 0; - int lastScan = 0; - int lastPos = 0; - int lastOffset = 0; - - while (scan < newBytes.Length) - { - int oldScore = 0; - - for (int scsc = scan += len; scan < newBytes.Length; scan++) - { - len = Search(suffixArray, oldBytes, newBytes, scan, 0, oldBytes.Length, out pos); - - for (; scsc < scan + len; scsc++) - { - if ((scsc + lastOffset < oldBytes.Length) && (oldBytes[scsc + lastOffset] == newBytes[scsc])) - oldScore++; - } + if ((scan + lastoffset < oldBytes.Length) && + (oldBytes[scan + lastoffset] == newBytes[scan])) + oldscore--; + } - if ((len == oldScore && len != 0) || (len > oldScore + 8)) - break; + if (len != oldscore || scan == newBytes.Length) + { + int s = 0; + int sf = 0; + int lenf = 0; + for (int i = 0; (lastscan + i < scan) && (lastpos + i < oldBytes.Length);) + { + if (oldBytes[lastpos + i] == newBytes[lastscan + i]) + s++; + i++; + if (s * 2 - i > sf * 2 - lenf) + { + sf = s; + lenf = i; + } + } + + int lenb = 0; + if (scan < newBytes.Length) + { + s = 0; + int sb = 0; + for (int i = 1; (scan >= lastscan + i) && (pos >= i); i++) + { + if (oldBytes[pos - i] == newBytes[scan - i]) + s++; + if (s * 2 - i > sb * 2 - lenb) + { + sb = s; + lenb = i; + } + } + } + + if (lastscan + lenf > scan - lenb) + { + int overlap = (lastscan + lenf) - (scan - lenb); + s = 0; + int ss = 0; + int lens = 0; + for (int i = 0; i < overlap; i++) + { + if (newBytes[lastscan + lenf - overlap + i] == + oldBytes[lastpos + lenf - overlap + i]) + s++; + if (newBytes[scan - lenb + i] == oldBytes[pos - lenb + i]) + s--; + if (s > ss) + { + ss = s; + lens = i + 1; + } + } + + lenf += lens - overlap; + lenb -= lens; + } + + for (int i = 0; i < lenf; i++) + db[dblen + i] = (byte)(newBytes[lastscan + i] - oldBytes[lastpos + i]); + for (int i = 0; i < (scan - lenb) - (lastscan + lenf); i++) + eb[eblen + i] = newBytes[lastscan + lenf + i]; + + dblen += lenf; + eblen += (scan - lenb) - (lastscan + lenf); + + byte[] buf = new byte[8]; + WriteInt64(lenf, buf, 0); + bz2Stream.Write(buf, 0, 8); + + WriteInt64((scan - lenb) - (lastscan + lenf), buf, 0); + bz2Stream.Write(buf, 0, 8); + + WriteInt64((pos - lenb) - (lastpos + lenf), buf, 0); + bz2Stream.Write(buf, 0, 8); + + lastscan = scan - lenb; + lastpos = pos - lenb; + lastoffset = pos - scan; + } + } + } - if ((scan + lastOffset < oldBytes.Length) && (oldBytes[scan + lastOffset] == newBytes[scan])) - oldScore--; - } + // compute size of compressed ctrl data + long controlEndPosition = output.Position; + WriteInt64(controlEndPosition - startPosition - c_headerSize, header, 8); - if (len != oldScore || scan == newBytes.Length) - { - int s = 0; - int sf = 0; - int lenf = 0; - for (int i = 0; (lastScan + i < scan) && (lastPos + i < oldBytes.Length);) - { - if (oldBytes[lastPos + i] == newBytes[lastScan + i]) - s++; - i++; - if (s * 2 - i > sf * 2 - lenf) + // write compressed diff data + using (var bz2Stream = new BZip2OutputStream(output) { IsStreamOwner = false }) { - sf = s; - lenf = i; + bz2Stream.Write(db, 0, dblen); } - } - int lenb = 0; - if (scan < newBytes.Length) - { - s = 0; - int sb = 0; - for (int i = 1; (scan >= lastScan + i) && (pos >= i); i++) - { - if (oldBytes[pos - i] == newBytes[scan - i]) - s++; - if (s * 2 - i > sb * 2 - lenb) - { - sb = s; - lenb = i; - } - } - } + // compute size of compressed diff data + long diffEndPosition = output.Position; + WriteInt64(diffEndPosition - controlEndPosition, header, 16); - if (lastScan + lenf > scan - lenb) - { - int overlap = (lastScan + lenf) - (scan - lenb); - s = 0; - int ss = 0; - int lens = 0; - for (int i = 0; i < overlap; i++) + // write compressed extra data + using (var bz2Stream = new BZip2OutputStream(output) { IsStreamOwner = false }) { - if (newBytes[lastScan + lenf - overlap + i] == oldBytes[lastPos + lenf - overlap + i]) - s++; - if (newBytes[scan - lenb + i] == oldBytes[pos - lenb + i]) - s--; - if (s > ss) - { - ss = s; - lens = i + 1; - } + bz2Stream.Write(eb, 0, eblen); } - lenf += lens - overlap; - lenb -= lens; + // seek to the beginning, write the header, then seek back to end + long endPosition = output.Position; + output.Position = startPosition; + output.Write(header, 0, header.Length); + output.Position = endPosition; } - - for (int i = 0; i < lenf; i++) - diffBytes[diffLength + i] = (byte)(newBytes[lastScan + i] - oldBytes[lastPos + i]); - for (int i = 0; i < (scan - lenb) - (lastScan + lenf); i++) - extraBytes[extraLength + i] = newBytes[lastScan + lenf + i]; - - diffLength += lenf; - extraLength += (scan - lenb) - (lastScan + lenf); - - byte[] buffer = new byte[8]; - WriteInt64(lenf, buffer, 0); - bz2Stream.Write(buffer, 0, 8); - - WriteInt64((scan - lenb) - (lastScan + lenf), buffer, 0); - bz2Stream.Write(buffer, 0, 8); - - WriteInt64((pos - lenb) - (lastPos + lenf), buffer, 0); - bz2Stream.Write(buffer, 0, 8); - - lastScan = scan - lenb; - lastPos = pos - lenb; - lastOffset = pos - scan; } - } + catch (Exception ex) + { + throw new Exception($"Clean error : {ex.Message} !", ex.InnerException); + } + }); } - private void ApplyPatch() + /// + /// Update the patch file to the client application. + /// + /// + /// + /// + /// + /// + /// + public async Task Dirty(string oldfilePath, string newfilePath, string patchPath) { - using (FileStream input = new FileStream(_oldFilePath, FileMode.Open, FileAccess.Read, FileShare.Read)) + await Task.Run(() => { - using (FileStream output = new FileStream(_newFilePath, FileMode.Create)) + try { - Func openPatchStream = () => new FileStream(_patchPath, FileMode.Open, FileAccess.Read, FileShare.Read); - - // Read header - long controlLength, diffLength, newSize; - using (Stream patchStream = openPatchStream()) - { - // Check patch stream capabilities - if (!patchStream.CanRead) - throw new ArgumentException("Patch stream must be readable.", nameof(openPatchStream)); - if (!patchStream.CanSeek) - throw new ArgumentException("Patch stream must be seekable.", nameof(openPatchStream)); - - byte[] header = ReadExactly(patchStream, HeaderSize); - - // Check for appropriate magic - long signature = ReadInt64(header, 0); - if (signature != FileSignature) - throw new InvalidOperationException("Corrupt patch."); - - // Read lengths from header - controlLength = ReadInt64(header, 8); - diffLength = ReadInt64(header, 16); - newSize = ReadInt64(header, 24); - if (controlLength < 0 || diffLength < 0 || newSize < 0) - throw new InvalidOperationException("Corrupt patch."); - } - - // Preallocate buffers for reading and writing - const int BufferSize = 1048576; - byte[] newData = new byte[BufferSize]; - byte[] oldData = new byte[BufferSize]; - - // Prepare to read three parts of the patch in parallel - using (Stream compressedControlStream = openPatchStream()) - using (Stream compressedDiffStream = openPatchStream()) - using (Stream compressedExtraStream = openPatchStream()) + _oldfilePath = oldfilePath; + _newfilePath = newfilePath; + _patchPath = patchPath; + ValidationParameters(); + using (FileStream input = + new FileStream(_oldfilePath, FileMode.Open, FileAccess.Read, FileShare.Read)) { - // Seek to the start of each part - compressedControlStream.Seek(HeaderSize, SeekOrigin.Current); - compressedDiffStream.Seek(HeaderSize + controlLength, SeekOrigin.Current); - compressedExtraStream.Seek(HeaderSize + controlLength + diffLength, SeekOrigin.Current); - - // Decompress each part (to read it) - using (BZip2InputStream controlStream = new BZip2InputStream(compressedControlStream)) - using (BZip2InputStream diffStream = new BZip2InputStream(compressedDiffStream)) - using (BZip2InputStream extraStream = new BZip2InputStream(compressedExtraStream)) + using (FileStream output = new FileStream(_newfilePath, FileMode.Create)) { - long[] control = new long[3]; - byte[] buffer = new byte[8]; - - int oldPosition = 0; - int newPosition = 0; - while (newPosition < newSize) + Func openPatchStream = () => + new FileStream(patchPath, FileMode.Open, FileAccess.Read, FileShare.Read); + //File format: + // 0 8 "BSDIFF40" + // 8 8 X + // 16 8 Y + // 24 8 sizeof(newfile) + // 32 X bzip2(control block) + // 32 + X Y bzip2(diff block) + // 32 + X + Y ??? bzip2(extra block) + //with control block a set of triples(x, y, z) meaning "add x bytes + //from oldfile to x bytes from the diff block; copy y bytes from the + //extra block; seek forwards in oldfile by z bytes". + // read header + long controlLength, diffLength, newSize; + using (Stream patchStream = openPatchStream()) { - // Read control data - for (int i = 0; i < 3; i++) - { - ReadExactly(controlStream, buffer, 0, 8); - control[i] = ReadInt64(buffer, 0); - } - - // Sanity-check - if (newPosition + control[0] > newSize) - throw new InvalidOperationException("Corrupt patch."); - - // Seek old file to the position that the new data is diffed against - input.Position = oldPosition; - - int bytesToCopy = (int)control[0]; - while (bytesToCopy > 0) - { - int actualBytesToCopy = Math.Min(bytesToCopy, BufferSize); + // check patch stream capabilities + if (!patchStream.CanRead) + throw new ArgumentException("Patch stream must be readable.", "openPatchStream"); + if (!patchStream.CanSeek) + throw new ArgumentException("Patch stream must be seekable.", "openPatchStream"); - // Read diff string - ReadExactly(diffStream, newData, 0, actualBytesToCopy); + byte[] header = ReadExactly(patchStream, c_headerSize); - // Add old data to diff string - int availableInputBytes = Math.Min(actualBytesToCopy, (int)(input.Length - input.Position)); - ReadExactly(input, oldData, 0, availableInputBytes); - - for (int index = 0; index < availableInputBytes; index++) - newData[index] += oldData[index]; - - output.Write(newData, 0, actualBytesToCopy); - - // Adjust counters - newPosition += actualBytesToCopy; - oldPosition += actualBytesToCopy; - bytesToCopy -= actualBytesToCopy; - } - - // Sanity-check - if (newPosition + control[1] > newSize) + // check for appropriate magic + long signature = ReadInt64(header, 0); + if (signature != c_fileSignature) throw new InvalidOperationException("Corrupt patch."); - // Read extra string - bytesToCopy = (int)control[1]; - while (bytesToCopy > 0) - { - int actualBytesToCopy = Math.Min(bytesToCopy, BufferSize); + // read lengths from header + controlLength = ReadInt64(header, 8); + diffLength = ReadInt64(header, 16); + newSize = ReadInt64(header, 24); + if (controlLength < 0 || diffLength < 0 || newSize < 0) + throw new InvalidOperationException("Corrupt patch."); + } - ReadExactly(extraStream, newData, 0, actualBytesToCopy); - output.Write(newData, 0, actualBytesToCopy); + // preallocate buffers for reading and writing + const int c_bufferSize = 1048576; + byte[] newData = new byte[c_bufferSize]; + byte[] oldData = new byte[c_bufferSize]; - newPosition += actualBytesToCopy; - bytesToCopy -= actualBytesToCopy; + // prepare to read three parts of the patch in parallel + using (Stream compressedControlStream = openPatchStream()) + using (Stream compressedDiffStream = openPatchStream()) + using (Stream compressedExtraStream = openPatchStream()) + { + // seek to the start of each part + compressedControlStream.Seek(c_headerSize, SeekOrigin.Current); + compressedDiffStream.Seek(c_headerSize + controlLength, SeekOrigin.Current); + compressedExtraStream.Seek(c_headerSize + controlLength + diffLength, + SeekOrigin.Current); + + // decompress each part (to read it) + using (BZip2InputStream controlStream = new BZip2InputStream(compressedControlStream)) + using (BZip2InputStream diffStream = new BZip2InputStream(compressedDiffStream)) + using (BZip2InputStream extraStream = new BZip2InputStream(compressedExtraStream)) + { + long[] control = new long[3]; + byte[] buffer = new byte[8]; + + int oldPosition = 0; + int newPosition = 0; + while (newPosition < newSize) + { + // read control data + for (int i = 0; i < 3; i++) + { + ReadExactly(controlStream, buffer, 0, 8); + control[i] = ReadInt64(buffer, 0); + } + + // sanity-check + if (newPosition + control[0] > newSize) + throw new InvalidOperationException("Corrupt patch."); + + // seek old file to the position that the new data is diffed against + input.Position = oldPosition; + + int bytesToCopy = (int)control[0]; + while (bytesToCopy > 0) + { + int actualBytesToCopy = Math.Min(bytesToCopy, c_bufferSize); + + // read diff string + ReadExactly(diffStream, newData, 0, actualBytesToCopy); + + // add old data to diff string + int availableInputBytes = Math.Min(actualBytesToCopy, + (int)(input.Length - input.Position)); + ReadExactly(input, oldData, 0, availableInputBytes); + + for (int index = 0; index < availableInputBytes; index++) + newData[index] += oldData[index]; + + output.Write(newData, 0, actualBytesToCopy); + + // adjust counters + newPosition += actualBytesToCopy; + oldPosition += actualBytesToCopy; + bytesToCopy -= actualBytesToCopy; + } + + // sanity-check + if (newPosition + control[1] > newSize) + throw new InvalidOperationException("Corrupt patch."); + + // read extra string + bytesToCopy = (int)control[1]; + while (bytesToCopy > 0) + { + int actualBytesToCopy = Math.Min(bytesToCopy, c_bufferSize); + + ReadExactly(extraStream, newData, 0, actualBytesToCopy); + output.Write(newData, 0, actualBytesToCopy); + + newPosition += actualBytesToCopy; + bytesToCopy -= actualBytesToCopy; + } + + // adjust position + oldPosition = (int)(oldPosition + control[2]); + } } - - // Adjust position - oldPosition = (int)(oldPosition + control[2]); } } } + + File.Delete(_oldfilePath); + File.Move(_newfilePath, _oldfilePath); } - } + catch (Exception ex) + { + throw new Exception($"Dirty error : {ex.Message} !", ex.InnerException); + } + }); + } + + #endregion Public Methods - File.Delete(_oldFilePath); - File.Move(_newFilePath, _oldFilePath); + #region Private Methods + + private void ValidationParameters() + { + if (string.IsNullOrWhiteSpace(_oldfilePath)) throw new ArgumentNullException("'oldfilePath' This parameter cannot be empty ."); + if (string.IsNullOrWhiteSpace(_newfilePath)) throw new ArgumentNullException("'newfilePath' This parameter cannot be empty ."); + if (string.IsNullOrWhiteSpace(_patchPath)) throw new ArgumentNullException("'patchPath' This parameter cannot be empty ."); } private int CompareBytes(byte[] left, int leftOffset, byte[] right, int rightOffset) @@ -386,34 +414,34 @@ private int MatchLength(byte[] oldBytes, int oldOffset, byte[] newBytes, int new return i; } - private int Search(int[] suffixArray, byte[] oldBytes, byte[] newBytes, int newOffset, int start, int end, out int pos) + private int Search(int[] I, byte[] oldBytes, byte[] newBytes, int newOffset, int start, int end, out int pos) { if (end - start < 2) { - int startLength = MatchLength(oldBytes, suffixArray[start], newBytes, newOffset); - int endLength = MatchLength(oldBytes, suffixArray[end], newBytes, newOffset); + int startLength = MatchLength(oldBytes, I[start], newBytes, newOffset); + int endLength = MatchLength(oldBytes, I[end], newBytes, newOffset); if (startLength > endLength) { - pos = suffixArray[start]; + pos = I[start]; return startLength; } else { - pos = suffixArray[end]; + pos = I[end]; return endLength; } } else { int midPoint = start + (end - start) / 2; - return CompareBytes(oldBytes, suffixArray[midPoint], newBytes, newOffset) < 0 ? - Search(suffixArray, oldBytes, newBytes, newOffset, midPoint, end, out pos) : - Search(suffixArray, oldBytes, newBytes, newOffset, start, midPoint, out pos); + return CompareBytes(oldBytes, I[midPoint], newBytes, newOffset) < 0 ? + Search(I, oldBytes, newBytes, newOffset, midPoint, end, out pos) : + Search(I, oldBytes, newBytes, newOffset, start, midPoint, out pos); } } - private void Split(int[] suffixArray, int[] rankArray, int start, int len, int h) + private void Split(int[] I, int[] v, int start, int len, int h) { if (len < 16) { @@ -421,35 +449,35 @@ private void Split(int[] suffixArray, int[] rankArray, int start, int len, int h for (int k = start; k < start + len; k += j) { j = 1; - int x = rankArray[suffixArray[k] + h]; + int x = v[I[k] + h]; for (int i = 1; k + i < start + len; i++) { - if (rankArray[suffixArray[k + i] + h] < x) + if (v[I[k + i] + h] < x) { - x = rankArray[suffixArray[k + i] + h]; + x = v[I[k + i] + h]; j = 0; } - if (rankArray[suffixArray[k + i] + h] == x) + if (v[I[k + i] + h] == x) { - Swap(ref suffixArray[k + j], ref suffixArray[k + i]); + Swap(ref I[k + j], ref I[k + i]); j++; } } for (int i = 0; i < j; i++) - rankArray[suffixArray[k + i]] = k + j - 1; + v[I[k + i]] = k + j - 1; if (j == 1) - suffixArray[k] = -1; + I[k] = -1; } } else { - int x = rankArray[suffixArray[start + len / 2] + h]; + int x = v[I[start + len / 2] + h]; int jj = 0; int kk = 0; for (int i2 = start; i2 < start + len; i2++) { - if (rankArray[suffixArray[i2] + h] < x) jj++; - if (rankArray[suffixArray[i2] + h] == x) kk++; + if (v[I[i2] + h] < x) jj++; + if (v[I[i2] + h] == x) kk++; } jj += start; kk += jj; @@ -459,42 +487,42 @@ private void Split(int[] suffixArray, int[] rankArray, int start, int len, int h int k = 0; while (i < jj) { - if (rankArray[suffixArray[i] + h] < x) + if (v[I[i] + h] < x) { i++; } - else if (rankArray[suffixArray[i] + h] == x) + else if (v[I[i] + h] == x) { - Swap(ref suffixArray[i], ref suffixArray[jj + j]); + Swap(ref I[i], ref I[jj + j]); j++; } else { - Swap(ref suffixArray[i], ref suffixArray[kk + k]); + Swap(ref I[i], ref I[kk + k]); k++; } } while (jj + j < kk) { - if (rankArray[suffixArray[jj + j] + h] == x) + if (v[I[jj + j] + h] == x) { j++; } else { - Swap(ref suffixArray[jj + j], ref suffixArray[kk + k]); + Swap(ref I[jj + j], ref I[kk + k]); k++; } } - if (jj > start) Split(suffixArray, rankArray, start, jj - start, h); + if (jj > start) Split(I, v, start, jj - start, h); for (i = 0; i < kk - jj; i++) - rankArray[suffixArray[jj + i]] = kk - 1; - if (jj == kk - 1) suffixArray[jj] = -1; + v[I[jj + i]] = kk - 1; + if (jj == kk - 1) I[jj] = -1; - if (start + len > kk) Split(suffixArray, rankArray, kk, start + len -kk, h); + if (start + len > kk) Split(I, v, kk, start + len - kk, h); } } @@ -509,49 +537,51 @@ private int[] SuffixSort(byte[] oldBytes) buckets[i] = buckets[i - 1]; buckets[0] = 0; - int[] suffixArray = new int[oldBytes.Length + 1]; + int[] I = new int[oldBytes.Length + 1]; for (int i = 0; i < oldBytes.Length; i++) - suffixArray[++buckets[oldBytes[i]]] = i; + I[++buckets[oldBytes[i]]] = i; - int[] rankArray = new int[oldBytes.Length + 1]; + int[] v = new int[oldBytes.Length + 1]; for (int i = 0; i < oldBytes.Length; i++) - rankArray[i] = buckets[oldBytes[i]]; + v[i] = buckets[oldBytes[i]]; for (int i = 1; i < 256; i++) - if (buckets[i] == buckets[i - 1] + 1) suffixArray[buckets[i]] = -1; - suffixArray[0] = -1; - for (int h = 1; suffixArray[0] != -(oldBytes.Length + 1); h += h) + if (buckets[i] == buckets[i - 1] + 1) I[buckets[i]] = -1; + I[0] = -1; + for (int h = 1; I[0] != -(oldBytes.Length + 1); h += h) { int len = 0; int i = 0; while (i < oldBytes.Length + 1) { - if (suffixArray[i] < 0) + if (I[i] < 0) { - len -= suffixArray[i]; - i -= suffixArray[i]; + len -= I[i]; + i -= I[i]; } else { - if (len != 0) suffixArray[i - len] = -len; - len = rankArray[suffixArray[i]] + 1 - i; - Split(suffixArray, rankArray, i, len, h); + if (len != 0) I[i - len] = -len; + len = v[I[i]] + 1 - i; + Split(I, v, i, len, h); i += len; len = 0; } } - if (len != 0) suffixArray[i - len] = -len; + if (len != 0) I[i - len] = -len; } for (int i = 0; i < oldBytes.Length + 1; i++) - suffixArray[rankArray[i]] = i; + I[v[i]] = i; - return suffixArray; + return I; } private void Swap(ref int first, ref int second) { - (first, second) = (second, first); + int temp = first; + first = second; + second = temp; } private long ReadInt64(byte[] buf, int offset) @@ -585,7 +615,7 @@ private void WriteInt64(long value, byte[] buf, int offset) /// A new byte array containing the data read from the stream. private byte[] ReadExactly(Stream stream, int count) { - if (count < 0) throw new ArgumentOutOfRangeException(nameof(count)); + if (count < 0) throw new ArgumentOutOfRangeException("count"); byte[] buffer = new byte[count]; ReadExactly(stream, buffer, 0, count); return buffer; @@ -601,19 +631,19 @@ private byte[] ReadExactly(Stream stream, int count) /// The count of bytes to read. private void ReadExactly(Stream stream, byte[] buffer, int offset, int count) { - // Check arguments - if (stream == null) throw new ArgumentNullException(nameof(stream)); - if (buffer == null) throw new ArgumentNullException(nameof(buffer)); - if (offset < 0 || offset > buffer.Length) throw new ArgumentOutOfRangeException(nameof(offset)); - if (count < 0 || buffer.Length - offset < count) throw new ArgumentOutOfRangeException(nameof(count)); + // check arguments + if (stream == null) throw new ArgumentNullException("stream"); + if (buffer == null) throw new ArgumentNullException("buffer"); + if (offset < 0 || offset > buffer.Length) throw new ArgumentOutOfRangeException("offset"); + if (count < 0 || buffer.Length - offset < count) throw new ArgumentOutOfRangeException("count"); while (count > 0) { - // Read data + // read data int bytesRead = stream.Read(buffer, offset, count); - // Check for failure to read + // check for failure to read if (bytesRead == 0) throw new EndOfStreamException(); - // Move to next block + // move to next block offset += bytesRead; count -= bytesRead; } diff --git a/src/c#/GeneralUpdate.Differential/Binary/IBinary.cs b/src/c#/GeneralUpdate.Differential/Binary/IBinary.cs deleted file mode 100644 index 2e99f55e..00000000 --- a/src/c#/GeneralUpdate.Differential/Binary/IBinary.cs +++ /dev/null @@ -1,25 +0,0 @@ -using System.Threading.Tasks; - -namespace GeneralUpdate.Differential.Binary -{ - public interface IBinary - { - /// - /// Sort out the patch . - /// - /// The file path of the previous version . - /// Current version file path . - /// Path to generate patch file . - /// future results . - Task Clean(string oldfilePath, string newfilePath, string patchPath); - - /// - /// Restore the patch. - /// - /// The file path of the previous version . - /// Current version file path . - /// Path to generate patch file . - /// future results . - Task Dirty(string oldfilePath, string newfilePath, string patchPath); - } -} \ No newline at end of file diff --git a/src/c#/GeneralUpdate.Differential/GStream/IChecksum.cs b/src/c#/GeneralUpdate.Differential/Binary/IChecksum.cs similarity index 82% rename from src/c#/GeneralUpdate.Differential/GStream/IChecksum.cs rename to src/c#/GeneralUpdate.Differential/Binary/IChecksum.cs index c4faac39..1d77c707 100644 --- a/src/c#/GeneralUpdate.Differential/GStream/IChecksum.cs +++ b/src/c#/GeneralUpdate.Differential/Binary/IChecksum.cs @@ -1,4 +1,4 @@ -namespace GeneralUpdate.Differential.GStream +namespace GeneralUpdate.Differential.Binary { public interface IChecksum { diff --git a/src/c#/GeneralUpdate.Differential/GStream/StrangeCRC.cs b/src/c#/GeneralUpdate.Differential/Binary/StrangeCRC.cs similarity index 99% rename from src/c#/GeneralUpdate.Differential/GStream/StrangeCRC.cs rename to src/c#/GeneralUpdate.Differential/Binary/StrangeCRC.cs index 43477e92..777da013 100644 --- a/src/c#/GeneralUpdate.Differential/GStream/StrangeCRC.cs +++ b/src/c#/GeneralUpdate.Differential/Binary/StrangeCRC.cs @@ -1,6 +1,6 @@ using System; -namespace GeneralUpdate.Differential.GStream +namespace GeneralUpdate.Differential.Binary { public class StrangeCRC : IChecksum { diff --git a/src/c#/GeneralUpdate.Differential/ContentProvider/.gitkeep b/src/c#/GeneralUpdate.Differential/ContentProvider/.gitkeep deleted file mode 100644 index e69de29b..00000000 diff --git a/src/c#/GeneralUpdate.Differential/CustomAwaiter/.gitkeep b/src/c#/GeneralUpdate.Differential/CustomAwaiter/.gitkeep deleted file mode 100644 index e69de29b..00000000 diff --git a/src/c#/GeneralUpdate.Differential/DifferentialCore.cs b/src/c#/GeneralUpdate.Differential/DifferentialCore.cs index 9fd835d3..6fc05ced 100644 --- a/src/c#/GeneralUpdate.Differential/DifferentialCore.cs +++ b/src/c#/GeneralUpdate.Differential/DifferentialCore.cs @@ -1,40 +1,22 @@ -using GeneralUpdate.Core.ContentProvider; -using GeneralUpdate.Core.HashAlgorithms; -using GeneralUpdate.Differential.Binary; +using GeneralUpdate.Differential.Binary; using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Threading.Tasks; +using GeneralUpdate.Common.FileBasic; +using GeneralUpdate.Common.HashAlgorithms; namespace GeneralUpdate.Differential { public sealed class DifferentialCore { - #region Private Members - - private static readonly object _lockObj = new object(); + private static readonly object _lockObj = new (); private static DifferentialCore _instance; - /// - /// Differential file format . - /// private const string PATCH_FORMAT = ".patch"; - - /// - /// Patch catalog. - /// - private const string PATCHS = "patchs"; - - /// - /// List of files that need to be deleted. - /// private const string DELETE_FILES_NAME = "generalupdate_delete_files.json"; - #endregion Private Members - - #region Public Properties - public static DifferentialCore Instance { get @@ -53,77 +35,37 @@ public static DifferentialCore Instance } } - #endregion Public Properties - - #region Public Methods - - /// - /// Generate patch file [Cannot contain files with the same name but different extensions] . - /// - /// Previous version folder path . - /// Recent version folder path. - /// Store discovered incremental update files in a temporary directory . - /// - public async Task Clean(string sourcePath, string targetPath, string patchPath = null) + public async Task Clean(string sourcePath, string targetPath, string patchPath) { try { - if (string.IsNullOrWhiteSpace(patchPath)) - patchPath = Path.Combine(Environment.CurrentDirectory, PATCHS); - if (!Directory.Exists(patchPath)) - Directory.CreateDirectory(patchPath); - - //Take the left tree as the center to match the files that are not in the right tree . - var fileProvider = new FileProvider(); - var nodes = await fileProvider.Compare(sourcePath, targetPath); - var hashAlgorithm = new Sha256HashAlgorithm(); - - //Binary differencing of like terms . - foreach (var file in nodes.Item3) + var fileManager = new GeneralFileManager(); + var comparisonResult = fileManager.Compare(sourcePath, targetPath); + foreach (var file in comparisonResult.DifferentNodes) { - var dirSeparatorChar = Path.DirectorySeparatorChar.ToString().ToCharArray(); - var tempPath = file.FullName.Replace(targetPath, "").Replace(Path.GetFileName(file.FullName), "").TrimStart(dirSeparatorChar).TrimEnd(dirSeparatorChar); - var tempPath0 = string.Empty; - var tempDir = string.Empty; - if (string.IsNullOrEmpty(tempPath)) - { - tempDir = patchPath; - tempPath0 = Path.Combine(patchPath, $"{file.Name}{PATCH_FORMAT}"); - } - else - { - tempDir = Path.Combine(patchPath, tempPath); - if (!Directory.Exists(tempDir)) Directory.CreateDirectory(tempDir); - tempPath0 = Path.Combine(tempDir, $"{file.Name}{PATCH_FORMAT}"); - } - - var finOldFile = nodes.Item1.FirstOrDefault(i => i.Name.Equals(file.Name)); - var oldFile = finOldFile == null ? "" : finOldFile.FullName; - var newFile = file.FullName; - var extensionName = Path.GetExtension(file.FullName); - if (File.Exists(oldFile) && File.Exists(newFile) && !FileProvider.GetBlackFileFormats().Contains(extensionName)) + var tempDir = GetTempDirectory(file, targetPath, patchPath); + var oldFile = comparisonResult.LeftNodes.FirstOrDefault(i => i.Name.Equals(file.Name)); + var newFile = file; + + if (File.Exists(oldFile.FullName) && File.Exists(newFile.FullName) && string.Equals(oldFile.RelativePath, newFile.RelativePath)) { - if (hashAlgorithm.ComputeHash(oldFile) - .Equals(hashAlgorithm.ComputeHash(newFile), StringComparison.OrdinalIgnoreCase)) + if (!GeneralFileManager.HashEquals(oldFile.FullName, newFile.FullName)) { - continue; + var tempPatchPath = Path.Combine(tempDir, $"{file.Name}{PATCH_FORMAT}"); + await new BinaryHandler().Clean(oldFile.FullName, newFile.FullName, tempPatchPath); } - - //Generate the difference file to the difference directory . - await new BinaryHandle().Clean(oldFile, newFile, tempPath0); } else { - File.Copy(newFile, Path.Combine(tempDir, Path.GetFileName(newFile)), true); + File.Copy(newFile.FullName, Path.Combine(tempDir, Path.GetFileName(newFile.FullName)), true); } } - //If a file is found that needs to be deleted, a list of files is written to the update package. - var exceptFiles = (await fileProvider.Except(sourcePath, targetPath)).ToList(); - if (exceptFiles.Count != 0) + var exceptFiles = fileManager.Except(sourcePath, targetPath); + if (exceptFiles != null && exceptFiles.Any()) { var path = Path.Combine(patchPath, DELETE_FILES_NAME); - FileProvider.CreateJson(path, exceptFiles); + GeneralFileManager.CreateJson(path, exceptFiles); } } catch (Exception ex) @@ -132,58 +74,28 @@ public async Task Clean(string sourcePath, string targetPath, string patchPath = } } - /// - /// Apply patch [Cannot contain files with the same name but different extensions] . - /// - /// Client application directory . - /// Patch file path. - /// - /// public async Task Dirty(string appPath, string patchPath) { if (!Directory.Exists(appPath) || !Directory.Exists(patchPath)) return; + try { - var patchFiles = FileProvider.GetAllfiles(patchPath); - var oldFiles = FileProvider.GetAllfiles(appPath); - - //If a JSON file for the deletion list is found in the update package, it will be deleted based on its contents. - var deleteListJson = patchFiles.FirstOrDefault(i => i.Name.Equals(DELETE_FILES_NAME)); - if (deleteListJson != null) - { - var deleteFiles = FileProvider.GetJson>(deleteListJson.FullName); - var hashAlgorithm = new Sha256HashAlgorithm(); - foreach (var file in deleteFiles) - { - var resultFile = oldFiles.FirstOrDefault(i => - string.Equals(hashAlgorithm.ComputeHash(i.FullName), file.Hash, StringComparison.OrdinalIgnoreCase)); - if (resultFile == null) - { - continue; - } - if (File.Exists(resultFile.FullName)) - { - File.Delete(resultFile.FullName); - } - } - } - + var patchFiles = GeneralFileManager.GetAllfiles(patchPath); + var oldFiles = GeneralFileManager.GetAllfiles(appPath); + //Refresh the collection after deleting the file. + HandleDeleteList(patchFiles, oldFiles); + oldFiles = GeneralFileManager.GetAllfiles(appPath); foreach (var oldFile in oldFiles) { - //Only the difference file (.patch) can be updated here. var findFile = patchFiles.FirstOrDefault(f => + Path.GetFileNameWithoutExtension(f.Name).Replace(PATCH_FORMAT, "").Equals(oldFile.Name)); + + if (findFile != null && Path.GetExtension(findFile.FullName).Equals(PATCH_FORMAT)) { - var tempName = Path.GetFileNameWithoutExtension(f.Name).Replace(PATCH_FORMAT, ""); - return tempName.Equals(oldFile.Name); - }); - if (findFile != null) - { - var extensionName = Path.GetExtension(findFile.FullName); - if (!extensionName.Equals(PATCH_FORMAT)) continue; await DirtyPatch(oldFile.FullName, findFile.FullName); } } - //Update does not include files or copies configuration files. + await DirtyUnknow(appPath, patchPath); } catch (Exception ex) @@ -192,31 +104,47 @@ public async Task Dirty(string appPath, string patchPath) } } - /// - /// Set a blacklist. - /// - /// A collection of blacklist files that are skipped when updated. - /// A collection of blacklist file name extensions that are skipped on update. - public void SetBlocklist(List blackFiles, List blackFileFormats) => FileProvider.SetBlacklist(blackFiles, blackFileFormats); + #region Private Methods - #endregion Public Methods + private static string GetTempDirectory(FileNode file, string targetPath, string patchPath) + { + var tempPath = file.FullName.Replace(targetPath, "").Replace(Path.GetFileName(file.FullName), "").Trim(Path.DirectorySeparatorChar); + var tempDir = string.IsNullOrEmpty(tempPath) ? patchPath : Path.Combine(patchPath, tempPath); + Directory.CreateDirectory(tempDir); + return tempDir; + } - #region Private Methods + private void HandleDeleteList(IEnumerable patchFiles, IEnumerable oldFiles) + { + var json = patchFiles.FirstOrDefault(i => i.Name.Equals(DELETE_FILES_NAME)); + if (json == null) + return; + + var deleteFiles = GeneralFileManager.GetJson>(json.FullName); + if (deleteFiles == null) + return; + + //Match the collection of files to be deleted based on the file hash values stored in the JSON file. + var hashAlgorithm = new Sha256HashAlgorithm(); + var tempDeleteFiles = oldFiles.Where(old => deleteFiles.Any(del => del.Hash.SequenceEqual(hashAlgorithm.ComputeHash(old.FullName)))).ToList(); + foreach (var file in tempDeleteFiles) + { + if (File.Exists(file.FullName)) + { + File.Delete(file.FullName); + } + } + } - /// - /// Apply patch file . - /// - /// Client application directory . - /// - /// - /// private async Task DirtyPatch(string appPath, string patchPath) { try { - if (!File.Exists(appPath) || !File.Exists(patchPath)) return; - var newPath = Path.Combine(Path.GetDirectoryName(appPath), $"{Path.GetRandomFileName()}_{Path.GetFileName(appPath)}"); - await new BinaryHandle().Dirty(appPath, newPath, patchPath); + if (!File.Exists(appPath) || !File.Exists(patchPath)) + return; + + var newPath = Path.Combine(Path.GetDirectoryName(appPath)!, $"{Path.GetRandomFileName()}_{Path.GetFileName(appPath)}"); + await new BinaryHandler().Dirty(appPath, newPath, patchPath); } catch (Exception ex) { @@ -224,36 +152,40 @@ private async Task DirtyPatch(string appPath, string patchPath) } } - /// - /// Add new files . - /// - /// Client application directory . - /// Patch file path. private Task DirtyUnknow(string appPath, string patchPath) { try { - var fileProvider = new FileProvider(); - var listExcept = fileProvider.Comparer(appPath, patchPath); - foreach (var file in listExcept) + var fileManager = new GeneralFileManager(); + var comparisonResult = fileManager.Compare(appPath, patchPath); + foreach (var file in comparisonResult.DifferentNodes) { var extensionName = Path.GetExtension(file.FullName); - if (FileProvider.GetBlackFileFormats().Contains(extensionName)) continue; - var targetFileName = file.FullName.Replace(patchPath, "").TrimStart("\\".ToCharArray()); + if (BlackListManager.Instance.IsBlacklisted(extensionName)) continue; + + var targetFileName = file.FullName.Replace(patchPath, "").TrimStart(Path.DirectorySeparatorChar); var targetPath = Path.Combine(appPath, targetFileName); var parentFolder = Directory.GetParent(targetPath); - if (!parentFolder.Exists) parentFolder.Create(); - File.Copy(file.FullName, Path.Combine(appPath, targetPath), true); + if (parentFolder?.Exists == false) + { + parentFolder.Create(); + } + + File.Copy(file.FullName, targetPath, true); + } + + if (Directory.Exists(patchPath)) + { + Directory.Delete(patchPath, true); } - if (Directory.Exists(patchPath)) Directory.Delete(patchPath, true); return Task.CompletedTask; } catch (Exception ex) { - throw new Exception($" DirtyNew error : {ex.Message} !", ex.InnerException); + throw new Exception($"DirtyNew error : {ex.Message} !", ex.InnerException); } } - #endregion Private Methods + #endregion } } \ No newline at end of file diff --git a/src/c#/GeneralUpdate.Differential/Domain/Entity/.gitkeep b/src/c#/GeneralUpdate.Differential/Domain/Entity/.gitkeep deleted file mode 100644 index e69de29b..00000000 diff --git a/src/c#/GeneralUpdate.Differential/Domain/PO/.gitkeep b/src/c#/GeneralUpdate.Differential/Domain/PO/.gitkeep deleted file mode 100644 index e69de29b..00000000 diff --git a/src/c#/GeneralUpdate.Differential/Exceptions/.gitkeep b/src/c#/GeneralUpdate.Differential/Exceptions/.gitkeep deleted file mode 100644 index e69de29b..00000000 diff --git a/src/c#/GeneralUpdate.Differential/Exceptions/CustomArgs/.gitkeep b/src/c#/GeneralUpdate.Differential/Exceptions/CustomArgs/.gitkeep deleted file mode 100644 index e69de29b..00000000 diff --git a/src/c#/GeneralUpdate.Differential/Exceptions/CustomException/.gitkeep b/src/c#/GeneralUpdate.Differential/Exceptions/CustomException/.gitkeep deleted file mode 100644 index e69de29b..00000000 diff --git a/src/c#/GeneralUpdate.Differential/GeneralUpdate.Differential.csproj b/src/c#/GeneralUpdate.Differential/GeneralUpdate.Differential.csproj index 0efc41da..ae772653 100644 --- a/src/c#/GeneralUpdate.Differential/GeneralUpdate.Differential.csproj +++ b/src/c#/GeneralUpdate.Differential/GeneralUpdate.Differential.csproj @@ -4,7 +4,6 @@ netstandard2.0 GeneralUpdate.ico GeneralUpdate128.png - False https://github.com/JusterZhu/GeneralUpdate The binary differential update function is provided, but the configuration file update function is reserved. juster.zhu @@ -16,69 +15,11 @@ - - - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/c#/GeneralUpdate.Upgrad.Test/GeneralUpdate.Upgrad.Test.csproj b/src/c#/GeneralUpdate.Upgrad.Test/GeneralUpdate.Upgrad.Test.csproj new file mode 100644 index 00000000..085bdddf --- /dev/null +++ b/src/c#/GeneralUpdate.Upgrad.Test/GeneralUpdate.Upgrad.Test.csproj @@ -0,0 +1,23 @@ + + + + net8.0 + enable + enable + + false + true + + + + + + + + + + + + + + diff --git a/src/c#/GeneralUpdate.Upgrad.Test/UnitTest1.cs b/src/c#/GeneralUpdate.Upgrad.Test/UnitTest1.cs new file mode 100644 index 00000000..89a044d4 --- /dev/null +++ b/src/c#/GeneralUpdate.Upgrad.Test/UnitTest1.cs @@ -0,0 +1,9 @@ +namespace GeneralUpdate.Upgrad.Test; + +public class UnitTest1 +{ + [Fact] + public void Test1() + { + } +} \ No newline at end of file diff --git a/src/c#/GeneralUpdate.Upgrad/Program.cs b/src/c#/GeneralUpdate.Upgrad/Program.cs index ac3952d2..4ad1d6c0 100644 --- a/src/c#/GeneralUpdate.Upgrad/Program.cs +++ b/src/c#/GeneralUpdate.Upgrad/Program.cs @@ -1,10 +1,11 @@ -using GeneralUpdate.Core; -using GeneralUpdate.Core.Bootstrap; -using GeneralUpdate.Core.Domain.Enum; -using GeneralUpdate.Core.Events.CommonArgs; -using GeneralUpdate.Core.Events.MultiEventArgs; -using GeneralUpdate.Core.Strategys.PlatformWindows; -using System.Text; +using System.Text; +using GeneralUpdate.Common.Download; +using GeneralUpdate.Common.FileBasic; +using GeneralUpdate.Common.Internal; +using GeneralUpdate.Common.Internal.Bootstrap; +using GeneralUpdate.Common.Shared.Object; +using GeneralUpdate.Core; +using GeneralUpdate.Core.Driver; namespace GeneralUpdate.Upgrad { @@ -12,98 +13,98 @@ internal class Program { private static void Main(string[] args) { - Task.Run(async () => + //中文操作系统的驱动包字段映射表,用于解析所有驱动包的信息的字符串 + var fieldMappingsCN = new Dictionary + { + { "PublishedName", "发布名称" }, + { "OriginalName", "原始名称" }, + { "Provider", "提供程序名称" }, + { "ClassName", "类名" }, + { "ClassGUID", "类 GUID" }, + { "Version", "驱动程序版本" }, + { "Signer", "签名者姓名" } + }; + + //英文操作系统的驱动包字段映射表,用于解析所有驱动包的信息的字符串 + var fieldMappingsEN = new Dictionary { - //var url = "http://192.168.50.203"; - //var appName = "GeneralUpdate.Client"; - //var version = "1.0.0.0"; + { "PublishedName", "Driver" }, + { "OriginalName", "OriginalFileName" }, + { "Provider", "ProviderName" }, + { "ClassName", "ClassName" }, + { "Version", "Version" } + }; + + //var fileExtension = ".inf"; + //var outPutPath = @"D:\drivers\"; + //var driversPath = @"D:\driverslocal\"; - ////Part1 OSS服务示例 - //var versionFileName = "version.json"; - //ParamsOSS @params = new ParamsOSS(url, appName, version, versionFileName); - //GeneralUpdateOSS.AddListenerMultiDownloadProgress(OnMultiDownloadProgressChanged); - ////单个或多个更新包下载速度、剩余下载事件、当前下载版本信息通知事件 - //GeneralUpdateOSS.AddListenerMultiDownloadStatistics(OnMultiDownloadStatistics); - ////单个或多个更新包下载完成 - //GeneralUpdateOSS.AddListenerMultiDownloadCompleted(OnMultiDownloadCompleted); - ////完成所有的下载任务通知 - //GeneralUpdateOSS.AddListenerMultiAllDownloadCompleted(OnMultiAllDownloadCompleted); - ////下载过程出现的异常通知 - //GeneralUpdateOSS.AddListenerMultiDownloadError(OnMultiDownloadError); - ////整个更新过程出现的任何问题都会通过这个事件通知 - //GeneralUpdateOSS.AddListenerException(OnException); - //await GeneralUpdateOSS.Start(@params,Encoding.Default); + /*var information = new DriverInformation.Builder() + .SetDriverFileExtension(fileExtension) + .SetOutPutDirectory(outPutPath) + .SetDriverDirectory(driversPath) + .SetFieldMappings(fieldMappingsCN) + .Build(); - //Part 2 常规更新示例 - var bootStrap = await new GeneralUpdateBootstrap() - //单个或多个更新包下载通知事件 - .AddListenerMultiDownloadProgress(OnMultiDownloadProgressChanged) - //单个或多个更新包下载速度、剩余下载事件、当前下载版本信息通知事件 - .AddListenerMultiDownloadStatistics(OnMultiDownloadStatistics) - //单个或多个更新包下载完成 - .AddListenerMultiDownloadCompleted(OnMultiDownloadCompleted) - //完成所有的下载任务通知 - .AddListenerMultiAllDownloadCompleted(OnMultiAllDownloadCompleted) - //下载过程出现的异常通知 - .AddListenerMultiDownloadError(OnMultiDownloadError) - //整个更新过程出现的任何问题都会通过这个事件通知 - .AddListenerException(OnException) - .Strategy() - .Option(UpdateOption.Encoding, Encoding.Default) - .Option(UpdateOption.DownloadTimeOut, 60) - .Option(UpdateOption.Format, Format.ZIP) - .LaunchTaskAsync(); + var processor = new DriverProcessor(); + processor.AddCommand(new BackupDriverCommand(information)); + processor.AddCommand(new DeleteDriverCommand(information)); + processor.AddCommand(new InstallDriverCommand(information)); + processor.ProcessCommands();*/ + + Task.Run(async () => + { + Console.WriteLine("升级程序启动辣!!!!"); + await Task.Delay(3000); + + //var jsonPath = @"D:\packet\test.json"; + //var json = File.ReadAllText(jsonPath); + //Environment.SetEnvironmentVariable("ProcessInfo", json, EnvironmentVariableTarget.User); + + _ = new GeneralUpdateBootstrap() //单个或多个更新包下载通知事件 + .AddListenerMultiDownloadProgress(OnMultiDownloadProgressChanged) + //单个或多个更新包下载速度、剩余下载事件、当前下载版本信息通知事件 + .AddListenerMultiDownloadStatistics(OnMultiDownloadStatistics) + //单个或多个更新包下载完成 + .AddListenerMultiDownloadCompleted(OnMultiDownloadCompleted) + //完成所有的下载任务通知 + .AddListenerMultiAllDownloadCompleted(OnMultiAllDownloadCompleted) + //下载过程出现的异常通知 + .AddListenerMultiDownloadError(OnMultiDownloadError) + //整个更新过程出现的任何问题都会通过这个事件通知 + .AddListenerException(OnException) + //设置字段映射表,用于解析所有驱动包的信息的字符串 + //.SetFieldMappings(fieldMappingsCN) + //是否开启驱动更新 + //.Option(UpdateOption.Drive, true) + .LaunchAsync(); }); + Console.Read(); } - private static void OnMultiDownloadStatistics(object sender, MultiDownloadStatisticsEventArgs e) + private static void OnMultiDownloadError(object arg1, MultiDownloadErrorEventArgs arg2) { - Console.WriteLine($" {e.Speed} , {e.Remaining.ToShortTimeString()}"); } - private static void OnMultiDownloadProgressChanged(object sender, MultiDownloadProgressChangedEventArgs e) + private static void OnMultiAllDownloadCompleted(object arg1, MultiAllDownloadCompletedEventArgs arg2) { - switch (e.Type) - { - case ProgressType.Check: - break; - - case ProgressType.Download: - Console.WriteLine($" {Math.Round(e.ProgressValue * 100, 2)}% , Receivedbyte:{e.BytesReceived}M ,Totalbyte:{e.TotalBytesToReceive}M"); - break; - - case ProgressType.Updatefile: - break; - - case ProgressType.Done: - break; - - case ProgressType.Fail: - break; - } } - private static void OnMultiDownloadCompleted(object sender, MultiDownloadCompletedEventArgs e) + private static void OnMultiDownloadCompleted(object arg1, MultiDownloadCompletedEventArgs arg2) { - //var info = e.Version as GeneralUpdate.Core.Domain.Entity.VersionInfo; - //Console.WriteLine($"{info.Name} download completed."); } - private static void OnMultiAllDownloadCompleted(object sender, MultiAllDownloadCompletedEventArgs e) + private static void OnMultiDownloadStatistics(object arg1, MultiDownloadStatisticsEventArgs arg2) { - Console.WriteLine($"AllDownloadCompleted {e.IsAllDownloadCompleted}"); } - private static void OnMultiDownloadError(object sender, MultiDownloadErrorEventArgs e) + private static void OnMultiDownloadProgressChanged(object arg1, MultiDownloadProgressChangedEventArgs arg2) { - //var info = e.Version as GeneralUpdate.Core.Domain.Entity.VersionInfo; - //Console.WriteLine($"{info.Name},{e.Exception.Message}."); } - private static void OnException(object sender, ExceptionEventArgs e) + private static void OnException(object arg1, ExceptionEventArgs arg2) { - Console.WriteLine($"{e.Exception.Message}"); } } } \ No newline at end of file diff --git a/src/c#/GeneralUpdate.Upgrad/Properties/launchSettings.json b/src/c#/GeneralUpdate.Upgrad/Properties/launchSettings.json index ffe508a8..e1b5724e 100644 --- a/src/c#/GeneralUpdate.Upgrad/Properties/launchSettings.json +++ b/src/c#/GeneralUpdate.Upgrad/Properties/launchSettings.json @@ -2,7 +2,7 @@ "profiles": { "GeneralUpdate.Upgrad": { "commandName": "Project", - "launchBrowser": true, + "launchBrowser": false, "environmentVariables": { "ASPNETCORE_ENVIRONMENT": "Development" }, diff --git a/src/c#/GeneralUpdate.Zip.Test/GeneralUpdate.Zip.Test.csproj b/src/c#/GeneralUpdate.Zip.Test/GeneralUpdate.Zip.Test.csproj new file mode 100644 index 00000000..085bdddf --- /dev/null +++ b/src/c#/GeneralUpdate.Zip.Test/GeneralUpdate.Zip.Test.csproj @@ -0,0 +1,23 @@ + + + + net8.0 + enable + enable + + false + true + + + + + + + + + + + + + + diff --git a/src/c#/GeneralUpdate.Zip.Test/UnitTest1.cs b/src/c#/GeneralUpdate.Zip.Test/UnitTest1.cs new file mode 100644 index 00000000..0a715df0 --- /dev/null +++ b/src/c#/GeneralUpdate.Zip.Test/UnitTest1.cs @@ -0,0 +1,9 @@ +namespace GeneralUpdate.Zip.Test; + +public class UnitTest1 +{ + [Fact] + public void Test1() + { + } +} \ No newline at end of file diff --git a/src/c#/GeneralUpdate.Zip/GeneralUpdate.Zip.csproj b/src/c#/GeneralUpdate.Zip/GeneralUpdate.Zip.csproj index 7044d4d8..7438e740 100644 --- a/src/c#/GeneralUpdate.Zip/GeneralUpdate.Zip.csproj +++ b/src/c#/GeneralUpdate.Zip/GeneralUpdate.Zip.csproj @@ -23,13 +23,6 @@ - - - True - \ - - -