diff --git a/.github/workflows/dotnet-ci.yaml b/.github/workflows/dotnet-ci.yaml
index a239ad23d0f553ad2d362e269dc2f553e5835cf8..7020725481058328c92e8c3eb071e693baad2bd0 100644
--- a/.github/workflows/dotnet-ci.yaml
+++ b/.github/workflows/dotnet-ci.yaml
@@ -11,9 +11,7 @@ jobs:
- name: Setup .NET SDK
uses: actions/setup-dotnet@v2
with:
- dotnet-version: '8.0.x'
- - name: Install .NET MAUI
- run: dotnet workload install maui
+ dotnet-version: '9.0.x'
- name: Restore dependencies
run: dotnet restore ./src/c#/GeneralUpdate.sln
- name: build
diff --git a/README.md b/README.md
index 2c9d97f2b8d9682b201a0908d4d56edebde320d6..f66208c11a1168f9f96b16fa40a90da0bedb063f 100644
--- a/README.md
+++ b/README.md
@@ -2,133 +2,90 @@

-
+
[English introduction](https://github.com/JusterZhu/GeneralUpdate/blob/master/README_en.md)
## 1.组件介绍 ##
-- GeneralUpdate是一款基于.NET Standard2.0开源自动升级组件。
-- 运行环境:.NET7、.NET MAUI、Visual studio 2022(Preview)
-
-
-
-| 功能 | 是否支持 | 备注 |
-| ------------------------------ | -------- | ------------------------------------------------------------ |
-| 断点续传 | 支持 | 单次更新失败时,下次一次启动时继续上一次更新下载更新包内容。(引用组件默认生效) |
-| 逐版本更新 | 支持 | 客户端当前版本如果与服务器相差多个版本,则根据多个版本的发布日期逐个更新。(引用组件默认生效) |
-| 二进制差分更新 | 支持 | 对比新老版本通过差分算法生成补丁文件。(引用组件默认生效) |
-| 增量更新功能 | 支持 | 相比上一个版本只更新当前修改过的文件,并且删除当前版本不存在的文件。(引用组件默认生效) |
-| 强制更新 | 支持 | 打开客户端之后直接强制更新。 |
-| 多分支更新 | 支持 | 当一个产品有多个分支时,需要根据不同的分支更新对应的内容。 |
-| 最新版本推送 | 支持 | 基于Signal R实现,推送当前最新版本。 |
-| 客户端程序、服务端程序应用更新 | 支持 | C/S和B/S程序均可使用。 |
-| 多平台、操作系统 | 部分支持 | Windows、MAUI Android平台 |
-| 多语言 | 待验证 | 也可将本组件编写为控制台程序,作为更新“脚本”。更新其他语言的应用程序。 |
-| 跳过更新 | 支持 | 支持注入弹窗让用户决定是否更新本次发布,服务端决定强制时更新不生效。 |
-| 相互升级 | 支持 | 主程序可更新升级程序,升级程序可更新主程序。 |
-| 黑名单 | 支持 | 在更新过程中会跳过黑名单中的文件列表和文件扩展名列表。 |
-| OSS | 支持 | 极简化更新,是一套独立的更新机制。只需要在文件服务器中放置version.json的版本配置文件。组件会根据配置文件中的版本信息进行更新下载。(支持Windows,MAUI Android) |
-| 回滚 | 待测试 | 逐版本更新时会备份每个版本,如果更新失败则逐版本回滚。 |
-| 驱动更新 | 待测试 | 逐版本更新时会备份每个版本的驱动文件(.inf),如果更新失败则逐版本回滚。 |
-| 遗言 | 待测试 | 开机时和升级时会检查升级是否成功,如果失败则根据遗言还原之前的备份。遗言是更新之前就已经自动创建在C:\generalupdate_willmessages目录下的will_message.json文件。will_message.json的内容是持久化回滚备份的文件目录相关信息。(需要部署GeneralUpdate.SystemService系统服务) |
-| 自定义方法列表 | 支持 | 注入一个自定义方法集合,该集合会在更新启动前执行。执行自定义方法列表如果出现任何异常,将通过异常订阅通知。(推荐在更新之前检查当前软件环境) |
-
-
-
-## 2.帮助文档 ##
-
-- 讲解视频: https://www.bilibili.com/video/BV1aX4y137dd
-- 官方网站: http://justerzhu.cn/
-- 快速启动: https://mp.weixin.qq.com/s/pRKPFe3eC0NSqv9ixXEiTg
-- 使用教程视频:https://www.bilibili.com/video/BV1FT4y1Y7hV
-- 文档:https://gitee.com/GeneralLibrary/GeneralUpdate/tree/master/doc
+GeneralUpdate是一款基于.NET Standard2.0开源自动升级组件。
+
+帮助文档
-## 3.开源地址 ##
+- 官方网站: https://www.justerzhu.cn/
+- 使用教程视频:https://www.bilibili.com/video/BV1FT4y1Y7hV
-### 3.1当前项目GeneralUpdate
+当前项目GeneralUpdate
- https://github.com/JusterZhu/GeneralUpdate
- https://gitee.com/Juster-zhu/GeneralUpdate
-### 3.2打包工具项目地址GeneralUpdate.Tools
+MAUI GeneralUpdate.Maui
+
+- https://github.com/GeneralLibrary/GeneralUpdate.Maui
+
+打包工具项目地址GeneralUpdate.Tools
- https://github.com/GeneralLibrary/GeneralUpdate.Tools
- https://gitee.com/GeneralTeam/GeneralUpdate.Tools
-### 3.3示例项目地址GeneralUpdate-Samples
+示例项目地址GeneralUpdate-Samples
- https://github.com/GeneralLibrary/GeneralUpdate-Samples
- https://gitee.com/GeneralTeam/GeneralUpdate-Samples
+功能介绍:
+
+| 功能 | 是否支持 | 备注 |
+| -------------- | -------- | ------------------------------------------------------------ |
+| 断点续传 | 支持 | 单次更新失败时,下次一次启动时继续上一次更新下载更新包内容。(引用组件默认生效) |
+| 逐版本更新 | 支持 | 客户端当前版本如果与服务器相差多个版本,则根据多个版本的发布日期逐个更新。(引用组件默认生效) |
+| 二进制差分更新 | 支持 | 对比新老版本通过差分算法生成补丁文件。(引用组件默认生效) |
+| 增量更新功能 | 支持 | 相比上一个版本只更新当前修改过的文件,并且删除当前版本不存在的文件。(引用组件默认生效) |
+| 强制更新 | 支持 | 打开客户端之后直接强制更新。 |
+| 多分支更新 | 支持 | 当一个产品有多个分支时,需要根据不同的分支更新对应的内容。 |
+| 最新版本推送 | 支持 | 基于Signal R实现,推送当前最新版本。 |
+| 多语言 | 待验证 | 也可将本组件编写为控制台程序,作为更新“脚本”。更新其他语言的应用程序。 |
+| 跳过更新 | 支持 | 支持注入弹窗让用户决定是否更新本次发布,服务端决定强制时更新不生效。 |
+| 相互升级 | 支持 | 主程序可更新升级程序,升级程序可更新主程序。 |
+| 黑名单 | 支持 | 在更新过程中会跳过黑名单中的文件列表和文件扩展名列表。 |
+| OSS | 支持 | 极简化更新,是一套独立的更新机制。只需要在文件服务器中放置version.json的版本配置文件。组件会根据配置文件中的版本信息进行更新下载。 |
+| 回滚、备份 | 支持 | 更新之前会将客户端本地文件备份,如果客户端启动失败或崩溃则回滚覆盖。 |
+| 驱动更新 | 待验证 | 更新之前会将驱动备份到本地,如果客户端启动失败或崩溃则回滚覆盖。 |
+| 自定义方法列表 | 支持 | 注入一个自定义方法集合,该集合会在更新启动前执行。执行自定义方法列表如果出现任何异常,将通过异常订阅通知。(推荐在更新之前检查当前软件环境) |
+| AOT | 支持 | 支持AOT编译发布。 |
-## 4.支持框架
-| 框架名称 | 是否支持 |
+## 2.支持框架
+
+| .NET框架名称 | 是否支持 |
| -------------------------- | -------- |
| .NET Core 2.0 | 支持 |
| .NET 5 ... to last version | 支持 |
| .NET Framework 4.6.1 | 支持 |
-| UI框架名称 | 是否支持 |
-| ----------------- | --------------------- |
-| WPF | 支持 |
-| UWP | 商店模式下不可更新 |
-| MAUI | 目前仅支持Android平台 |
-| Avalonia | 支持 |
-| WinUI | 待验证,等待反馈 |
-| Console(控制台) | 支持 |
-| Winform | 支持 |
-
-| 服务端框架 | 是否支持 |
-| ---------- | -------- |
-| ASP.NET | 待验证 |
+| UI框架名称 | 是否支持 |
+| ---------- | --------------------- |
+| WPF | 支持 |
+| UWP | 商店模式下不可更新 |
+| MAUI | 目前仅支持Android平台 |
+| Avalonia | 支持 |
+| WinUI | 支持 |
+| Console | 支持 |
+| WinForms | 支持 |
-## 5.操作系统
+## 3.操作系统
| 操作系统名称 | 是否支持 |
| ------------ | -------- |
| Windows | 支持 |
-| Linux | 待验证 |
-| Mac | 待验证 |
+| Linux | 支持 |
| Android | 支持 |
-| 树莓派(IoT) | 待验证 |
| 麒麟V10(飞腾S2500) | 支持 |
| 麒麟V10(x64) | 支持 |
-
-
-
-## 6.GeneralUpdate.SystemService发布/部署
-
-GeneralUpdate.SystemService是一个windows系统服务,并不是部署在服务端的web api。它的主要作用是监听更新过程,以及更新崩溃之后还原。
-
-**发布:**
-
-推荐发布Single file,如果想发布AOT版本需要移除源码中映射代码。
-
-```shell
-dotnet publish -r win-x64 -p:PublishSingleFile=true -p:IncludeNativeLibrariesForSelfExtract=true --self-contained true
-```
-
-**创建/部署windows服务:**
-
-```shell
-sc create MyWorkerService binPath="C:\your_path\GeneralUpdate.SystemService.exe"
-```
-
-**启动已部署的windows服务:**
-
-```shell
-sc start GeneralUpdate.SystemService
-```
-
-**删除已部署的windows服务:**
-
-```shell
-sc delete GeneralUpdate.SystemService
-```
-
+| Ubuntu | 支持 |
+| 龙芯(Loongnix) | 待验证 |
diff --git a/README_en.md b/README_en.md
index 537126a1e947f2114cb379dc51bf2e2b2fa46da5..d9f6e9315a3d69660ac049e21834baf17b450e6f 100644
--- a/README_en.md
+++ b/README_en.md
@@ -92,36 +92,3 @@
| raspberry pie | Not currently supported |
| Kylin V10 (FT-S2500) | yes |
| Kylin V10 (x64) | yes |
-
-
-
-## GeneralUpdate.SystemService Publish/Deploy
-
-GeneralUpdate.SystemService is a Windows system service, not a web API deployed on the server. Its main purpose is to listen for the update process and restore after an update crash.
-
-**Publish:**
-
-It is recommended to release a single file, if you want to release the AOT version, you need to remove the mapping code from the source code.
-
-```shell
-dotnet publish -r win-x64 -p:PublishSingleFile=true -p:IncludeNativeLibrariesForSelfExtract=true --self-contained true
-```
-
-**Create/deploy Windows services:**
-
-```shell
-sc create MyWorkerService binPath="C:\your_path\GeneralUpdate.SystemService.exe"
-```
-
-**Start the deployed Windows service:**
-
-```shell
-sc start GeneralUpdate.SystemService
-```
-
-**Delete the deployed Windows service:**
-
-```shell
-sc delete GeneralUpdate.SystemService
-```
-
diff --git a/imgs/1708869360661.jpg b/imgs/1708869360661.jpg
deleted file mode 100644
index d2ddd8c5d6c9afdde41f8f2a2c3f0b070cde3493..0000000000000000000000000000000000000000
Binary files a/imgs/1708869360661.jpg and /dev/null differ
diff --git a/imgs/GeneralUpdate_h2.png b/imgs/GeneralUpdate_h2.png
new file mode 100644
index 0000000000000000000000000000000000000000..1e77f86315cd676e3336249689d7213d3628f2f0
Binary files /dev/null and b/imgs/GeneralUpdate_h2.png differ
diff --git a/imgs/bowl.jpeg b/imgs/bowl.jpeg
new file mode 100644
index 0000000000000000000000000000000000000000..b099e2163483804fb316c5e3175e91529696f139
Binary files /dev/null and b/imgs/bowl.jpeg differ
diff --git a/src/c#/GeneralUpdate.Bowl/Applications/Windows/export.bat b/src/c#/GeneralUpdate.Bowl/Applications/Windows/export.bat
new file mode 100644
index 0000000000000000000000000000000000000000..80921e8ec4144b4314045f9b6c6c0d53494e9f54
--- /dev/null
+++ b/src/c#/GeneralUpdate.Bowl/Applications/Windows/export.bat
@@ -0,0 +1,40 @@
+@echo off
+setlocal
+
+if "%~1"=="" (
+ echo Please provide the export path as the first parameter.
+ exit /b 1
+)
+
+set exportDir=%~1
+
+if not exist "%exportDir%" (
+ mkdir "%exportDir%"
+)
+
+set outputFile=%exportDir%\driverInfo.txt
+
+:: 导出驱动信息
+driverquery /v /fo table > "%outputFile%"
+echo %outputFile% Export successfully.
+
+:: 导出系统信息
+set systemInfoFile=%exportDir%\systeminfo.txt
+systeminfo > "%systemInfoFile%"
+echo %systemInfoFile% Export successfully.
+
+:: 获取当前日期
+for /f "tokens=1-4 delims=/- " %%i in ('date /t') do (
+ set yyyy=%%i
+ set mm=%%j
+ set dd=%%k
+)
+
+:: 设置日志文件名
+set logFile=%exportDir%\systemlog.evtx
+
+:: 导出系统日志
+wevtutil epl System "%logFile%" /q:"*[System[TimeCreated[timediff(@SystemTime) <= 86400000]]]"
+echo %logFile% Export successfully.
+
+endlocal
\ No newline at end of file
diff --git a/src/c#/GeneralUpdate.Bowl/Bowl.cs b/src/c#/GeneralUpdate.Bowl/Bowl.cs
index fc828ebbb201e5b2214381b8c19670bfeac8d8c0..e9556b4d335d68249a6c12960df22023196cb525 100644
--- a/src/c#/GeneralUpdate.Bowl/Bowl.cs
+++ b/src/c#/GeneralUpdate.Bowl/Bowl.cs
@@ -1,39 +1,58 @@
using System;
+using System.IO;
using System.Runtime.InteropServices;
+using System.Text.Json;
using GeneralUpdate.Bowl.Strategys;
+using GeneralUpdate.Common.Internal.JsonContext;
+using GeneralUpdate.Common.Shared.Object;
namespace GeneralUpdate.Bowl;
-public class Bowl
+///
+/// Surveillance Main Program.
+///
+public sealed class Bowl
{
- private IStrategy _strategy;
+ private static IStrategy? _strategy;
- public Bowl(MonitorParameter parameter = null)
- {
- CreateStrategy();
- _strategy!.SetParameter(parameter);
- }
+ private Bowl() { }
- private void CreateStrategy()
+ private static void CreateStrategy()
{
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
- {
_strategy = new WindowStrategy();
- }
- else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
- {
- _strategy = new LinuxStrategy();
- }
+
+ if (_strategy == null)
+ throw new PlatformNotSupportedException("Unsupported operating system");
+ }
+
+ public static void Launch(MonitorParameter? monitorParameter = null)
+ {
+ monitorParameter ??= CreateParameter();
+ CreateStrategy();
+ _strategy?.SetParameter(monitorParameter);
+ _strategy?.Launch();
}
- public Bowl SetParameter(MonitorParameter parameter)
+ private static MonitorParameter CreateParameter()
{
- if(parameter.Verify())
- throw new ArgumentException("Parameter contains illegal values");
+ var json = Environment.GetEnvironmentVariable("ProcessInfo", EnvironmentVariableTarget.User);
+ if(string.IsNullOrWhiteSpace(json))
+ throw new ArgumentNullException("ProcessInfo environment variable not set !");
- _strategy.SetParameter(parameter);
- return this;
+ var processInfo = JsonSerializer.Deserialize(json, ProcessInfoJsonContext.Default.ProcessInfo);
+ if(processInfo == null)
+ throw new ArgumentNullException("ProcessInfo json deserialize fail!");
+
+ return new MonitorParameter
+ {
+ ProcessNameOrId = processInfo.AppName,
+ DumpFileName = $"{processInfo.LastVersion}_fail.dmp",
+ FailFileName = $"{processInfo.LastVersion}_fail.json",
+ TargetPath = processInfo.InstallPath,
+ FailDirectory = Path.Combine(processInfo.InstallPath, "fail", processInfo.LastVersion),
+ BackupDirectory = Path.Combine(processInfo.InstallPath, processInfo.LastVersion),
+ ExtendedField = processInfo.LastVersion
+ };
}
-
- public void Launch() => _strategy.Launch();
}
\ No newline at end of file
diff --git a/src/c#/GeneralUpdate.Bowl/GeneralUpdate.Bowl.csproj b/src/c#/GeneralUpdate.Bowl/GeneralUpdate.Bowl.csproj
index 3c0d6140729b9d79d2041cdfb1ac0587211403d1..0c47f789a967899071f599befa9aa37686d53ffd 100644
--- a/src/c#/GeneralUpdate.Bowl/GeneralUpdate.Bowl.csproj
+++ b/src/c#/GeneralUpdate.Bowl/GeneralUpdate.Bowl.csproj
@@ -25,6 +25,17 @@
PreserveNewest
+
+ PreserveNewest
+
+
+
+
+
+
+
+
+
diff --git a/src/c#/GeneralUpdate.Bowl/Internal/Crash.cs b/src/c#/GeneralUpdate.Bowl/Internal/Crash.cs
new file mode 100644
index 0000000000000000000000000000000000000000..2b783c1194363a4054df8ad4dad33d2cfbb5329f
--- /dev/null
+++ b/src/c#/GeneralUpdate.Bowl/Internal/Crash.cs
@@ -0,0 +1,11 @@
+using System.Collections.Generic;
+using GeneralUpdate.Bowl.Strategys;
+
+namespace GeneralUpdate.Bowl.Internal;
+
+internal class Crash
+{
+ public MonitorParameter Parameter { get; set; }
+
+ public List ProcdumpOutPutLines { get; set; }
+}
\ No newline at end of file
diff --git a/src/c#/GeneralUpdate.Bowl/Internal/CrashJsonContext.cs b/src/c#/GeneralUpdate.Bowl/Internal/CrashJsonContext.cs
new file mode 100644
index 0000000000000000000000000000000000000000..1c3f8ab1f144a0d0b475d5924f52b85acccaea2b
--- /dev/null
+++ b/src/c#/GeneralUpdate.Bowl/Internal/CrashJsonContext.cs
@@ -0,0 +1,6 @@
+using System.Text.Json.Serialization;
+
+namespace GeneralUpdate.Bowl.Internal;
+
+[JsonSerializable(typeof(Crash))]
+internal partial class CrashJsonContext : JsonSerializerContext;
\ No newline at end of file
diff --git a/src/c#/GeneralUpdate.Bowl/Strategys/LinuxSystem.cs b/src/c#/GeneralUpdate.Bowl/Internal/LinuxSystem.cs
similarity index 84%
rename from src/c#/GeneralUpdate.Bowl/Strategys/LinuxSystem.cs
rename to src/c#/GeneralUpdate.Bowl/Internal/LinuxSystem.cs
index 4db1dbec39a502733f76e2e46ad8a4cf996354d4..66903efb6ed4c4af5fc3075a5f0e625251d98d5f 100644
--- a/src/c#/GeneralUpdate.Bowl/Strategys/LinuxSystem.cs
+++ b/src/c#/GeneralUpdate.Bowl/Internal/LinuxSystem.cs
@@ -1,4 +1,4 @@
-namespace GeneralUpdate.Bowl.Strategys;
+namespace GeneralUpdate.Bowl.Internal;
internal class LinuxSystem
{
diff --git a/src/c#/GeneralUpdate.Bowl/Strategys/AbstractStrategy.cs b/src/c#/GeneralUpdate.Bowl/Strategys/AbstractStrategy.cs
index dcf8f2750fdff690818628b26b954cbcb1022f07..c6bc12c3222fedc0ab4a7a33c67557deed41f714 100644
--- a/src/c#/GeneralUpdate.Bowl/Strategys/AbstractStrategy.cs
+++ b/src/c#/GeneralUpdate.Bowl/Strategys/AbstractStrategy.cs
@@ -1,32 +1,36 @@
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
+using GeneralUpdate.Common.FileBasic;
namespace GeneralUpdate.Bowl.Strategys;
-public abstract class AbstractStrategy : IStrategy
+internal abstract class AbstractStrategy : IStrategy
{
protected MonitorParameter _parameter;
-
- private readonly IReadOnlyList _sensitiveCharacter = new List
- {
- "Exit",
- "exit"
- };
+ protected List OutputList = new ();
+
+ public void SetParameter(MonitorParameter parameter) => _parameter = parameter;
public virtual void Launch()
{
- Backup();
- Startup(_parameter.ProcessNameOrId, _parameter.InnerArguments);
+ Startup(_parameter.InnerApp, _parameter.InnerArguments);
}
private void Startup(string appName, string arguments)
{
+ if (Directory.Exists(_parameter.FailDirectory))
+ {
+ StorageManager.DeleteDirectory(_parameter.FailDirectory);
+ }
+ Directory.CreateDirectory(_parameter.FailDirectory);
+
var startInfo = new ProcessStartInfo
{
FileName = appName,
Arguments = arguments,
RedirectStandardOutput = true,
+ RedirectStandardError = true,
UseShellExecute = false,
CreateNoWindow = true
};
@@ -35,71 +39,15 @@ public abstract class AbstractStrategy : IStrategy
process.OutputDataReceived += OutputHandler;
process.ErrorDataReceived += OutputHandler;
process.Start();
- process.StandardOutput.ReadToEnd();
- process.WaitForExit();
+ process.BeginOutputReadLine();
+ process.BeginErrorReadLine();
+ process.WaitForExit(1000 * 10);
}
private void OutputHandler(object sendingProcess, DataReceivedEventArgs outLine)
{
var data = outLine.Data;
if (!string.IsNullOrEmpty(data))
- {
- foreach (var sensitive in _sensitiveCharacter)
- {
- if (data.Contains(sensitive)){
- Restore();
- Process.Start(_parameter.ProcessNameOrId, _parameter.Arguments);
- break;
- }
- }
- }
+ OutputList.Add(data);
}
-
- private void Backup()
- {
- var backupPath = _parameter.Target;
- var sourcePath = _parameter.Source;
-
- if (Directory.Exists(backupPath))
- {
- Directory.Delete(backupPath, true);
- }
-
- Directory.CreateDirectory(backupPath);
-
- foreach (string dirPath in Directory.GetDirectories(sourcePath, "*", SearchOption.AllDirectories))
- {
- Directory.CreateDirectory(dirPath.Replace(sourcePath, backupPath));
- }
-
- foreach (string newPath in Directory.GetFiles(sourcePath, "*.*", SearchOption.AllDirectories))
- {
- File.Copy(newPath, newPath.Replace(sourcePath, backupPath), true);
- }
- }
-
- private void Restore()
- {
- var restorePath = _parameter.Target;
- var backupPath = _parameter.Source;
-
- if (Directory.Exists(restorePath))
- {
- Directory.Delete(restorePath, true);
- }
-
- Directory.CreateDirectory(restorePath);
-
- foreach (string dirPath in Directory.GetDirectories(backupPath, "*", SearchOption.AllDirectories))
- {
- Directory.CreateDirectory(dirPath.Replace(backupPath, restorePath));
- }
-
- foreach (string newPath in Directory.GetFiles(backupPath, "*.*", SearchOption.AllDirectories))
- {
- File.Copy(newPath, newPath.Replace(backupPath, restorePath), true);
- }
- }
-
- public void SetParameter(MonitorParameter parameter) => _parameter = parameter;
}
\ No newline at end of file
diff --git a/src/c#/GeneralUpdate.Bowl/Strategys/IStrategy.cs b/src/c#/GeneralUpdate.Bowl/Strategys/IStrategy.cs
index d0a58e9f9046bc9ef4d483718dcb07778b79d96d..6b4298f0d2a612b18d4926fa2b7cb129e8546a75 100644
--- a/src/c#/GeneralUpdate.Bowl/Strategys/IStrategy.cs
+++ b/src/c#/GeneralUpdate.Bowl/Strategys/IStrategy.cs
@@ -1,6 +1,8 @@
-namespace GeneralUpdate.Bowl.Strategys;
+using GeneralUpdate.Bowl.Internal;
-public interface IStrategy
+namespace GeneralUpdate.Bowl.Strategys;
+
+internal interface IStrategy
{
void Launch();
diff --git a/src/c#/GeneralUpdate.Bowl/Strategys/LinuxStrategy.cs b/src/c#/GeneralUpdate.Bowl/Strategys/LinuxStrategy.cs
index 64f300c515900e5d04655dc7bb2cfb7580a255bc..7f38e923d518c5331f298354e614054a71c06ad0 100644
--- a/src/c#/GeneralUpdate.Bowl/Strategys/LinuxStrategy.cs
+++ b/src/c#/GeneralUpdate.Bowl/Strategys/LinuxStrategy.cs
@@ -3,19 +3,22 @@ using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
+using GeneralUpdate.Bowl.Internal;
namespace GeneralUpdate.Bowl.Strategys;
-public class LinuxStrategy : AbstractStrategy
+internal 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 +67,9 @@ public class LinuxStrategy : AbstractStrategy
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 +108,7 @@ public class LinuxStrategy : AbstractStrategy
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.Bowl/Strategys/MonitorParameter.cs b/src/c#/GeneralUpdate.Bowl/Strategys/MonitorParameter.cs
index 53d49e612eb96c49dcbb2e2bcfbe21e648987305..d53d2f309f0c2b453b3c84266a3d7a3faa55856c 100644
--- a/src/c#/GeneralUpdate.Bowl/Strategys/MonitorParameter.cs
+++ b/src/c#/GeneralUpdate.Bowl/Strategys/MonitorParameter.cs
@@ -2,29 +2,29 @@
public class MonitorParameter
{
- public string Target { get; set; }
-
- public string Source { get; set; }
+ public MonitorParameter() { }
- public string ProcessNameOrId { get; set; }
+ public string TargetPath { get; set; }
- public string DumpPath { get; set; }
+ public string FailDirectory { get; set; }
+ public string BackupDirectory { get; set; }
+
+ public string ProcessNameOrId { get; set; }
+
public string DumpFileName { get; set; }
- public string Arguments { get; set; }
+ public string FailFileName { get; set; }
- internal string InnerArguments => $"-e -ma {ProcessNameOrId} {DumpPath}";
+ internal string InnerArguments { get; set; }
- internal string InnerAppName { get; set; }
-
- public bool Verify()
- {
- return string.IsNullOrEmpty(Target) &&
- string.IsNullOrEmpty(Source) &&
- string.IsNullOrEmpty(ProcessNameOrId) &&
- string.IsNullOrEmpty(DumpPath) &&
- string.IsNullOrEmpty(DumpFileName) &&
- string.IsNullOrEmpty(Arguments);
- }
+ internal string InnerApp { get; set; }
+
+ ///
+ /// Upgrade: upgrade mode. This mode is primarily used in conjunction with GeneralUpdate for internal use. Please do not modify it arbitrarily when the default mode is activated.
+ /// Normal: Normal mode,This mode can be used independently to monitor a single program. If the program crashes, it will export the crash information.
+ ///
+ public string WorkModel { get; set; } = "Upgrade";
+
+ public string ExtendedField { get; set; }
}
\ No newline at end of file
diff --git a/src/c#/GeneralUpdate.Bowl/Strategys/WindowStrategy.cs b/src/c#/GeneralUpdate.Bowl/Strategys/WindowStrategy.cs
index da32bcd6c977c1a40dd6b1c2f9a1c0ccb60865ca..dbc77f5bbfa6c5c0550b92bde69d4993d4c2146d 100644
--- a/src/c#/GeneralUpdate.Bowl/Strategys/WindowStrategy.cs
+++ b/src/c#/GeneralUpdate.Bowl/Strategys/WindowStrategy.cs
@@ -1,23 +1,105 @@
-using System.Runtime.InteropServices;
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.IO;
+using System.Runtime.InteropServices;
+using GeneralUpdate.Bowl.Internal;
+using GeneralUpdate.Common.FileBasic;
namespace GeneralUpdate.Bowl.Strategys;
-public class WindowStrategy : AbstractStrategy
+internal class WindowStrategy : AbstractStrategy
{
+ private const string WorkModel = "Upgrade";
+ private string? _applicationsDirectory;
+ private List _actions = new();
+
public override void Launch()
{
- _parameter.InnerAppName = GetAppName();
+ InitializeActions();
+ _applicationsDirectory = Path.Combine(_parameter.TargetPath, "Applications", "Windows");
+ _parameter.InnerApp = Path.Combine(_applicationsDirectory, GetAppName());
+ var dmpFullName = Path.Combine(_parameter.FailDirectory, _parameter.DumpFileName);
+ _parameter.InnerArguments = $"-e -ma {_parameter.ProcessNameOrId} {dmpFullName}";
base.Launch();
+ ExecuteFinalTreatment();
}
- private string GetAppName()
+ private string GetAppName() => RuntimeInformation.OSArchitecture switch
{
- string appName = RuntimeInformation.OSArchitecture switch
+ Architecture.X86 => "procdump.exe",
+ Architecture.X64 => "procdump64.exe",
+ _ => "procdump64a.exe"
+ };
+
+ private void ExecuteFinalTreatment()
+ {
+ var dumpFile = Path.Combine(_parameter.FailDirectory, _parameter.DumpFileName);
+ if (File.Exists(dumpFile))
+ {
+ foreach (var action in _actions)
+ {
+ action.Invoke();
+ }
+ }
+ }
+
+ private void InitializeActions()
+ {
+ _actions.Add(CreateCrash);
+ _actions.Add(Export);
+ _actions.Add(Restore);
+ _actions.Add(SetEnvironment);
+ }
+
+ ///
+ /// Export the crash output information from procdump.exe and the monitoring parameters of Bowl.
+ ///
+ private void CreateCrash()
+ {
+ var crash = new Crash
{
- Architecture.X86 => "procdump.exe",
- Architecture.X64 => "procdump64.exe",
- _ => "procdump64a.exe"
+ Parameter = _parameter,
+ ProcdumpOutPutLines = OutputList
};
- return appName;
+ var failJsonPath = Path.Combine(_parameter.FailDirectory, _parameter.FailFileName);
+ StorageManager.CreateJson(failJsonPath, crash, CrashJsonContext.Default.Crash);
+ }
+
+ ///
+ /// Export operating system information, system logs, and system driver information.
+ ///
+ private void Export()
+ {
+ var batPath = Path.Combine(_applicationsDirectory, "export.bat");
+ if(!File.Exists(batPath))
+ throw new FileNotFoundException("export.bat not found!");
+
+ Process.Start(batPath, _parameter.FailDirectory);
+ }
+
+ ///
+ /// Within the GeneralUpdate upgrade system, restore the specified backup version files to the current working directory.
+ ///
+ private void Restore()
+ {
+ if (string.Equals(_parameter.WorkModel, WorkModel))
+ StorageManager.Restore(_parameter.BackupDirectory, _parameter.TargetPath);
+ }
+
+ ///
+ /// Write the failed update version number to the local environment variable.
+ ///
+ private void SetEnvironment()
+ {
+ if (!string.Equals(_parameter.WorkModel, WorkModel))
+ return;
+
+ /*
+ * The `UpgradeFail` environment variable is used to mark an exception version number during updates.
+ * If the latest version number obtained via an HTTP request is less than or equal to the exception version number, the update is skipped.
+ * Once this version number is set, it will not be removed, and updates will not proceed until a version greater than the exception version number is obtained through the HTTP request.
+ */
+ Environment.SetEnvironmentVariable("UpgradeFail", _parameter.ExtendedField, EnvironmentVariableTarget.User);
}
}
\ No newline at end of file
diff --git a/src/c#/GeneralUpdate.Client/GeneralUpdate.Client.csproj b/src/c#/GeneralUpdate.Client/GeneralUpdate.Client.csproj
index 94ea81d5b8a99c500de3b09bda23e96227a07b29..3c07e165e287c053adf840647e9d04263fff55ea 100644
--- a/src/c#/GeneralUpdate.Client/GeneralUpdate.Client.csproj
+++ b/src/c#/GeneralUpdate.Client/GeneralUpdate.Client.csproj
@@ -5,9 +5,14 @@
net8.0
enable
enable
-
+ true
+ default
+
+
+
+
diff --git a/src/c#/GeneralUpdate.Client/MySample.cs b/src/c#/GeneralUpdate.Client/MySample.cs
deleted file mode 100644
index d602edbcd514c288bdff9a812648c2dfb4d66f3f..0000000000000000000000000000000000000000
--- 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 1b9dd51c972a8f7125b322c96aa9cb064d97f72a..328636ac816cb6eb28981234cc9279bdd0a6ebf7 100644
--- a/src/c#/GeneralUpdate.Client/Program.cs
+++ b/src/c#/GeneralUpdate.Client/Program.cs
@@ -1,28 +1,123 @@
-namespace GeneralUpdate.Client
+using System.Diagnostics;
+using System.Text;
+using GeneralUpdate.ClientCore;
+using GeneralUpdate.ClientCore.Hubs;
+using GeneralUpdate.Common.Download;
+using GeneralUpdate.Common.Internal;
+using GeneralUpdate.Common.Internal.Bootstrap;
+using GeneralUpdate.Common.Shared.Object;
+using GeneralUpdate.Common.Shared.Object.Enum;
+
+namespace GeneralUpdate.Client
{
internal class Program
{
- private static void Main(string[] args)
+ static async Task Main(string[] args)
+ {
+ /*try
+ {
+ Console.WriteLine($"主程序初始化,{DateTime.Now}!");
+ Console.WriteLine("当前运行目录:" + Thread.GetDomain().BaseDirectory);
+ await Task.Delay(2000);
+ var configinfo = new Configinfo
+ {
+ //configinfo.UpdateLogUrl = "https://www.baidu.com";
+ ReportUrl = "http://127.0.0.1:5000/Upgrade/Report",
+ UpdateUrl = "http://127.0.0.1:5000/Upgrade/Verification",
+ AppName = "GeneralUpdate.Upgrad.exe",
+ MainAppName = "GeneralUpdate.Client.exe",
+ InstallPath = Thread.GetDomain().BaseDirectory,
+ //configinfo.Bowl = "Generalupdate.CatBowl.exe";
+ //当前客户端的版本号
+ ClientVersion = "1.0.0.0",
+ //当前升级端的版本号
+ UpgradeClientVersion = "1.0.0.0",
+ //产品id
+ ProductId = "2d974e2a-31e6-4887-9bb1-b4689e98c77a",
+ //应用密钥
+ AppSecretKey = "dfeb5833-975e-4afb-88f1-6278ee9aeff6"
+ };
+ _ = await new GeneralClientBootstrap() //单个或多个更新包下载通知事件
+ //单个或多个更新包下载速度、剩余下载事件、当前下载版本信息通知事件
+ .AddListenerMultiDownloadStatistics(OnMultiDownloadStatistics)
+ //单个或多个更新包下载完成
+ .AddListenerMultiDownloadCompleted(OnMultiDownloadCompleted)
+ //完成所有的下载任务通知
+ .AddListenerMultiAllDownloadCompleted(OnMultiAllDownloadCompleted)
+ //下载过程出现的异常通知
+ .AddListenerMultiDownloadError(OnMultiDownloadError)
+ //整个更新过程出现的任何问题都会通过这个事件通知
+ .AddListenerException(OnException)
+ .SetConfig(configinfo)
+ .Option(UpdateOption.DownloadTimeOut, 60)
+ .Option(UpdateOption.Encoding, Encoding.UTF8)
+ .LaunchAsync();
+ Console.WriteLine($"主程序已启动,{DateTime.Now}!");
+ }
+ catch (Exception e)
+ {
+ Console.WriteLine(e.Message + "\n" + e.StackTrace);
+ }*/
+
+ /*var paramsOSS = new GlobalConfigInfoOSS();
+ paramsOSS.Url = "http://192.168.50.203/versions.json";
+ paramsOSS.CurrentVersion = "1.0.0.0";
+ paramsOSS.VersionFileName = "versions.json";
+ paramsOSS.AppName = "GeneralUpdate.Client.exe";
+ paramsOSS.Encoding = Encoding.UTF8.WebName;
+ GeneralClientOSS.Start(paramsOSS);*/
+
+ var hub = new UpgradeHubService("http://localhost:5000/UpgradeHub"
+ , null,"dfeb5833-975e-4afb-88f1-6278ee9aeff6");
+ hub.AddListenerReceive((message) =>
+ {
+ Debug.WriteLine(message);
+ });
+ await hub.StartAsync();
+
+ /*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);
+ });*/
+
+ while (true)
+ {
+ var content = Console.ReadLine();
+ if (content == "exit") break;
+ }
+ }
+
+ private static void OnMultiDownloadError(object arg1, MultiDownloadErrorEventArgs arg2)
+ {
+ var version = arg2.Version as VersionInfo;
+ Console.WriteLine($"{version.Version} {arg2.Exception}");
+ }
+
+ private static void OnMultiAllDownloadCompleted(object arg1, MultiAllDownloadCompletedEventArgs arg2)
+ {
+ Console.WriteLine(arg2.IsAllDownloadCompleted ? "所有的下载任务已完成!" : $"下载任务已失败!{arg2.FailedVersions.Count}");
+ }
+
+ private static void OnMultiDownloadCompleted(object arg1, MultiDownloadCompletedEventArgs arg2)
+ {
+ var version = arg2.Version as VersionInfo;
+ Console.WriteLine(arg2.IsComplated ? $"当前下载版本:{version.Version}, 下载完成!" : $"当前下载版本:{version.Version}, 下载失败!");
+ }
+
+ private static void OnMultiDownloadStatistics(object arg1, MultiDownloadStatisticsEventArgs arg2)
+ {
+ var version = arg2.Version as VersionInfo;
+ Console.WriteLine($"当前下载版本:{version.Version},下载速度:{arg2.Speed},剩余下载时间:{arg2.Remaining},已下载大小:{arg2.BytesReceived},总大小:{arg2.TotalBytesToReceive}, 进度百分比:{arg2.ProgressPercentage}%");
+ }
+
+ private static void OnException(object arg1, ExceptionEventArgs arg2)
{
- 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();
- //});
- Console.Read();
+ Console.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 e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000
diff --git a/src/c#/GeneralUpdate.ClientCore/CustomAwaiter/.gitkeep b/src/c#/GeneralUpdate.ClientCore/CustomAwaiter/.gitkeep
deleted file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000
diff --git a/src/c#/GeneralUpdate.ClientCore/Differential/.gitkeep b/src/c#/GeneralUpdate.ClientCore/Differential/.gitkeep
deleted file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000
diff --git a/src/c#/GeneralUpdate.ClientCore/Differential/Binary/.gitkeep b/src/c#/GeneralUpdate.ClientCore/Differential/Binary/.gitkeep
deleted file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000
diff --git a/src/c#/GeneralUpdate.ClientCore/Differential/ContentProvider/.gitkeep b/src/c#/GeneralUpdate.ClientCore/Differential/ContentProvider/.gitkeep
deleted file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000
diff --git a/src/c#/GeneralUpdate.ClientCore/Differential/GStream/.gitkeep b/src/c#/GeneralUpdate.ClientCore/Differential/GStream/.gitkeep
deleted file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000
diff --git a/src/c#/GeneralUpdate.ClientCore/Domain/.gitkeep b/src/c#/GeneralUpdate.ClientCore/Domain/.gitkeep
deleted file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000
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 e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000
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 e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000
diff --git a/src/c#/GeneralUpdate.ClientCore/Domain/Enum/.gitkeep b/src/c#/GeneralUpdate.ClientCore/Domain/Enum/.gitkeep
deleted file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000
diff --git a/src/c#/GeneralUpdate.ClientCore/Domain/PO/.gitkeep b/src/c#/GeneralUpdate.ClientCore/Domain/PO/.gitkeep
deleted file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000
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 e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000
diff --git a/src/c#/GeneralUpdate.ClientCore/Domain/Service/.gitkeep b/src/c#/GeneralUpdate.ClientCore/Domain/Service/.gitkeep
deleted file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000
diff --git a/src/c#/GeneralUpdate.ClientCore/Domain/VO/.gitkeep b/src/c#/GeneralUpdate.ClientCore/Domain/VO/.gitkeep
deleted file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000
diff --git a/src/c#/GeneralUpdate.ClientCore/Download/.gitkeep b/src/c#/GeneralUpdate.ClientCore/Download/.gitkeep
deleted file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000
diff --git a/src/c#/GeneralUpdate.ClientCore/Driver/.gitkeep b/src/c#/GeneralUpdate.ClientCore/Driver/.gitkeep
deleted file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000
diff --git a/src/c#/GeneralUpdate.ClientCore/Events/CommonArgs/.gitkeep b/src/c#/GeneralUpdate.ClientCore/Events/CommonArgs/.gitkeep
deleted file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000
diff --git a/src/c#/GeneralUpdate.ClientCore/Events/MultiEventArgs/.gitkeep b/src/c#/GeneralUpdate.ClientCore/Events/MultiEventArgs/.gitkeep
deleted file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000
diff --git a/src/c#/GeneralUpdate.ClientCore/Exceptions/.gitkeep b/src/c#/GeneralUpdate.ClientCore/Exceptions/.gitkeep
deleted file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000
diff --git a/src/c#/GeneralUpdate.ClientCore/Exceptions/CustomArgs/.gitkeep b/src/c#/GeneralUpdate.ClientCore/Exceptions/CustomArgs/.gitkeep
deleted file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000
diff --git a/src/c#/GeneralUpdate.ClientCore/Exceptions/CustomException/.gitkeep b/src/c#/GeneralUpdate.ClientCore/Exceptions/CustomException/.gitkeep
deleted file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000
diff --git a/src/c#/GeneralUpdate.ClientCore/GeneralClientBootstrap.cs b/src/c#/GeneralUpdate.ClientCore/GeneralClientBootstrap.cs
index 11bded52fce1b7146d9bffc5762d295a8c6dd6f5..ff05faf0694781e316e8f24ee749143ac1953629 100644
--- a/src/c#/GeneralUpdate.ClientCore/GeneralClientBootstrap.cs
+++ b/src/c#/GeneralUpdate.ClientCore/GeneralClientBootstrap.cs
@@ -1,271 +1,454 @@
-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.JsonContext;
+using GeneralUpdate.Common.Internal.Strategy;
+using GeneralUpdate.Common.Shared.Object;
+using GeneralUpdate.Common.Shared.Object.Enum;
+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();
- private List> _customOptions;
- private List>> _customTaskOptions;
+ #region Public Methods
- public GeneralClientBootstrap() : base()
+ ///
+ /// Main function for booting the update startup.
+ ///
+ ///
+ public override async Task LaunchAsync()
+ {
+ try
{
- _customOptions = new List>();
- _customTaskOptions = new List>>();
+ CallSmallBowlHome(_configInfo.Bowl);
+ ExecuteCustomOptions();
+ ClearEnvironmentVariable();
+ await ExecuteWorkflowAsync();
}
-
- #region Public Methods
-
- ///
- /// Start the update.
- ///
- ///
- public override GeneralClientBootstrap LaunchAsync()
+ catch (Exception exception)
{
- Task.Run(() => BaseLaunch());
- return this;
+ Debug.WriteLine(exception.Message);
+ EventManager.Instance.Dispatch(this, new ExceptionEventArgs(exception, exception.Message));
}
+ return this;
+ }
+
+ ///
+ /// Configure server address (Recommended Windows,Linux,Mac).
+ ///
+ public GeneralClientBootstrap SetConfig(Configinfo configInfo)
+ {
+ Debug.Assert(configInfo != null, "configInfo should not be null");
+ configInfo?.Validate();
+ _configInfo = new GlobalConfigInfo
+ {
+ 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,
+ ProductId = configInfo.ProductId,
+ UpgradeClientVersion = configInfo.UpgradeClientVersion,
+ Bowl = configInfo.Bowl
+ };
+ return this;
+ }
+
+ ///
+ /// 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;
+ }
+
+ ///
+ /// 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> funcList)
+ {
+ Debug.Assert(funcList != null && funcList.Any());
+ _customOptions.AddRange(funcList);
+ return this;
+ }
+
+ public GeneralClientBootstrap AddListenerMultiAllDownloadCompleted(
+ Action