├── .gitattributes
├── .github
└── workflows
│ └── dotnet-ci.yaml
├── .gitignore
├── LICENSE
├── NuGet.Config
├── README.md
├── README_ZHCN.md
├── git_push.bat
├── imgs
├── GeneralUpdate.ico
├── GeneralUpdate.png
├── GeneralUpdate128.png
├── GeneralUpdate_h.png
├── GeneralUpdate_h2.png
├── WPFPage_16x.png
├── Windows.png
├── bowl.jpeg
├── contact.png
├── dot-net-plain-wordmark.png
├── gitcode.jpg
├── gitee.png
├── github.png
├── linux.png
├── purple-border-gradient-icon.png
├── toolkit.png
├── ubuntu.png
├── ui.png
├── winui.png
├── 统信UOS.png
├── 麒麟.png
└── 龙芯.png
└── src
└── c#
├── GeneralUpdate.Bowl
├── Applications
│ ├── Linux
│ │ ├── install.sh
│ │ ├── procdump-3.3.0-0.cm2.x86_64.rpm
│ │ ├── procdump-3.3.0-0.el8.x86_64.rpm
│ │ └── procdump_3.3.0_amd64.deb
│ └── Windows
│ │ ├── export.bat
│ │ ├── procdump.exe
│ │ ├── procdump64.exe
│ │ └── procdump64a.exe
├── Bowl.cs
├── Common
│ └── git.keep
├── GeneralUpdate.Bowl.csproj
├── Internal
│ ├── Crash.cs
│ ├── CrashJsonContext.cs
│ └── LinuxSystem.cs
├── Strategys
│ ├── AbstractStrategy.cs
│ ├── IStrategy.cs
│ ├── LinuxStrategy.cs
│ ├── MonitorParameter.cs
│ └── WindowStrategy.cs
└── bowl.jpeg
├── GeneralUpdate.Client
├── GeneralUpdate.Client.csproj
└── Program.cs
├── GeneralUpdate.ClientCore
├── Common
│ └── git.keep
├── GeneralClientBootstrap.cs
├── GeneralClientOSS.cs
├── GeneralUpdate.ClientCore.csproj
├── GeneralUpdate.ico
├── GeneralUpdate.png
├── Hubs
│ ├── IUpgradeHubService.cs
│ ├── RandomRetryPolicy.cs
│ └── UpgradeHubService.cs
├── Pipeline
│ ├── CompressMiddleware.cs
│ ├── HashMiddleware.cs
│ └── PatchMiddleware.cs
├── Properties
│ └── launchSettings.json
└── Strategys
│ ├── LinuxStrategy.cs
│ └── WindowsStrategy.cs
├── GeneralUpdate.Common
├── Compress
│ ├── CompressProvider.cs
│ ├── ICompressionStrategy.cs
│ └── ZipCompressionStrategy.cs
├── Download
│ ├── DownloadManager.cs
│ ├── DownloadTask.cs
│ └── MultiEventArgs
│ │ ├── MutiAllDownloadCompletedEventArgs.cs
│ │ ├── MutiDownloadCompletedEventArgs.cs
│ │ ├── MutiDownloadErrorEventArgs.cs
│ │ └── MutiDownloadStatisticsEventArgs.cs
├── FileBasic
│ ├── BlackListManager.cs
│ ├── ComparisonResult.cs
│ ├── FileNode.cs
│ ├── FileTree.cs
│ └── StorageManager.cs
├── GeneralUpdate.Common.csproj
├── GeneralUpdate128.png
├── HashAlgorithms
│ ├── HashAlgorithmBase.cs
│ ├── Md5HashAlgorithm.cs
│ ├── Sha1HashAlgorithm.cs
│ └── Sha256HashAlgorithm.cs
├── Internal
│ ├── Bootstrap
│ │ ├── AbstractBootstrap.cs
│ │ ├── Environments.cs
│ │ ├── UpdateOption.cs
│ │ └── UpdateOptionValue.cs
│ ├── Event
│ │ ├── EventManager.cs
│ │ └── IEventManager.cs
│ ├── Exception
│ │ └── ExceptionEventArgs.cs
│ ├── JsonContext
│ │ ├── FileNodesJsonContext.cs
│ │ ├── GlobalConfigInfoOSSJsonContext.cs
│ │ ├── HttpParameterJsonContext.cs
│ │ ├── PacketJsonContext.cs
│ │ ├── ProcessInfoJsonContext.cs
│ │ ├── ReportRespJsonContext.cs
│ │ ├── VersionOSSJsonContext.cs
│ │ └── VersionRespJsonContext.cs
│ ├── Pipeline
│ │ ├── IMiddleware.cs
│ │ ├── PipelineBuilder.cs
│ │ └── PipelineContext.cs
│ └── Strategy
│ │ ├── AbstractStrategy.cs
│ │ └── IStrategy.cs
└── Shared
│ ├── Object
│ ├── Configinfo.cs
│ ├── DTO
│ │ ├── BaseResponseDTO.cs
│ │ └── VersionRespDTO.cs
│ ├── Enum
│ │ ├── AppType.cs
│ │ ├── Format.cs
│ │ ├── PlatformType.cs
│ │ └── ReportType.cs
│ ├── GlobalConfigInfo.cs
│ ├── GlobalConfigInfoOSS.cs
│ ├── Packet.cs
│ ├── ProcessInfo.cs
│ ├── VersionInfo.cs
│ └── VersionOSS.cs
│ └── Service
│ └── VersionService.cs
├── GeneralUpdate.Core
├── Common
│ └── git.keep
├── Driver
│ ├── BackupDriverCommand.cs
│ ├── CommandExecutor.cs
│ ├── DeleteDriverCommand.cs
│ ├── DriverCommand.cs
│ ├── DriverInfo.cs
│ ├── DriverInformation.cs
│ ├── DriverProcessor.cs
│ ├── InstallDriverCommand.cs
│ └── RestoreDriverCommand.cs
├── GeneralUpdate.Core.csproj
├── GeneralUpdate.ico
├── GeneralUpdate.png
├── GeneralUpdateBootstrap.cs
├── GeneralUpdateOSS.cs
├── Pipeline
│ ├── CompressMiddleware.cs
│ ├── DriverMiddleware.cs
│ ├── HashMiddleware.cs
│ └── PatchMiddleware.cs
├── Properties
│ ├── AssemblyInfo.cs
│ └── launchSettings.json
└── Strategys
│ ├── LinuxStrategy.cs
│ ├── OSSStrategy.cs
│ └── WindowsStrategy.cs
├── GeneralUpdate.Differential
├── Binary
│ ├── BZip2Constants.cs
│ ├── BZip2InputStream.cs
│ ├── BZip2OutputStream.cs
│ ├── BinaryHandler.cs
│ ├── IChecksum.cs
│ └── StrangeCRC.cs
├── DifferentialCore.cs
├── GeneralUpdate.Differential.csproj
├── GeneralUpdate.ico
├── GeneralUpdate.png
└── Properties
│ └── launchSettings.json
├── GeneralUpdate.Upgrad
├── GeneralUpdate.Upgrad.csproj
└── Program.cs
├── GeneralUpdate.sln
└── Generalupdate.CatBowl
├── Generalupdate.CatBowl.csproj
└── Program.cs
/.gitattributes:
--------------------------------------------------------------------------------
1 | ###############################################################################
2 | # Set default behavior to automatically normalize line endings.
3 | ###############################################################################
4 | * text=auto
5 |
6 | ###############################################################################
7 | # Set default behavior for command prompt diff.
8 | #
9 | # This is need for earlier builds of msysgit that does not have it on by
10 | # default for csharp files.
11 | # Note: This is only used by command line
12 | ###############################################################################
13 | #*.cs diff=csharp
14 |
15 | ###############################################################################
16 | # Set the merge driver for project and solution files
17 | #
18 | # Merging from the command prompt will add diff markers to the files if there
19 | # are conflicts (Merging from VS is not affected by the settings below, in VS
20 | # the diff markers are never inserted). Diff markers may cause the following
21 | # file extensions to fail to load in VS. An alternative would be to treat
22 | # these files as binary and thus will always conflict and require user
23 | # intervention with every merge. To do so, just uncomment the entries below
24 | ###############################################################################
25 | #*.sln merge=binary
26 | #*.csproj merge=binary
27 | #*.vbproj merge=binary
28 | #*.vcxproj merge=binary
29 | #*.vcproj merge=binary
30 | #*.dbproj merge=binary
31 | #*.fsproj merge=binary
32 | #*.lsproj merge=binary
33 | #*.wixproj merge=binary
34 | #*.modelproj merge=binary
35 | #*.sqlproj merge=binary
36 | #*.wwaproj merge=binary
37 |
38 | ###############################################################################
39 | # behavior for image files
40 | #
41 | # image files are treated as binary by default.
42 | ###############################################################################
43 | #*.jpg binary
44 | #*.png binary
45 | #*.gif binary
46 |
47 | ###############################################################################
48 | # diff behavior for common document formats
49 | #
50 | # Convert binary document formats to text before diffing them. This feature
51 | # is only available from the command line. Turn it on by uncommenting the
52 | # entries below.
53 | ###############################################################################
54 | #*.doc diff=astextplain
55 | #*.DOC diff=astextplain
56 | #*.docx diff=astextplain
57 | #*.DOCX diff=astextplain
58 | #*.dot diff=astextplain
59 | #*.DOT diff=astextplain
60 | #*.pdf diff=astextplain
61 | #*.PDF diff=astextplain
62 | #*.rtf diff=astextplain
63 | #*.RTF diff=astextplain
64 |
--------------------------------------------------------------------------------
/.github/workflows/dotnet-ci.yaml:
--------------------------------------------------------------------------------
1 | name: dotnet-ci
2 |
3 | on: [push, pull_request]
4 |
5 | jobs:
6 | build:
7 | runs-on: windows-latest
8 |
9 | steps:
10 | - uses: actions/checkout@v3
11 | - name: Setup .NET SDK
12 | uses: actions/setup-dotnet@v2
13 | with:
14 | dotnet-version: '9.0.x'
15 | - name: Restore dependencies
16 | run: dotnet restore ./src/c#/GeneralUpdate.sln
17 | - name: build
18 | run: dotnet build ./src/c#/GeneralUpdate.sln -c Release
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | ## Ignore Visual Studio temporary files, build results, and
2 | ## files generated by popular Visual Studio add-ons.
3 |
4 | # User-specific files
5 | *.suo
6 | *.user
7 | *.sln.docstates
8 |
9 | # Build results
10 | [Dd]ebug/
11 | [Dd]ebugPublic/
12 | [Rr]elease/
13 | [Rr]eleases/
14 | x64/
15 | x86/
16 | build/
17 | bld/
18 | [Bb]in/
19 | [Oo]bj/
20 | *.vs/
21 |
22 | # Roslyn cache directories
23 | *.ide/
24 |
25 | # MSTest test Results
26 | [Tt]est[Rr]esult*/
27 | [Bb]uild[Ll]og.*
28 |
29 | #NUNIT
30 | *.VisualState.xml
31 | TestResult.xml
32 |
33 | # Build Results of an ATL Project
34 | [Dd]ebugPS/
35 | [Rr]eleasePS/
36 | dlldata.c
37 |
38 | *_i.c
39 | *_p.c
40 | *_i.h
41 | *.ilk
42 | *.meta
43 | *.obj
44 | *.pch
45 | *.pdb
46 | *.pgc
47 | *.pgd
48 | *.rsp
49 | *.sbr
50 | *.tlb
51 | *.tli
52 | *.tlh
53 | *.tmp
54 | *.tmp_proj
55 | *.log
56 | *.vspscc
57 | *.vssscc
58 | .builds
59 | *.pidb
60 | *.svclog
61 | *.scc
62 |
63 | # Chutzpah Test files
64 | _Chutzpah*
65 |
66 | # Visual C++ cache files
67 | ipch/
68 | *.aps
69 | *.ncb
70 | *.opensdf
71 | *.sdf
72 | *.cachefile
73 |
74 | # Visual Studio profiler
75 | *.psess
76 | *.vsp
77 | *.vspx
78 |
79 | # TFS 2012 Local Workspace
80 | $tf/
81 |
82 | # Guidance Automation Toolkit
83 | *.gpState
84 |
85 | # ReSharper is a .NET coding add-in
86 | _ReSharper*/
87 | *.[Rr]e[Ss]harper
88 | *.DotSettings.user
89 |
90 | # JustCode is a .NET coding addin-in
91 | .JustCode
92 |
93 | # TeamCity is a build add-in
94 | _TeamCity*
95 |
96 | # DotCover is a Code Coverage Tool
97 | *.dotCover
98 |
99 | # NCrunch
100 | _NCrunch_*
101 | .*crunch*.local.xml
102 |
103 | # MightyMoose
104 | *.mm.*
105 | AutoTest.Net/
106 |
107 | # Web workbench (sass)
108 | .sass-cache/
109 |
110 | # Installshield output folder
111 | [Ee]xpress/
112 |
113 | # DocProject is a documentation generator add-in
114 | DocProject/buildhelp/
115 | DocProject/Help/*.HxT
116 | DocProject/Help/*.HxC
117 | DocProject/Help/*.hhc
118 | DocProject/Help/*.hhk
119 | DocProject/Help/*.hhp
120 | DocProject/Help/Html2
121 | DocProject/Help/html
122 |
123 | # Click-Once directory
124 | publish/
125 |
126 | # Publish Web Output
127 | *.[Pp]ublish.xml
128 | *.azurePubxml
129 | # TODO: Comment the next line if you want to checkin your web deploy settings
130 | # but database connection strings (with potential passwords) will be unencrypted
131 | *.pubxml
132 | *.publishproj
133 |
134 | # NuGet Packages
135 | *.nupkg
136 | # The packages folder can be ignored because of Package Restore
137 | **/packages/*
138 | # except build/, which is used as an MSBuild target.
139 | !**/packages/build/
140 | # If using the old MSBuild-Integrated Package Restore, uncomment this:
141 | #!**/packages/repositories.config
142 |
143 | # Windows Azure Build Output
144 | csx/
145 | *.build.csdef
146 |
147 | # Windows Store app package directory
148 | AppPackages/
149 |
150 | # Others
151 | sql/
152 | *.Cache
153 | ClientBin/
154 | [Ss]tyle[Cc]op.*
155 | ~$*
156 | *~
157 | *.dbmdl
158 | *.dbproj.schemaview
159 | *.pfx
160 | *.publishsettings
161 | node_modules/
162 |
163 | # RIA/Silverlight projects
164 | Generated_Code/
165 |
166 | # Backup & report files from converting an old project file
167 | # to a newer Visual Studio version. Backup files are not needed,
168 | # because we have git ;-)
169 | _UpgradeReport_Files/
170 | Backup*/
171 | UpgradeLog*.XML
172 | UpgradeLog*.htm
173 |
174 | # SQL Server files
175 | *.mdf
176 | *.ldf
177 |
178 | # Business Intelligence projects
179 | *.rdl.data
180 | *.bim.layout
181 | *.bim_*.settings
182 |
183 | # Microsoft Fakes
184 | FakesAssemblies/
185 |
186 | # SVN Repo
187 | .svn/
188 | *.vsidx
189 | *.v2
190 | *.lock
191 | *.txt
192 | *.v3
193 | *.v5
194 | src/c\#/.vs
195 | src/c\#/.idea
196 | src/c\#/global.json
197 |
--------------------------------------------------------------------------------
/NuGet.Config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/git_push.bat:
--------------------------------------------------------------------------------
1 | @echo off
2 |
3 | git remote -v
4 |
5 | set /p commitmessage=Git commit message:
6 |
7 | git add .
8 |
9 | git commit -m "%commitMessage%"
10 |
11 | echo Pushing to default remote repository...
12 | git push
13 | if %errorlevel% neq 0 (
14 | echo Failed to push to default remote repository.
15 | pause
16 | exit /b %errorlevel%
17 | )
18 |
19 | echo Pushing to upstream remote on 'master' branch...
20 | git push upstream master
21 | if %errorlevel% neq 0 (
22 | echo Failed to push to upstream remote on 'main' branch.
23 | pause
24 | exit /b %errorlevel%
25 | )
26 |
27 | echo Pushing to 'upstream_gitcode' remote on 'master' branch...
28 | git push upstream_gitcode master
29 | if %errorlevel% neq 0 (
30 | echo Failed to push to 'upstream_gitcode' remote on 'main' branch.
31 | pause
32 | exit /b %errorlevel%
33 | )
34 |
35 | echo All pushes completed successfully.
36 | pause
--------------------------------------------------------------------------------
/imgs/GeneralUpdate.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GeneralLibrary/GeneralUpdate/69c16da6d74b6a1e8cfbf571b9d49e1b5a820da2/imgs/GeneralUpdate.ico
--------------------------------------------------------------------------------
/imgs/GeneralUpdate.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GeneralLibrary/GeneralUpdate/69c16da6d74b6a1e8cfbf571b9d49e1b5a820da2/imgs/GeneralUpdate.png
--------------------------------------------------------------------------------
/imgs/GeneralUpdate128.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GeneralLibrary/GeneralUpdate/69c16da6d74b6a1e8cfbf571b9d49e1b5a820da2/imgs/GeneralUpdate128.png
--------------------------------------------------------------------------------
/imgs/GeneralUpdate_h.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GeneralLibrary/GeneralUpdate/69c16da6d74b6a1e8cfbf571b9d49e1b5a820da2/imgs/GeneralUpdate_h.png
--------------------------------------------------------------------------------
/imgs/GeneralUpdate_h2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GeneralLibrary/GeneralUpdate/69c16da6d74b6a1e8cfbf571b9d49e1b5a820da2/imgs/GeneralUpdate_h2.png
--------------------------------------------------------------------------------
/imgs/WPFPage_16x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GeneralLibrary/GeneralUpdate/69c16da6d74b6a1e8cfbf571b9d49e1b5a820da2/imgs/WPFPage_16x.png
--------------------------------------------------------------------------------
/imgs/Windows.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GeneralLibrary/GeneralUpdate/69c16da6d74b6a1e8cfbf571b9d49e1b5a820da2/imgs/Windows.png
--------------------------------------------------------------------------------
/imgs/bowl.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GeneralLibrary/GeneralUpdate/69c16da6d74b6a1e8cfbf571b9d49e1b5a820da2/imgs/bowl.jpeg
--------------------------------------------------------------------------------
/imgs/contact.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GeneralLibrary/GeneralUpdate/69c16da6d74b6a1e8cfbf571b9d49e1b5a820da2/imgs/contact.png
--------------------------------------------------------------------------------
/imgs/dot-net-plain-wordmark.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GeneralLibrary/GeneralUpdate/69c16da6d74b6a1e8cfbf571b9d49e1b5a820da2/imgs/dot-net-plain-wordmark.png
--------------------------------------------------------------------------------
/imgs/gitcode.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GeneralLibrary/GeneralUpdate/69c16da6d74b6a1e8cfbf571b9d49e1b5a820da2/imgs/gitcode.jpg
--------------------------------------------------------------------------------
/imgs/gitee.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GeneralLibrary/GeneralUpdate/69c16da6d74b6a1e8cfbf571b9d49e1b5a820da2/imgs/gitee.png
--------------------------------------------------------------------------------
/imgs/github.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GeneralLibrary/GeneralUpdate/69c16da6d74b6a1e8cfbf571b9d49e1b5a820da2/imgs/github.png
--------------------------------------------------------------------------------
/imgs/linux.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GeneralLibrary/GeneralUpdate/69c16da6d74b6a1e8cfbf571b9d49e1b5a820da2/imgs/linux.png
--------------------------------------------------------------------------------
/imgs/purple-border-gradient-icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GeneralLibrary/GeneralUpdate/69c16da6d74b6a1e8cfbf571b9d49e1b5a820da2/imgs/purple-border-gradient-icon.png
--------------------------------------------------------------------------------
/imgs/toolkit.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GeneralLibrary/GeneralUpdate/69c16da6d74b6a1e8cfbf571b9d49e1b5a820da2/imgs/toolkit.png
--------------------------------------------------------------------------------
/imgs/ubuntu.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GeneralLibrary/GeneralUpdate/69c16da6d74b6a1e8cfbf571b9d49e1b5a820da2/imgs/ubuntu.png
--------------------------------------------------------------------------------
/imgs/ui.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GeneralLibrary/GeneralUpdate/69c16da6d74b6a1e8cfbf571b9d49e1b5a820da2/imgs/ui.png
--------------------------------------------------------------------------------
/imgs/winui.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GeneralLibrary/GeneralUpdate/69c16da6d74b6a1e8cfbf571b9d49e1b5a820da2/imgs/winui.png
--------------------------------------------------------------------------------
/imgs/统信UOS.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GeneralLibrary/GeneralUpdate/69c16da6d74b6a1e8cfbf571b9d49e1b5a820da2/imgs/统信UOS.png
--------------------------------------------------------------------------------
/imgs/麒麟.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GeneralLibrary/GeneralUpdate/69c16da6d74b6a1e8cfbf571b9d49e1b5a820da2/imgs/麒麟.png
--------------------------------------------------------------------------------
/imgs/龙芯.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GeneralLibrary/GeneralUpdate/69c16da6d74b6a1e8cfbf571b9d49e1b5a820da2/imgs/龙芯.png
--------------------------------------------------------------------------------
/src/c#/GeneralUpdate.Bowl/Applications/Linux/install.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | # 获取脚本的实际名称
4 | SCRIPT_NAME=$(basename "\$0")
5 |
6 | # 检查是否提供了参数
7 | if [ "$#" -ne 1 ]; then
8 | echo "Usage: $SCRIPT_NAME "
9 | exit 1
10 | fi
11 |
12 | PACKAGE_FILE=\$1
13 |
14 | # 检查文件类型并安装
15 | if [[ "$PACKAGE_FILE" == *.rpm ]]; then
16 | if command -v rpm &> /dev/null; then
17 | sudo rpm -ivh "$PACKAGE_FILE" || { echo "Failed to install $PACKAGE_FILE using rpm"; exit 1; }
18 | elif command -v dnf &> /dev/null; then
19 | sudo dnf install -y "$PACKAGE_FILE" || { echo "Failed to install $PACKAGE_FILE using dnf"; exit 1; }
20 | elif command -v yum &> /dev/null; then
21 | sudo yum install -y "$PACKAGE_FILE" || { echo "Failed to install $PACKAGE_FILE using yum"; exit 1; }
22 | else
23 | echo "RPM package manager not found."
24 | exit 1
25 | fi
26 | elif [[ "$PACKAGE_FILE" == *.deb ]]; then
27 | if command -v dpkg &> /dev/null; then
28 | sudo dpkg -i "$PACKAGE_FILE" || { echo "Failed to install $PACKAGE_FILE using dpkg"; exit 1; }
29 | sudo apt-get install -f -y || { echo "Failed to fix dependencies"; exit 1; }
30 | else
31 | echo "DEB package manager not found."
32 | exit 1
33 | fi
34 | else
35 | echo "Unsupported package format."
36 | exit 1
37 | fi
38 |
39 | echo "Installation of $PACKAGE_FILE completed."
--------------------------------------------------------------------------------
/src/c#/GeneralUpdate.Bowl/Applications/Linux/procdump-3.3.0-0.cm2.x86_64.rpm:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GeneralLibrary/GeneralUpdate/69c16da6d74b6a1e8cfbf571b9d49e1b5a820da2/src/c#/GeneralUpdate.Bowl/Applications/Linux/procdump-3.3.0-0.cm2.x86_64.rpm
--------------------------------------------------------------------------------
/src/c#/GeneralUpdate.Bowl/Applications/Linux/procdump-3.3.0-0.el8.x86_64.rpm:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GeneralLibrary/GeneralUpdate/69c16da6d74b6a1e8cfbf571b9d49e1b5a820da2/src/c#/GeneralUpdate.Bowl/Applications/Linux/procdump-3.3.0-0.el8.x86_64.rpm
--------------------------------------------------------------------------------
/src/c#/GeneralUpdate.Bowl/Applications/Linux/procdump_3.3.0_amd64.deb:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GeneralLibrary/GeneralUpdate/69c16da6d74b6a1e8cfbf571b9d49e1b5a820da2/src/c#/GeneralUpdate.Bowl/Applications/Linux/procdump_3.3.0_amd64.deb
--------------------------------------------------------------------------------
/src/c#/GeneralUpdate.Bowl/Applications/Windows/export.bat:
--------------------------------------------------------------------------------
1 | @echo off
2 | setlocal
3 |
4 | if "%~1"=="" (
5 | echo Please provide the export path as the first parameter.
6 | exit /b 1
7 | )
8 |
9 | set exportDir=%~1
10 |
11 | if not exist "%exportDir%" (
12 | mkdir "%exportDir%"
13 | )
14 |
15 | set outputFile=%exportDir%\driverInfo.txt
16 |
17 | :: 导出驱动信息
18 | driverquery /v /fo table > "%outputFile%"
19 | echo %outputFile% Export successfully.
20 |
21 | :: 导出系统信息
22 | set systemInfoFile=%exportDir%\systeminfo.txt
23 | systeminfo > "%systemInfoFile%"
24 | echo %systemInfoFile% Export successfully.
25 |
26 | :: 获取当前日期
27 | for /f "tokens=1-4 delims=/- " %%i in ('date /t') do (
28 | set yyyy=%%i
29 | set mm=%%j
30 | set dd=%%k
31 | )
32 |
33 | :: 设置日志文件名
34 | set logFile=%exportDir%\systemlog.evtx
35 |
36 | :: 导出系统日志
37 | wevtutil epl System "%logFile%" /q:"*[System[TimeCreated[timediff(@SystemTime) <= 86400000]]]"
38 | echo %logFile% Export successfully.
39 |
40 | endlocal
--------------------------------------------------------------------------------
/src/c#/GeneralUpdate.Bowl/Applications/Windows/procdump.exe:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GeneralLibrary/GeneralUpdate/69c16da6d74b6a1e8cfbf571b9d49e1b5a820da2/src/c#/GeneralUpdate.Bowl/Applications/Windows/procdump.exe
--------------------------------------------------------------------------------
/src/c#/GeneralUpdate.Bowl/Applications/Windows/procdump64.exe:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GeneralLibrary/GeneralUpdate/69c16da6d74b6a1e8cfbf571b9d49e1b5a820da2/src/c#/GeneralUpdate.Bowl/Applications/Windows/procdump64.exe
--------------------------------------------------------------------------------
/src/c#/GeneralUpdate.Bowl/Applications/Windows/procdump64a.exe:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GeneralLibrary/GeneralUpdate/69c16da6d74b6a1e8cfbf571b9d49e1b5a820da2/src/c#/GeneralUpdate.Bowl/Applications/Windows/procdump64a.exe
--------------------------------------------------------------------------------
/src/c#/GeneralUpdate.Bowl/Bowl.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.IO;
3 | using System.Runtime.InteropServices;
4 | using System.Text.Json;
5 | using GeneralUpdate.Bowl.Strategys;
6 | using GeneralUpdate.Common.Internal.Bootstrap;
7 | using GeneralUpdate.Common.Internal.JsonContext;
8 | using GeneralUpdate.Common.Shared.Object;
9 |
10 | namespace GeneralUpdate.Bowl;
11 |
12 | ///
13 | /// Surveillance Main Program.
14 | ///
15 | public sealed class Bowl
16 | {
17 | private static IStrategy? _strategy;
18 |
19 | private Bowl() { }
20 |
21 | private static void CreateStrategy()
22 | {
23 | if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
24 | _strategy = new WindowStrategy();
25 |
26 | if (_strategy == null)
27 | throw new PlatformNotSupportedException("Unsupported operating system");
28 | }
29 |
30 | public static void Launch(MonitorParameter? monitorParameter = null)
31 | {
32 | monitorParameter ??= CreateParameter();
33 | CreateStrategy();
34 | _strategy?.SetParameter(monitorParameter);
35 | _strategy?.Launch();
36 | }
37 |
38 | private static MonitorParameter CreateParameter()
39 | {
40 | var json = Environments.GetEnvironmentVariable("ProcessInfo");
41 | if(string.IsNullOrWhiteSpace(json))
42 | throw new ArgumentNullException("ProcessInfo environment variable not set !");
43 |
44 | var processInfo = JsonSerializer.Deserialize(json, ProcessInfoJsonContext.Default.ProcessInfo);
45 | if(processInfo == null)
46 | throw new ArgumentNullException("ProcessInfo json deserialize fail!");
47 |
48 | return new MonitorParameter
49 | {
50 | ProcessNameOrId = processInfo.AppName,
51 | DumpFileName = $"{processInfo.LastVersion}_fail.dmp",
52 | FailFileName = $"{processInfo.LastVersion}_fail.json",
53 | TargetPath = processInfo.InstallPath,
54 | FailDirectory = Path.Combine(processInfo.InstallPath, "fail", processInfo.LastVersion),
55 | BackupDirectory = Path.Combine(processInfo.InstallPath, processInfo.LastVersion),
56 | ExtendedField = processInfo.LastVersion
57 | };
58 | }
59 | }
--------------------------------------------------------------------------------
/src/c#/GeneralUpdate.Bowl/Common/git.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GeneralLibrary/GeneralUpdate/69c16da6d74b6a1e8cfbf571b9d49e1b5a820da2/src/c#/GeneralUpdate.Bowl/Common/git.keep
--------------------------------------------------------------------------------
/src/c#/GeneralUpdate.Bowl/Internal/Crash.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using GeneralUpdate.Bowl.Strategys;
3 |
4 | namespace GeneralUpdate.Bowl.Internal;
5 |
6 | internal class Crash
7 | {
8 | public MonitorParameter Parameter { get; set; }
9 |
10 | public List ProcdumpOutPutLines { get; set; }
11 | }
--------------------------------------------------------------------------------
/src/c#/GeneralUpdate.Bowl/Internal/CrashJsonContext.cs:
--------------------------------------------------------------------------------
1 | using System.Text.Json.Serialization;
2 |
3 | namespace GeneralUpdate.Bowl.Internal;
4 |
5 | [JsonSerializable(typeof(Crash))]
6 | internal partial class CrashJsonContext : JsonSerializerContext;
--------------------------------------------------------------------------------
/src/c#/GeneralUpdate.Bowl/Internal/LinuxSystem.cs:
--------------------------------------------------------------------------------
1 | namespace GeneralUpdate.Bowl.Internal;
2 |
3 | internal class LinuxSystem
4 | {
5 | internal string Name { get; set; }
6 |
7 | internal string Version { get; set; }
8 |
9 | internal LinuxSystem(string name, string version)
10 | {
11 | Name = name;
12 | Version = version;
13 | }
14 | }
--------------------------------------------------------------------------------
/src/c#/GeneralUpdate.Bowl/Strategys/AbstractStrategy.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using System.Diagnostics;
3 | using System.IO;
4 | using GeneralUpdate.Common.FileBasic;
5 |
6 | namespace GeneralUpdate.Bowl.Strategys;
7 |
8 | internal abstract class AbstractStrategy : IStrategy
9 | {
10 | protected MonitorParameter _parameter;
11 | protected List OutputList = new ();
12 |
13 | public void SetParameter(MonitorParameter parameter) => _parameter = parameter;
14 |
15 | public virtual void Launch()
16 | {
17 | Startup(_parameter.InnerApp, _parameter.InnerArguments);
18 | }
19 |
20 | private void Startup(string appName, string arguments)
21 | {
22 | if (Directory.Exists(_parameter.FailDirectory))
23 | {
24 | StorageManager.DeleteDirectory(_parameter.FailDirectory);
25 | }
26 | Directory.CreateDirectory(_parameter.FailDirectory);
27 |
28 | var startInfo = new ProcessStartInfo
29 | {
30 | FileName = appName,
31 | Arguments = arguments,
32 | RedirectStandardOutput = true,
33 | RedirectStandardError = true,
34 | UseShellExecute = false,
35 | CreateNoWindow = true
36 | };
37 |
38 | var process = new Process { StartInfo = startInfo };
39 | process.OutputDataReceived += OutputHandler;
40 | process.ErrorDataReceived += OutputHandler;
41 | process.Start();
42 | process.BeginOutputReadLine();
43 | process.BeginErrorReadLine();
44 | process.WaitForExit(1000 * 10);
45 | }
46 |
47 | private void OutputHandler(object sendingProcess, DataReceivedEventArgs outLine)
48 | {
49 | var data = outLine.Data;
50 | if (!string.IsNullOrEmpty(data))
51 | OutputList.Add(data);
52 | }
53 | }
--------------------------------------------------------------------------------
/src/c#/GeneralUpdate.Bowl/Strategys/IStrategy.cs:
--------------------------------------------------------------------------------
1 | using GeneralUpdate.Bowl.Internal;
2 |
3 | namespace GeneralUpdate.Bowl.Strategys;
4 |
5 | internal interface IStrategy
6 | {
7 | void Launch();
8 |
9 | void SetParameter(MonitorParameter parameter);
10 | }
--------------------------------------------------------------------------------
/src/c#/GeneralUpdate.Bowl/Strategys/LinuxStrategy.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Diagnostics;
4 | using System.IO;
5 | using System.Linq;
6 | using GeneralUpdate.Bowl.Internal;
7 |
8 | namespace GeneralUpdate.Bowl.Strategys;
9 |
10 | internal class LinuxStrategy : AbstractStrategy
11 | {
12 | /*procdump-3.3.0-0.cm2.x86_64.rpm:
13 | 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.
14 |
15 | procdump-3.3.0-0.el8.x86_64.rpm:
16 | Compatible Systems: This RPM package is suitable for Red Hat Enterprise Linux 8 (RHEL 8), CentOS 8, and other RHEL 8-based distributions.
17 |
18 | procdump_3.3.0_amd64.deb:
19 | Compatible Systems: This DEB package is suitable for Debian and its derivatives, such as Ubuntu, for 64-bit systems (amd64 architecture).*/
20 |
21 | private IReadOnlyList _rocdumpAmd64 = new List { "Ubuntu", "Debian" };
22 | private IReadOnlyList procdump_el8_x86_64 = new List { "Red Hat", "CentOS", "Fedora" };
23 | private IReadOnlyList procdump_cm2_x86_64 = new List { "ClearOS" };
24 |
25 | public override void Launch()
26 | {
27 | Install();
28 | base.Launch();
29 | }
30 |
31 | private void Install()
32 | {
33 | string scriptPath = "./install.sh";
34 | string packageFile = GetPacketName();
35 |
36 | ProcessStartInfo processStartInfo = new ProcessStartInfo()
37 | {
38 | FileName = "/bin/bash",
39 | Arguments = $"{scriptPath} {packageFile}",
40 | RedirectStandardOutput = true,
41 | RedirectStandardError = true,
42 | UseShellExecute = false,
43 | CreateNoWindow = true
44 | };
45 |
46 | try
47 | {
48 | using Process process = Process.Start(processStartInfo);
49 | string output = process.StandardOutput.ReadToEnd();
50 | string error = process.StandardError.ReadToEnd();
51 | process.WaitForExit();
52 |
53 | Console.WriteLine("Output:");
54 | Console.WriteLine(output);
55 |
56 | if (!string.IsNullOrEmpty(error))
57 | {
58 | Console.WriteLine("Error:");
59 | Console.WriteLine(error);
60 | }
61 | }
62 | catch (Exception e)
63 | {
64 | Console.WriteLine($"An error occurred: {e.Message}");
65 | }
66 | }
67 |
68 | private string GetPacketName()
69 | {
70 | var packageFileName = string.Empty;
71 | var system = GetSystem();
72 | if (_rocdumpAmd64.Contains(system.Name))
73 | {
74 | packageFileName = $"procdump_3.3.0_amd64.deb";
75 | }
76 | else if (procdump_el8_x86_64.Contains(system.Name))
77 | {
78 | packageFileName = $"procdump-3.3.0-0.el8.x86_64.rpm";
79 | }
80 | else if (procdump_cm2_x86_64.Contains(system.Name))
81 | {
82 | packageFileName = $"procdump-3.3.0-0.cm2.x86_64.rpm";
83 | }
84 |
85 | return packageFileName;
86 | }
87 |
88 | private LinuxSystem GetSystem()
89 | {
90 | string osReleaseFile = "/etc/os-release";
91 | if (File.Exists(osReleaseFile))
92 | {
93 | var lines = File.ReadAllLines(osReleaseFile);
94 | string distro = string.Empty;
95 | string version = string.Empty;
96 |
97 | foreach (var line in lines)
98 | {
99 | if (line.StartsWith("ID="))
100 | {
101 | distro = line.Substring(3).Trim('\"');
102 | }
103 | else if (line.StartsWith("VERSION_ID="))
104 | {
105 | version = line.Substring(11).Trim('\"');
106 | }
107 | }
108 |
109 | return new LinuxSystem(distro, version);
110 | }
111 |
112 | throw new FileNotFoundException("Cannot determine the Linux distribution. The /etc/os-release file does not exist.");
113 | }
114 | }
--------------------------------------------------------------------------------
/src/c#/GeneralUpdate.Bowl/Strategys/MonitorParameter.cs:
--------------------------------------------------------------------------------
1 | namespace GeneralUpdate.Bowl.Strategys;
2 |
3 | public class MonitorParameter
4 | {
5 | public MonitorParameter() { }
6 |
7 | public string TargetPath { get; set; }
8 |
9 | public string FailDirectory { get; set; }
10 |
11 | public string BackupDirectory { get; set; }
12 |
13 | public string ProcessNameOrId { get; set; }
14 |
15 | public string DumpFileName { get; set; }
16 |
17 | public string FailFileName { get; set; }
18 |
19 | internal string InnerArguments { get; set; }
20 |
21 | internal string InnerApp { get; set; }
22 |
23 | ///
24 | /// 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.
25 | /// Normal: Normal mode,This mode can be used independently to monitor a single program. If the program crashes, it will export the crash information.
26 | ///
27 | public string WorkModel { get; set; } = "Upgrade";
28 |
29 | public string ExtendedField { get; set; }
30 | }
--------------------------------------------------------------------------------
/src/c#/GeneralUpdate.Bowl/Strategys/WindowStrategy.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Diagnostics;
4 | using System.IO;
5 | using System.Runtime.InteropServices;
6 | using GeneralUpdate.Bowl.Internal;
7 | using GeneralUpdate.Common.FileBasic;
8 | using GeneralUpdate.Common.Internal.Bootstrap;
9 |
10 | namespace GeneralUpdate.Bowl.Strategys;
11 |
12 | internal class WindowStrategy : AbstractStrategy
13 | {
14 | private const string WorkModel = "Upgrade";
15 | private string? _applicationsDirectory;
16 | private List _actions = new();
17 |
18 | public override void Launch()
19 | {
20 | InitializeActions();
21 | _applicationsDirectory = Path.Combine(_parameter.TargetPath, "Applications", "Windows");
22 | _parameter.InnerApp = Path.Combine(_applicationsDirectory, GetAppName());
23 | var dmpFullName = Path.Combine(_parameter.FailDirectory, _parameter.DumpFileName);
24 | _parameter.InnerArguments = $"-e -ma {_parameter.ProcessNameOrId} {dmpFullName}";
25 | //This method is used to launch scripts in applications.
26 | base.Launch();
27 | ExecuteFinalTreatment();
28 | }
29 |
30 | private string GetAppName() => RuntimeInformation.OSArchitecture switch
31 | {
32 | Architecture.X86 => "procdump.exe",
33 | Architecture.X64 => "procdump64.exe",
34 | _ => "procdump64a.exe"
35 | };
36 |
37 | private void ExecuteFinalTreatment()
38 | {
39 | var dumpFile = Path.Combine(_parameter.FailDirectory, _parameter.DumpFileName);
40 | if (File.Exists(dumpFile))
41 | {
42 | foreach (var action in _actions)
43 | {
44 | action.Invoke();
45 | }
46 | }
47 | }
48 |
49 | private void InitializeActions()
50 | {
51 | _actions.Add(CreateCrash);
52 | _actions.Add(Export);
53 | _actions.Add(Restore);
54 | _actions.Add(SetEnvironment);
55 | }
56 |
57 | ///
58 | /// Export the crash output information from procdump.exe and the monitoring parameters of Bowl.
59 | ///
60 | private void CreateCrash()
61 | {
62 | var crash = new Crash
63 | {
64 | Parameter = _parameter,
65 | ProcdumpOutPutLines = OutputList
66 | };
67 | var failJsonPath = Path.Combine(_parameter.FailDirectory, _parameter.FailFileName);
68 | StorageManager.CreateJson(failJsonPath, crash, CrashJsonContext.Default.Crash);
69 | }
70 |
71 | ///
72 | /// Export operating system information, system logs, and system driver information.
73 | ///
74 | private void Export()
75 | {
76 | var batPath = Path.Combine(_applicationsDirectory, "export.bat");
77 | if(!File.Exists(batPath))
78 | throw new FileNotFoundException("export.bat not found!");
79 |
80 | Process.Start(batPath, _parameter.FailDirectory);
81 | }
82 |
83 | ///
84 | /// Within the GeneralUpdate upgrade system, restore the specified backup version files to the current working directory.
85 | ///
86 | private void Restore()
87 | {
88 | if (string.Equals(_parameter.WorkModel, WorkModel))
89 | StorageManager.Restore(_parameter.BackupDirectory, _parameter.TargetPath);
90 | }
91 |
92 | ///
93 | /// Write the failed update version number to the local environment variable.
94 | ///
95 | private void SetEnvironment()
96 | {
97 | if (!string.Equals(_parameter.WorkModel, WorkModel))
98 | return;
99 |
100 | /*
101 | * The `UpgradeFail` environment variable is used to mark an exception version number during updates.
102 | * If the latest version number obtained via an HTTP request is less than or equal to the exception version number, the update is skipped.
103 | * 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.
104 | */
105 | Environments.SetEnvironmentVariable("UpgradeFail", _parameter.ExtendedField);
106 | }
107 | }
--------------------------------------------------------------------------------
/src/c#/GeneralUpdate.Bowl/bowl.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GeneralLibrary/GeneralUpdate/69c16da6d74b6a1e8cfbf571b9d49e1b5a820da2/src/c#/GeneralUpdate.Bowl/bowl.jpeg
--------------------------------------------------------------------------------
/src/c#/GeneralUpdate.Client/GeneralUpdate.Client.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Exe
5 | net8.0
6 | enable
7 | enable
8 | default
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/src/c#/GeneralUpdate.Client/Program.cs:
--------------------------------------------------------------------------------
1 | using System.Diagnostics;
2 | using System.Text;
3 | using GeneralUpdate.ClientCore;
4 | using GeneralUpdate.ClientCore.Hubs;
5 | using GeneralUpdate.Common.Download;
6 | using GeneralUpdate.Common.Internal;
7 | using GeneralUpdate.Common.Internal.Bootstrap;
8 | using GeneralUpdate.Common.Shared.Object;
9 | using GeneralUpdate.Common.Shared.Object.Enum;
10 |
11 | namespace GeneralUpdate.Client
12 | {
13 | internal class Program
14 | {
15 | static async Task Main(string[] args)
16 | {
17 | try
18 | {
19 | Console.WriteLine($"主程序初始化,{DateTime.Now}!");
20 | Console.WriteLine("当前运行目录:" + Thread.GetDomain().BaseDirectory);
21 | await Task.Delay(2000);
22 | var configinfo = new Configinfo
23 | {
24 | //configinfo.UpdateLogUrl = "https://www.baidu.com";
25 | ReportUrl = "http://127.0.0.1:5000/Upgrade/Report",
26 | UpdateUrl = "http://127.0.0.1:5000/Upgrade/Verification",
27 | AppName = "GeneralUpdate.Upgrad.exe",
28 | MainAppName = "GeneralUpdate.Client.exe",
29 | InstallPath = Thread.GetDomain().BaseDirectory,
30 | //configinfo.Bowl = "Generalupdate.CatBowl.exe";
31 | //当前客户端的版本号
32 | ClientVersion = "1.0.0.0",
33 | //当前升级端的版本号
34 | UpgradeClientVersion = "1.0.0.0",
35 | //产品id
36 | ProductId = "2d974e2a-31e6-4887-9bb1-b4689e98c77a",
37 | //应用密钥
38 | AppSecretKey = "dfeb5833-975e-4afb-88f1-6278ee9aeff6"
39 | };
40 | _ = await new GeneralClientBootstrap() //单个或多个更新包下载通知事件
41 | //单个或多个更新包下载速度、剩余下载事件、当前下载版本信息通知事件
42 | .AddListenerMultiDownloadStatistics(OnMultiDownloadStatistics)
43 | //单个或多个更新包下载完成
44 | .AddListenerMultiDownloadCompleted(OnMultiDownloadCompleted)
45 | //完成所有的下载任务通知
46 | .AddListenerMultiAllDownloadCompleted(OnMultiAllDownloadCompleted)
47 | //下载过程出现的异常通知
48 | .AddListenerMultiDownloadError(OnMultiDownloadError)
49 | //整个更新过程出现的任何问题都会通过这个事件通知
50 | .AddListenerException(OnException)
51 | .SetConfig(configinfo)
52 | .Option(UpdateOption.DownloadTimeOut, 60)
53 | .Option(UpdateOption.Encoding, Encoding.UTF8)
54 | .LaunchAsync();
55 | Console.WriteLine($"主程序已启动,{DateTime.Now}!");
56 | }
57 | catch (Exception e)
58 | {
59 | Console.WriteLine(e.Message + "\n" + e.StackTrace);
60 | }
61 |
62 | /*var paramsOSS = new GlobalConfigInfoOSS
63 | {
64 | Url = @"http://localhost:5000/packages/versions.json",
65 | CurrentVersion = "1.0.0.0",
66 | VersionFileName = "versions.json",
67 | AppName = "GeneralUpdate.Client.exe",
68 | Encoding = Encoding.UTF8.WebName
69 | };
70 | await GeneralClientOSS.Start(paramsOSS, "GeneralUpdate.Upgrad.exe");*/
71 |
72 | /*var hub = new UpgradeHubService("http://localhost:5000/UpgradeHub"
73 | , null,"dfeb5833-975e-4afb-88f1-6278ee9aeff6");
74 | hub.AddListenerReceive((message) =>
75 | {
76 | Debug.WriteLine(message);
77 | });
78 | await hub.StartAsync();*/
79 |
80 | /*Task.Run(async () =>
81 | {
82 | var source = @"D:\packet\app";
83 | var target = @"D:\packet\release";
84 | var patch = @"D:\packet\patch";
85 |
86 | await DifferentialCore.Instance?.Clean(source, target, patch);
87 | await DifferentialCore.Instance?.Dirty(source, patch);
88 | });*/
89 |
90 | while (true)
91 | {
92 | var content = Console.ReadLine();
93 | if (content == "exit") break;
94 | }
95 | }
96 |
97 | private static void OnMultiDownloadError(object arg1, MultiDownloadErrorEventArgs arg2)
98 | {
99 | var version = arg2.Version as VersionInfo;
100 | Console.WriteLine($"{version.Version} {arg2.Exception}");
101 | }
102 |
103 | private static void OnMultiAllDownloadCompleted(object arg1, MultiAllDownloadCompletedEventArgs arg2)
104 | {
105 | Console.WriteLine(arg2.IsAllDownloadCompleted ? "所有的下载任务已完成!" : $"下载任务已失败!{arg2.FailedVersions.Count}");
106 | }
107 |
108 | private static void OnMultiDownloadCompleted(object arg1, MultiDownloadCompletedEventArgs arg2)
109 | {
110 | var version = arg2.Version as VersionInfo;
111 | Console.WriteLine(arg2.IsComplated ? $"当前下载版本:{version.Version}, 下载完成!" : $"当前下载版本:{version.Version}, 下载失败!");
112 | }
113 |
114 | private static void OnMultiDownloadStatistics(object arg1, MultiDownloadStatisticsEventArgs arg2)
115 | {
116 | var version = arg2.Version as VersionInfo;
117 | Console.WriteLine($"当前下载版本:{version.Version},下载速度:{arg2.Speed},剩余下载时间:{arg2.Remaining},已下载大小:{arg2.BytesReceived},总大小:{arg2.TotalBytesToReceive}, 进度百分比:{arg2.ProgressPercentage}%");
118 | }
119 |
120 | private static void OnException(object arg1, ExceptionEventArgs arg2)
121 | {
122 | Console.WriteLine($"{arg2.Exception}");
123 | }
124 | }
125 | }
--------------------------------------------------------------------------------
/src/c#/GeneralUpdate.ClientCore/Common/git.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GeneralLibrary/GeneralUpdate/69c16da6d74b6a1e8cfbf571b9d49e1b5a820da2/src/c#/GeneralUpdate.ClientCore/Common/git.keep
--------------------------------------------------------------------------------
/src/c#/GeneralUpdate.ClientCore/GeneralClientOSS.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Diagnostics;
4 | using System.IO;
5 | using System.Linq;
6 | using System.Net;
7 | using System.Text.Json;
8 | using System.Threading;
9 | using System.Threading.Tasks;
10 | using GeneralUpdate.Common.FileBasic;
11 | using GeneralUpdate.Common.Internal.Bootstrap;
12 | using GeneralUpdate.Common.Internal.JsonContext;
13 | using GeneralUpdate.Common.Shared.Object;
14 |
15 | namespace GeneralUpdate.ClientCore;
16 |
17 | public sealed class GeneralClientOSS
18 | {
19 | private GeneralClientOSS() { }
20 |
21 | ///
22 | /// Starting an OSS update for windows platform.
23 | ///
24 | public static async Task Start(GlobalConfigInfoOSS configGlobalConfigInfo, string upgradeAppName = "GeneralUpdate.Upgrade.exe")
25 | {
26 | await Task.Run(() =>
27 | {
28 | try
29 | {
30 | var basePath = Thread.GetDomain().BaseDirectory;
31 | //Download the version information file from OSS to be updated.(JSON)
32 | var versionsFilePath = Path.Combine(basePath, configGlobalConfigInfo.VersionFileName);
33 | DownloadFile(configGlobalConfigInfo.Url, versionsFilePath);
34 | if (!File.Exists(versionsFilePath)) return;
35 | var versions = StorageManager.GetJson>(versionsFilePath, VersionOSSJsonContext.Default.ListVersionOSS);
36 | if (versions == null || versions.Count == 0) return;
37 | versions = versions.OrderByDescending(x => x.PubTime).ToList();
38 | var newVersion = versions.First();
39 | //Determine whether the current client version needs to be upgraded.
40 | if (!IsUpgrade(configGlobalConfigInfo.CurrentVersion, newVersion.Version))
41 | return;
42 |
43 | //If you confirm that an update is required, start the upgrade application.
44 | var appPath = Path.Combine(basePath, $"{upgradeAppName}");
45 | if (!File.Exists(appPath))
46 | throw new Exception($"The application does not exist {upgradeAppName} !");
47 |
48 | var json = JsonSerializer.Serialize(configGlobalConfigInfo, GlobalConfigInfoOSSJsonContext.Default.GlobalConfigInfoOSS);
49 | Environments.SetEnvironmentVariable("GlobalConfigInfoOSS", json);
50 | Process.Start(appPath);
51 | Process.GetCurrentProcess().Kill();
52 | }
53 | catch (Exception ex)
54 | {
55 | var error = ex.Message + "\n" + ex.StackTrace;
56 | Trace.WriteLine(error);
57 | throw new Exception(error);
58 | }
59 | });
60 | }
61 |
62 | ///
63 | /// Determine whether the current client version needs to be upgraded.
64 | ///
65 | ///
66 | ///
67 | /// true: Upgrade required , false: No upgrade is required
68 | private static bool IsUpgrade(string clientVersion, string serverVersion)
69 | {
70 | if (string.IsNullOrWhiteSpace(clientVersion) || string.IsNullOrWhiteSpace(serverVersion))
71 | return false;
72 |
73 | var isParseClientVersion = Version.TryParse(clientVersion, out var currentClientVersion);
74 | var isParseServerVersion = Version.TryParse(serverVersion, out var currentServerVersion);
75 | if (!isParseClientVersion || !isParseServerVersion) return false;
76 | if (currentClientVersion < currentServerVersion) return true;
77 | return false;
78 | }
79 |
80 | private static void DownloadFile(string url, string path)
81 | {
82 | if (File.Exists(path))
83 | {
84 | File.SetAttributes(path, FileAttributes.Normal);
85 | File.Delete(path);
86 | }
87 |
88 | using var webClient = new WebClient();
89 | webClient.DownloadFile(new Uri(url), path);
90 | }
91 | }
--------------------------------------------------------------------------------
/src/c#/GeneralUpdate.ClientCore/GeneralUpdate.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GeneralLibrary/GeneralUpdate/69c16da6d74b6a1e8cfbf571b9d49e1b5a820da2/src/c#/GeneralUpdate.ClientCore/GeneralUpdate.ico
--------------------------------------------------------------------------------
/src/c#/GeneralUpdate.ClientCore/GeneralUpdate.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GeneralLibrary/GeneralUpdate/69c16da6d74b6a1e8cfbf571b9d49e1b5a820da2/src/c#/GeneralUpdate.ClientCore/GeneralUpdate.png
--------------------------------------------------------------------------------
/src/c#/GeneralUpdate.ClientCore/Hubs/IUpgradeHubService.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Threading.Tasks;
3 |
4 | namespace GeneralUpdate.ClientCore.Hubs;
5 |
6 | public interface IUpgradeHubService
7 | {
8 | ///
9 | /// Add a listener to receive upgrade information pushed from the server.
10 | ///
11 | /// string : group name , string : received message content.
12 | public void AddListenerReceive(Action receiveMessageCallback);
13 |
14 | ///
15 | /// Add a listener to receive online and offline notifications.
16 | ///
17 | /// string : Offline or online information.
18 | public void AddListenerOnline(Action onlineMessageCallback);
19 |
20 | ///
21 | /// Add a listener to receive reconnection notifications.
22 | ///
23 | /// string? : Reconnection information.
24 | public void AddListenerReconnected(Func? reconnectedCallback);
25 |
26 | ///
27 | /// Add a listener to receive disconnection notifications.
28 | ///
29 | /// Exception? : Offline exception information.
30 | public void AddListenerClosed(Func closeCallback);
31 |
32 | ///
33 | /// Start subscribing to upgrade push notifications, and the content of the notifications should be agreed upon independently (it is recommended to use JSON data format).
34 | ///
35 | public Task StartAsync();
36 |
37 | ///
38 | /// When closing the connection, any ongoing message processing will be completed, but no new messages will be accepted.
39 | /// This should be called before the application closes or goes to sleep, so it can reconnect when it resumes next time.
40 | ///
41 | public Task StopAsync();
42 |
43 | ///
44 | /// The Hub instance will be completely disposed of and cannot be used for reconnection.
45 | ///
46 | public Task DisposeAsync();
47 | }
--------------------------------------------------------------------------------
/src/c#/GeneralUpdate.ClientCore/Hubs/RandomRetryPolicy.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using Microsoft.AspNetCore.SignalR.Client;
3 |
4 | namespace GeneralUpdate.ClientCore.Hubs;
5 |
6 | public class RandomRetryPolicy : IRetryPolicy
7 | {
8 | private readonly Random _random = new();
9 |
10 | public TimeSpan? NextRetryDelay(RetryContext retryContext)
11 | {
12 | // If we've been reconnecting for less than 60 seconds so far,
13 | // wait between 0 and 10 seconds before the next reconnect attempt.
14 | if (retryContext.ElapsedTime < TimeSpan.FromSeconds(60))
15 | return TimeSpan.FromSeconds(_random.NextDouble() * 10);
16 | // If we've been reconnecting for more than 60 seconds so far, stop reconnecting.
17 | return null;
18 | }
19 | }
--------------------------------------------------------------------------------
/src/c#/GeneralUpdate.ClientCore/Hubs/UpgradeHubService.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Diagnostics;
3 | using System.Threading.Tasks;
4 | using GeneralUpdate.Common.Internal.JsonContext;
5 | using Microsoft.AspNetCore.SignalR;
6 | using Microsoft.AspNetCore.SignalR.Client;
7 | using Microsoft.Extensions.DependencyInjection;
8 |
9 | namespace GeneralUpdate.ClientCore.Hubs;
10 |
11 | ///
12 | /// Upgrade the push notification service.
13 | ///
14 | /// Subscription address, for example: http://127.0.0.1/UpgradeHub
15 | /// ID4 authentication token string.
16 | /// Parameters to be sent to the server upon connection (recommended as a JSON string).
17 | public class UpgradeHubService : IUpgradeHubService
18 | {
19 | private const string Onlineflag = "Online";
20 | private const string ReceiveMessageflag = "ReceiveMessage";
21 | private HubConnection? _connection;
22 |
23 | public UpgradeHubService(string url, string? token = null, string? appkey = null)
24 | => _connection = BuildHubConnection(url, token, appkey);
25 |
26 | private HubConnection BuildHubConnection(string url, string? token = null, string? appkey = null)
27 | {
28 | var builder = new HubConnectionBuilder()
29 | .WithUrl(url, config =>
30 | {
31 | if (!string.IsNullOrWhiteSpace(token))
32 | config.AccessTokenProvider = () => Task.FromResult(token);
33 |
34 | if (!string.IsNullOrWhiteSpace(appkey))
35 | config.Headers.Add("appkey", appkey);
36 | }).WithAutomaticReconnect(new RandomRetryPolicy());
37 | builder.Services.Configure(o =>
38 | {
39 | o.PayloadSerializerOptions.TypeInfoResolverChain.Insert(0, PacketJsonContext.Default);
40 | });
41 | return builder.Build();
42 | }
43 |
44 | public void AddListenerReceive(Action receiveMessageCallback)
45 | => _connection?.On(ReceiveMessageflag, receiveMessageCallback);
46 |
47 | public void AddListenerOnline(Action onlineMessageCallback)
48 | => _connection?.On(Onlineflag, onlineMessageCallback);
49 |
50 | public void AddListenerReconnected(Func? reconnectedCallback)
51 | => _connection!.Reconnected += reconnectedCallback;
52 |
53 | public void AddListenerClosed(Func closeCallback)
54 | => _connection!.Closed += closeCallback;
55 |
56 | public async Task StartAsync()
57 | {
58 | try
59 | {
60 | await _connection!.StartAsync();
61 | }
62 | catch (Exception e)
63 | {
64 | Debug.WriteLine(e);
65 | }
66 | }
67 |
68 | public async Task StopAsync()
69 | {
70 | try
71 | {
72 | await _connection!.StopAsync();
73 | }
74 | catch (Exception e)
75 | {
76 | Debug.WriteLine(e);
77 | }
78 | }
79 |
80 | public async Task DisposeAsync()
81 | {
82 | try
83 | {
84 | await _connection!.DisposeAsync();
85 | }
86 | catch (Exception e)
87 | {
88 | Debug.WriteLine(e);
89 | }
90 | }
91 | }
--------------------------------------------------------------------------------
/src/c#/GeneralUpdate.ClientCore/Pipeline/CompressMiddleware.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Diagnostics;
3 | using System.IO;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 | using GeneralUpdate.Common.Compress;
7 | using GeneralUpdate.Common.Internal;
8 | using GeneralUpdate.Common.Internal.Event;
9 | using GeneralUpdate.Common.Internal.Pipeline;
10 |
11 | namespace GeneralUpdate.ClientCore.Pipeline;
12 |
13 | public class CompressMiddleware : IMiddleware
14 | {
15 | public Task InvokeAsync(PipelineContext? context)
16 | {
17 | return Task.Run(() =>
18 | {
19 | var format = context.Get("Format");
20 | var sourcePath = context.Get("ZipFilePath");
21 | var patchPath = context.Get("PatchPath");
22 | var encoding = context.Get("Encoding");
23 | CompressProvider.Decompress(format,sourcePath,patchPath, encoding);
24 | });
25 | }
26 | }
--------------------------------------------------------------------------------
/src/c#/GeneralUpdate.ClientCore/Pipeline/HashMiddleware.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Diagnostics;
3 | using System.Security.Cryptography;
4 | using System.Threading.Tasks;
5 | using GeneralUpdate.Common.HashAlgorithms;
6 | using GeneralUpdate.Common.Internal;
7 | using GeneralUpdate.Common.Internal.Event;
8 | using GeneralUpdate.Common.Internal.Pipeline;
9 |
10 | namespace GeneralUpdate.ClientCore.Pipeline;
11 |
12 | public class HashMiddleware : IMiddleware
13 | {
14 | public async Task InvokeAsync(PipelineContext context)
15 | {
16 | var path = context.Get("ZipFilePath");
17 | var hash = context.Get("Hash");
18 | var isVerify = await VerifyFileHash(path, hash);
19 | if (!isVerify) throw new CryptographicException("Hash verification failed .");
20 | }
21 |
22 | private Task VerifyFileHash(string path, string hash)
23 | {
24 | return Task.Run(() =>
25 | {
26 | try
27 | {
28 | var hashAlgorithm = new Sha256HashAlgorithm();
29 | var hashSha256 = hashAlgorithm.ComputeHash(path);
30 | return string.Equals(hash, hashSha256, StringComparison.OrdinalIgnoreCase);
31 | }
32 | catch (Exception exception)
33 | {
34 | Debug.WriteLine(exception.Message);
35 | EventManager.Instance.Dispatch(this, new ExceptionEventArgs(exception, exception.Message));
36 | }
37 | return false;
38 | });
39 | }
40 | }
--------------------------------------------------------------------------------
/src/c#/GeneralUpdate.ClientCore/Pipeline/PatchMiddleware.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Diagnostics;
4 | using System.Threading.Tasks;
5 | using GeneralUpdate.Common.FileBasic;
6 | using GeneralUpdate.Common.Internal;
7 | using GeneralUpdate.Common.Internal.Event;
8 | using GeneralUpdate.Common.Internal.Pipeline;
9 | using GeneralUpdate.Differential;
10 |
11 | namespace GeneralUpdate.ClientCore.Pipeline;
12 |
13 | public class PatchMiddleware : IMiddleware
14 | {
15 | public async Task InvokeAsync(PipelineContext context)
16 | {
17 | var sourcePath = context.Get("SourcePath");
18 | var targetPath = context.Get("PatchPath");
19 | await DifferentialCore.Instance.Dirty(sourcePath, targetPath);
20 | }
21 | }
--------------------------------------------------------------------------------
/src/c#/GeneralUpdate.ClientCore/Properties/launchSettings.json:
--------------------------------------------------------------------------------
1 | {
2 | "profiles": {
3 | "GeneralUpdate.ClientCore": {
4 | "commandName": "Project",
5 | "launchBrowser": true,
6 | "environmentVariables": {
7 | "ASPNETCORE_ENVIRONMENT": "Development"
8 | },
9 | "applicationUrl": "https://localhost:65352;http://localhost:65362"
10 | }
11 | }
12 | }
--------------------------------------------------------------------------------
/src/c#/GeneralUpdate.ClientCore/Strategys/LinuxStrategy.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Diagnostics;
3 | using System.IO;
4 | using System.Threading;
5 | using System.Threading.Tasks;
6 | using GeneralUpdate.ClientCore.Pipeline;
7 | using GeneralUpdate.Common.FileBasic;
8 | using GeneralUpdate.Common.Internal;
9 | using GeneralUpdate.Common.Internal.Event;
10 | using GeneralUpdate.Common.Internal.Pipeline;
11 | using GeneralUpdate.Common.Internal.Strategy;
12 | using GeneralUpdate.Common.Shared.Object;
13 | using GeneralUpdate.Common.Shared.Object.Enum;
14 | using GeneralUpdate.Common.Shared.Service;
15 |
16 | namespace GeneralUpdate.ClientCore.Strategys;
17 |
18 | ///
19 | /// Update policy based on the linux platform.
20 | ///
21 | public class LinuxStrategy : AbstractStrategy
22 | {
23 | private GlobalConfigInfo _configinfo = new();
24 | private const string ProcessInfoFileName = "ProcessInfo.json";
25 |
26 | public override void Create(GlobalConfigInfo parameter) => _configinfo = parameter;
27 |
28 | public override async Task ExecuteAsync()
29 | {
30 | try
31 | {
32 | var status = ReportType.None;
33 | var patchPath = StorageManager.GetTempDirectory(Patchs);
34 | foreach (var version in _configinfo.UpdateVersions)
35 | {
36 | try
37 | {
38 | var context = new PipelineContext();
39 | //Common
40 | context.Add("ZipFilePath",
41 | Path.Combine(_configinfo.TempPath, $"{version.Name}{_configinfo.Format}"));
42 | //hash middleware
43 | context.Add("Hash", version.Hash);
44 | //zip middleware
45 | context.Add("Format", _configinfo.Format);
46 | context.Add("Name", version.Name);
47 | context.Add("Encoding", _configinfo.Encoding);
48 | //patch middleware
49 | context.Add("SourcePath", _configinfo.InstallPath);
50 | context.Add("PatchPath", patchPath);
51 | context.Add("BlackFiles", _configinfo.BlackFiles);
52 | context.Add("BlackFileFormats", _configinfo.BlackFormats);
53 | context.Add("SkipDirectorys", _configinfo.SkipDirectorys);
54 |
55 | var pipelineBuilder = new PipelineBuilder(context)
56 | .UseMiddleware()
57 | .UseMiddleware()
58 | .UseMiddleware();
59 | await pipelineBuilder.Build();
60 | status = ReportType.Success;
61 | }
62 | catch (Exception e)
63 | {
64 | status = ReportType.Failure;
65 | EventManager.Instance.Dispatch(this, new ExceptionEventArgs(e, e.Message));
66 | }
67 | finally
68 | {
69 | await VersionService.Report(_configinfo.ReportUrl
70 | , version.RecordId
71 | , status
72 | , version.AppType
73 | , _configinfo.Scheme
74 | , _configinfo.Token);
75 | }
76 | }
77 |
78 | if (!string.IsNullOrEmpty(_configinfo.UpdateLogUrl))
79 | {
80 | OpenBrowser(_configinfo.UpdateLogUrl);
81 | }
82 |
83 | Clear(patchPath);
84 | Clear(_configinfo.TempPath);
85 | }
86 | catch (Exception e)
87 | {
88 | Debug.WriteLine(e);
89 | EventManager.Instance.Dispatch(this, new ExceptionEventArgs(e, e.Message));
90 | }
91 | }
92 |
93 | public override void StartApp()
94 | {
95 | try
96 | {
97 | var appPath = Path.Combine(_configinfo.InstallPath, _configinfo.AppName);
98 | if (File.Exists(appPath))
99 | {
100 | if (File.Exists(ProcessInfoFileName))
101 | {
102 | File.SetAttributes(ProcessInfoFileName, FileAttributes.Normal);
103 | File.Delete(ProcessInfoFileName);
104 | }
105 |
106 | File.WriteAllText(ProcessInfoFileName, _configinfo.ProcessInfo);
107 | Process.Start(appPath);
108 | }
109 | }
110 | catch (Exception e)
111 | {
112 | Debug.WriteLine(e);
113 | EventManager.Instance.Dispatch(this, new ExceptionEventArgs(e, e.Message));
114 | }
115 | finally
116 | {
117 | Process.GetCurrentProcess().Kill();
118 | }
119 | }
120 | }
--------------------------------------------------------------------------------
/src/c#/GeneralUpdate.ClientCore/Strategys/WindowsStrategy.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Diagnostics;
3 | using System.IO;
4 | using System.Threading.Tasks;
5 | using GeneralUpdate.ClientCore.Pipeline;
6 | using GeneralUpdate.Common.FileBasic;
7 | using GeneralUpdate.Common.Internal;
8 | using GeneralUpdate.Common.Internal.Bootstrap;
9 | using GeneralUpdate.Common.Internal.Event;
10 | using GeneralUpdate.Common.Internal.Pipeline;
11 | using GeneralUpdate.Common.Internal.Strategy;
12 | using GeneralUpdate.Common.Shared.Object;
13 | using GeneralUpdate.Common.Shared.Object.Enum;
14 | using GeneralUpdate.Common.Shared.Service;
15 |
16 | namespace GeneralUpdate.ClientCore.Strategys;
17 |
18 | ///
19 | /// Update policy based on the Windows platform.
20 | ///
21 | public class WindowsStrategy : AbstractStrategy
22 | {
23 | private GlobalConfigInfo _configinfo = new();
24 |
25 | public override void Create(GlobalConfigInfo parameter) => _configinfo = parameter;
26 |
27 | public override async Task ExecuteAsync()
28 | {
29 | try
30 | {
31 | var status = ReportType.None;
32 | var patchPath = StorageManager.GetTempDirectory(Patchs);
33 | foreach (var version in _configinfo.UpdateVersions)
34 | {
35 | try
36 | {
37 | var context = new PipelineContext();
38 | //Common
39 | context.Add("ZipFilePath",
40 | Path.Combine(_configinfo.TempPath, $"{version.Name}{_configinfo.Format}"));
41 | //hash middleware
42 | context.Add("Hash", version.Hash);
43 | //zip middleware
44 | context.Add("Format", _configinfo.Format);
45 | context.Add("Name", version.Name);
46 | context.Add("Encoding", _configinfo.Encoding);
47 | //patch middleware
48 | context.Add("SourcePath", _configinfo.InstallPath);
49 | context.Add("PatchPath", patchPath);
50 |
51 | var pipelineBuilder = new PipelineBuilder(context)
52 | .UseMiddleware()
53 | .UseMiddleware()
54 | .UseMiddleware();
55 | await pipelineBuilder.Build();
56 | status = ReportType.Success;
57 | }
58 | catch (Exception e)
59 | {
60 | status = ReportType.Failure;
61 | EventManager.Instance.Dispatch(this, new ExceptionEventArgs(e, e.Message));
62 | }
63 | finally
64 | {
65 | await VersionService.Report(_configinfo.ReportUrl
66 | , version.RecordId
67 | , status
68 | , version.AppType
69 | , _configinfo.Scheme
70 | , _configinfo.Token);
71 | }
72 | }
73 |
74 | if (!string.IsNullOrEmpty(_configinfo.UpdateLogUrl))
75 | {
76 | OpenBrowser(_configinfo.UpdateLogUrl);
77 | }
78 |
79 | Clear(patchPath);
80 | Clear(_configinfo.TempPath);
81 | }
82 | catch (Exception e)
83 | {
84 | Debug.WriteLine(e);
85 | EventManager.Instance.Dispatch(this, new ExceptionEventArgs(e, e.Message));
86 | }
87 | }
88 |
89 | public override void StartApp()
90 | {
91 | try
92 | {
93 | Environments.SetEnvironmentVariable("ProcessInfo", _configinfo.ProcessInfo);
94 | var appPath = Path.Combine(_configinfo.InstallPath, _configinfo.AppName);
95 | if (File.Exists(appPath))
96 | {
97 | Environments.SetEnvironmentVariable("ProcessInfo", _configinfo.ProcessInfo);
98 | Process.Start(new ProcessStartInfo
99 | {
100 | UseShellExecute = true,
101 | FileName = appPath
102 | });
103 | }
104 | }
105 | catch (Exception e)
106 | {
107 | Debug.WriteLine(e);
108 | EventManager.Instance.Dispatch(this, new ExceptionEventArgs(e, e.Message));
109 | }
110 | finally
111 | {
112 | Process.GetCurrentProcess().Kill();
113 | }
114 | }
115 | }
--------------------------------------------------------------------------------
/src/c#/GeneralUpdate.Common/Compress/CompressProvider.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Text;
3 | using GeneralUpdate.Common.Shared.Object;
4 |
5 | namespace GeneralUpdate.Common.Compress;
6 |
7 | public class CompressProvider
8 | {
9 | private static ICompressionStrategy _compressionStrategy;
10 |
11 | private CompressProvider() { }
12 |
13 | public static void Compress(string compressType,string sourcePath, string destinationPath, bool includeRootDirectory, Encoding encoding)
14 | {
15 | _compressionStrategy = GetCompressionStrategy(compressType);
16 | _compressionStrategy.Compress(sourcePath, destinationPath, includeRootDirectory, encoding);
17 | }
18 |
19 | public static void Decompress(string compressType, string archivePath, string destinationPath, Encoding encoding)
20 | {
21 | _compressionStrategy = GetCompressionStrategy(compressType);
22 | _compressionStrategy.Decompress(archivePath, destinationPath, encoding);
23 | }
24 |
25 | private static ICompressionStrategy GetCompressionStrategy(string compressType) => compressType switch
26 | {
27 | Format.ZIP => new ZipCompressionStrategy(),
28 | _ => throw new ArgumentException("Compression format is not supported!")
29 | };
30 | }
--------------------------------------------------------------------------------
/src/c#/GeneralUpdate.Common/Compress/ICompressionStrategy.cs:
--------------------------------------------------------------------------------
1 | using System.Text;
2 |
3 | namespace GeneralUpdate.Common.Compress;
4 |
5 | public interface ICompressionStrategy
6 | {
7 | void Compress(string sourcePath, string destinationPath, bool includeRootDirectory, Encoding encoding);
8 | void Decompress(string archivePath, string destinationPath, Encoding encoding);
9 | }
--------------------------------------------------------------------------------
/src/c#/GeneralUpdate.Common/Download/DownloadManager.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Threading.Tasks;
4 | using System.Collections.Immutable;
5 | using System.Diagnostics;
6 | using System.Linq;
7 |
8 | namespace GeneralUpdate.Common.Download
9 | {
10 | public class DownloadManager(string path, string format, int timeOut)
11 | {
12 | #region Private Members
13 |
14 | private readonly ImmutableList.Builder _downloadTasksBuilder = ImmutableList.Create().ToBuilder();
15 | private ImmutableList _downloadTasks;
16 |
17 | #endregion Private Members
18 |
19 | #region Public Properties
20 |
21 | public List<(object, string)> FailedVersions { get; } = new();
22 |
23 | public string Path => path;
24 |
25 | public string Format => format;
26 |
27 | public int TimeOut => timeOut;
28 |
29 | private ImmutableList DownloadTasks => _downloadTasks ?? _downloadTasksBuilder.ToImmutable();
30 |
31 | public event EventHandler MultiAllDownloadCompleted;
32 | public event EventHandler MultiDownloadCompleted;
33 | public event EventHandler MultiDownloadError;
34 | public event EventHandler MultiDownloadStatistics;
35 |
36 | #endregion Public Properties
37 |
38 | #region Public Methods
39 |
40 | public async Task LaunchTasksAsync()
41 | {
42 | try
43 | {
44 | var downloadTasks = DownloadTasks.Select(task => task.LaunchAsync()).ToList();
45 | await Task.WhenAll(downloadTasks);
46 | MultiAllDownloadCompleted?.Invoke(this, new MultiAllDownloadCompletedEventArgs(true, FailedVersions));
47 | }
48 | catch (Exception ex)
49 | {
50 | MultiAllDownloadCompleted?.Invoke(this, new MultiAllDownloadCompletedEventArgs(false, FailedVersions));
51 | throw new Exception($"Download manager error: {ex.Message}", ex);
52 | }
53 | }
54 |
55 | public void OnMultiDownloadStatistics(object sender, MultiDownloadStatisticsEventArgs e)
56 | => MultiDownloadStatistics?.Invoke(this, e);
57 |
58 | public void OnMultiAsyncCompleted(object sender, MultiDownloadCompletedEventArgs e)
59 | => MultiDownloadCompleted?.Invoke(this, e);
60 |
61 | public void OnMultiDownloadError(object sender, MultiDownloadErrorEventArgs e)
62 | {
63 | MultiDownloadError?.Invoke(this, e);
64 | FailedVersions.Add((e.Version, e.Exception.Message));
65 | }
66 |
67 | public void Add(DownloadTask task)
68 | {
69 | Debug.Assert(task != null);
70 | if (!_downloadTasksBuilder.Contains(task))
71 | {
72 | _downloadTasksBuilder.Add(task);
73 | }
74 | }
75 |
76 | #endregion Public Methods
77 | }
78 | }
--------------------------------------------------------------------------------
/src/c#/GeneralUpdate.Common/Download/MultiEventArgs/MutiAllDownloadCompletedEventArgs.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 |
4 | namespace GeneralUpdate.Common.Download
5 | {
6 | public class MultiAllDownloadCompletedEventArgs : EventArgs
7 | {
8 | public MultiAllDownloadCompletedEventArgs(bool isAllDownloadCompleted, IList<(object, string)> failedVersions)
9 | {
10 | IsAllDownloadCompleted = isAllDownloadCompleted;
11 | FailedVersions = failedVersions;
12 | }
13 |
14 | public bool IsAllDownloadCompleted { get; set; }
15 |
16 | public IList> FailedVersions { get; set; }
17 | }
18 | }
--------------------------------------------------------------------------------
/src/c#/GeneralUpdate.Common/Download/MultiEventArgs/MutiDownloadCompletedEventArgs.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace GeneralUpdate.Common.Download
4 | {
5 | public class MultiDownloadCompletedEventArgs(object version, bool isComplated) : EventArgs
6 | {
7 | public object Version { get; private set; } = version;
8 |
9 | public bool IsComplated { get; private set; } = isComplated;
10 | }
11 | }
--------------------------------------------------------------------------------
/src/c#/GeneralUpdate.Common/Download/MultiEventArgs/MutiDownloadErrorEventArgs.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace GeneralUpdate.Common.Download
4 | {
5 | public class MultiDownloadErrorEventArgs : EventArgs
6 | {
7 | public MultiDownloadErrorEventArgs(Exception exception, object version)
8 | {
9 | Exception = exception;
10 | Version = version;
11 | }
12 |
13 | public Exception Exception { get; set; }
14 |
15 | public object Version { get; set; }
16 | }
17 | }
--------------------------------------------------------------------------------
/src/c#/GeneralUpdate.Common/Download/MultiEventArgs/MutiDownloadStatisticsEventArgs.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace GeneralUpdate.Common.Download;
4 |
5 | public class MultiDownloadStatisticsEventArgs(object version
6 | , TimeSpan remaining
7 | , string speed
8 | , long totalBytes
9 | , long bytesReceived
10 | , double progressPercentage) : EventArgs
11 | {
12 | public object Version { get; private set; } = version;
13 |
14 | public TimeSpan Remaining { get; private set; } = remaining;
15 |
16 | public string Speed { get; private set; } = speed;
17 |
18 | public long TotalBytesToReceive { get; private set; } = totalBytes;
19 |
20 | public long BytesReceived { get; private set; } = bytesReceived;
21 |
22 | public double ProgressPercentage { get; private set; } = progressPercentage;
23 | }
--------------------------------------------------------------------------------
/src/c#/GeneralUpdate.Common/FileBasic/BlackListManager.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using System.IO;
3 | using System.Linq;
4 | using GeneralUpdate.Common.Shared.Object;
5 |
6 | namespace GeneralUpdate.Common.FileBasic;
7 |
8 | public class BlackListManager
9 | {
10 | private static readonly object LockObject = new object();
11 | private static BlackListManager? _instance;
12 |
13 | private static readonly List _blackFileFormats =
14 | [
15 | ".patch",
16 | Format.ZIP,
17 | ".rar",
18 | ".tar",
19 | ".json",
20 | ".pdb"
21 | ];
22 |
23 | private static readonly List _blackFiles =
24 | [
25 | "Microsoft.Bcl.AsyncInterfaces.dll",
26 | "System.Collections.Immutable.dll",
27 | "System.IO.Pipelines.dll",
28 | "System.Text.Encodings.Web.dll",
29 | "System.Text.Json.dll"
30 | ];
31 |
32 | private static readonly List _skipDirectorys = ["app-", "fail"];
33 |
34 | private BlackListManager() { }
35 |
36 | public static BlackListManager? Instance
37 | {
38 | get
39 | {
40 | if (_instance == null)
41 | {
42 | lock (LockObject)
43 | {
44 | if (_instance == null)
45 | {
46 | _instance = new BlackListManager();
47 | }
48 | }
49 | }
50 |
51 | return _instance;
52 | }
53 | }
54 |
55 | public IReadOnlyList BlackFileFormats => _blackFileFormats.AsReadOnly();
56 | public IReadOnlyList BlackFiles => _blackFiles.AsReadOnly();
57 |
58 | public IReadOnlyList SkipDirectorys = _skipDirectorys.AsReadOnly();
59 |
60 | public void AddBlackFileFormats(List? formats)
61 | {
62 | if (formats == null)
63 | return;
64 |
65 | foreach (var format in formats)
66 | {
67 | AddBlackFileFormat(format);
68 | }
69 | }
70 |
71 | public void AddBlackFileFormat(string format)
72 | {
73 | if (string.IsNullOrWhiteSpace(format))
74 | return;
75 |
76 | if (!_blackFileFormats.Contains(format))
77 | {
78 | _blackFileFormats.Add(format);
79 | }
80 | }
81 |
82 | public void AddBlackFiles(List? fileNames)
83 | {
84 | if (fileNames == null)
85 | return;
86 |
87 | foreach (var fileName in fileNames)
88 | {
89 | AddBlackFile(fileName);
90 | }
91 | }
92 |
93 | public void AddBlackFile(string fileName)
94 | {
95 | if (string.IsNullOrWhiteSpace(fileName))
96 | return;
97 |
98 | if (!_blackFiles.Contains(fileName))
99 | {
100 | _blackFiles.Add(fileName);
101 | }
102 | }
103 |
104 | public void AddSkipDirectorys(List? directorys)
105 | {
106 | if (directorys == null)
107 | return;
108 |
109 | foreach (var directory in directorys)
110 | {
111 | AddSkipDirectory(directory);
112 | }
113 | }
114 |
115 | public void AddSkipDirectory(string directory)
116 | {
117 | if (string.IsNullOrWhiteSpace(directory))
118 | return;
119 |
120 | if (!_skipDirectorys.Contains(directory))
121 | {
122 | _skipDirectorys.Add(directory);
123 | }
124 | }
125 |
126 | public bool IsBlacklisted(string relativeFilePath)
127 | {
128 | var fileName = Path.GetFileName(relativeFilePath);
129 | var fileExtension = Path.GetExtension(relativeFilePath);
130 |
131 | return _blackFiles.Contains(fileName) || _blackFileFormats.Contains(fileExtension);
132 | }
133 |
134 | public bool IsSkipDirectory(string directory)
135 | {
136 | return _skipDirectorys.Any(directory.Contains);
137 | }
138 | }
--------------------------------------------------------------------------------
/src/c#/GeneralUpdate.Common/FileBasic/ComparisonResult.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 |
3 | namespace GeneralUpdate.Common.FileBasic;
4 |
5 | ///
6 | /// Result of a comparison between two directories.
7 | ///
8 | public class ComparisonResult
9 | {
10 | private List _leftNodes;
11 | private List _rightNodes;
12 | private List _differentNodes;
13 |
14 | public ComparisonResult()
15 | {
16 | _leftNodes = new List();
17 | _rightNodes = new List();
18 | _differentNodes = new List();
19 | }
20 |
21 | ///
22 | /// List of files that are unique to A.
23 | ///
24 | public IReadOnlyList LeftNodes => _leftNodes.AsReadOnly();
25 |
26 | ///
27 | /// List of files that are unique to B.
28 | ///
29 | public IReadOnlyList RightNodes => _rightNodes.AsReadOnly();
30 |
31 | ///
32 | /// List of files that are different between A and B.
33 | ///
34 | public IReadOnlyList DifferentNodes => _differentNodes.AsReadOnly();
35 |
36 | public void AddToLeft(IEnumerable files) => _leftNodes.AddRange(files);
37 |
38 | public void AddToRight(IEnumerable files) => _rightNodes.AddRange(files);
39 |
40 | public void AddDifferent(IEnumerable files) => _differentNodes.AddRange(files);
41 | }
--------------------------------------------------------------------------------
/src/c#/GeneralUpdate.Common/FileBasic/FileNode.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace GeneralUpdate.Common.FileBasic;
4 |
5 | public class FileNode
6 | {
7 | #region Public Properties
8 |
9 | public long Id { get; set; }
10 |
11 | public string Name { get; set; }
12 |
13 | public string FullName { get; set; }
14 |
15 | public string Path { get; set; }
16 |
17 | public string Hash { get; set; }
18 |
19 | public FileNode Left { get; set; }
20 |
21 | public FileNode Right { get; set; }
22 |
23 | public int LeftType { get; set; }
24 |
25 | public int RightType { get; set; }
26 |
27 | public string RelativePath { get; set; }
28 |
29 | #endregion Public Properties
30 |
31 | #region Constructors
32 |
33 | public FileNode()
34 | {
35 | }
36 |
37 | public FileNode(int id)
38 | {
39 | Id = id;
40 | }
41 |
42 | #endregion Constructors
43 |
44 | #region Public Methods
45 |
46 | public void Add(FileNode node)
47 | {
48 | if (node == null) return;
49 |
50 | if (node.Id < Id)
51 | {
52 | if (Left == null)
53 | {
54 | Left = node;
55 | }
56 | else
57 | {
58 | Left.Add(node);
59 | }
60 | }
61 | else
62 | {
63 | if (Right == null)
64 | {
65 | Right = node;
66 | }
67 | else
68 | {
69 | Right.Add(node);
70 | }
71 | }
72 | }
73 |
74 | public void InfixOrder()
75 | {
76 | if (Left != null)
77 | {
78 | Left.InfixOrder();
79 | }
80 |
81 | if (Right != null)
82 | {
83 | Right.InfixOrder();
84 | }
85 | }
86 |
87 | public FileNode Search(long id)
88 | {
89 | if (id == Id)
90 | {
91 | return this;
92 | }
93 | else if (id < Id)
94 | {
95 | if (Left == null) return null;
96 | return Left.Search(id);
97 | }
98 | else
99 | {
100 | if (Right == null) return null;
101 | return Right.Search(id);
102 | }
103 | }
104 |
105 | ///
106 | /// Find the parent node of the node that you want to delete.
107 | ///
108 | ///
109 | ///
110 | public FileNode SearchParent(long id)
111 | {
112 | if (Left != null && Left.Id == id || Right != null && Right.Id == id)
113 | {
114 | return this;
115 | }
116 | else
117 | {
118 | if (id < Id && Left != null)
119 | {
120 | return Left.SearchParent(id);
121 | }
122 | else if (id >= Id && Right != null)
123 | {
124 | return Right.SearchParent(id);
125 | }
126 | else
127 | {
128 | return null;
129 | }
130 | }
131 | }
132 |
133 | ///
134 | /// Compare tree nodes equally by Hash and file names.
135 | ///
136 | ///
137 | ///
138 | public override bool Equals(object obj)
139 | {
140 | if (obj == null) return false;
141 | var tempNode = obj as FileNode;
142 | if (tempNode == null) throw new ArgumentException(nameof(tempNode));
143 | return string.Equals(Hash, tempNode.Hash, StringComparison.OrdinalIgnoreCase) &&
144 | string.Equals(Name, tempNode.Name, StringComparison.OrdinalIgnoreCase);
145 | }
146 |
147 | public override int GetHashCode() => base.GetHashCode();
148 |
149 | #endregion Public Methods
150 | }
151 |
--------------------------------------------------------------------------------
/src/c#/GeneralUpdate.Common/FileBasic/FileTree.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using System.Diagnostics;
3 |
4 | namespace GeneralUpdate.Common.FileBasic;
5 |
6 | ///
7 | /// Simple file binary tree.
8 | ///
9 | public class FileTree
10 | {
11 | #region Private Members
12 |
13 | private FileNode _root;
14 |
15 | #endregion Private Members
16 |
17 | #region Constructors
18 |
19 | public FileTree()
20 | { }
21 |
22 | public FileTree(IEnumerable nodes)
23 | {
24 | foreach (var node in nodes) Add(node);
25 | }
26 |
27 | #endregion Constructors
28 |
29 | #region Public Methods
30 |
31 | public void Add(FileNode node)
32 | {
33 | if (_root == null)
34 | {
35 | _root = node;
36 | }
37 | else
38 | {
39 | _root.Add(node);
40 | }
41 | }
42 |
43 | public void InfixOrder()
44 | {
45 | if (_root != null)
46 | {
47 | _root.InfixOrder();
48 | }
49 | else
50 | {
51 | Debug.WriteLine("The binary sort tree is empty and cannot be traversed!");
52 | }
53 | }
54 |
55 | public FileNode Search(long id) => _root == null ? null : _root.Search(id);
56 |
57 | public FileNode SearchParent(long id) => _root == null ? null : _root.SearchParent(id);
58 |
59 | public long DelRightTreeMin(FileNode node)
60 | {
61 | FileNode target = node;
62 | while (target.Left != null)
63 | {
64 | target = target.Left;
65 | }
66 | DelNode(target.Id);
67 | return target.Id;
68 | }
69 |
70 | public void DelNode(long id)
71 | {
72 | if (_root == null)
73 | {
74 | return;
75 | }
76 | else
77 | {
78 | FileNode targetNode = Search(id);
79 | if (targetNode == null)
80 | {
81 | return;
82 | }
83 | if (_root.Left == null && _root.Right == null)
84 | {
85 | _root = null;
86 | return;
87 | }
88 |
89 | FileNode parent = SearchParent(id);
90 | if (targetNode.Left == null && targetNode.Right == null)
91 | {
92 | if (parent.Left != null && parent.Left.Id == id)
93 | {
94 | parent.Left = null;
95 | }
96 | else if (parent.Right != null && parent.Right.Id == id)
97 | {
98 | parent.Right = null;
99 | }
100 | }
101 | else if (targetNode.Left != null && targetNode.Right != null)
102 | {
103 | long minVal = DelRightTreeMin(targetNode.Right);
104 | targetNode.Id = minVal;
105 | }
106 | else
107 | {
108 | if (targetNode.Left != null)
109 | {
110 | if (parent.Left.Id == id)
111 | {
112 | parent.Left = targetNode.Left;
113 | }
114 | else
115 | {
116 | parent.Right = targetNode.Left;
117 | }
118 | }
119 | else
120 | {
121 | if (parent.Left.Id == id)
122 | {
123 | parent.Left = targetNode.Right;
124 | }
125 | else
126 | {
127 | parent.Right = targetNode.Right;
128 | }
129 | }
130 | }
131 | }
132 | }
133 |
134 | ///
135 | /// Starting from the root node, recursively compares two different child nodes of the binary tree and nodes that are not included.
136 | ///
137 | ///
138 | ///
139 | ///
140 | public void Compare(FileNode node, FileNode node0, ref List nodes)
141 | {
142 | if (node != null && node.Left != null)
143 | {
144 | if (!node.Equals(node0) && node0 != null) nodes.Add(node0);
145 | Compare(node.Left, node0.Left, ref nodes);
146 | }
147 | else if (node0 != null && node0.Left != null)
148 | {
149 | nodes.Add(node0);
150 | Compare(node.Left, node0.Left, ref nodes);
151 | }
152 |
153 | if (node != null && node.Right != null)
154 | {
155 | if (!node.Equals(node0) && node0 != null) nodes.Add(node0);
156 | Compare(node.Right, node0 == null ? null : node0.Right, ref nodes);
157 | }
158 | else if (node0 != null && node0.Right != null)
159 | {
160 | nodes.Add(node0);
161 | Compare(node == null ? null : node.Right, node0.Right, ref nodes);
162 | }
163 | else if (node0 != null)
164 | {
165 | nodes.Add(node0);
166 | }
167 | }
168 |
169 | public FileNode GetRoot() => _root;
170 |
171 | #endregion Public Methods
172 | }
--------------------------------------------------------------------------------
/src/c#/GeneralUpdate.Common/GeneralUpdate.Common.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | default
5 | enable
6 | netstandard2.0
7 | GeneralUpdate.Common
8 | JusterZhu
9 | The infrastructure required to support all components is necessary, and this nuget package is essential.
10 | Copyright © 2024 JusterZhu. All rights reserved.
11 | https://github.com/GeneralLibrary/GeneralUpdate
12 | https://github.com/GeneralLibrary/GeneralUpdate?tab=MIT-1-ov-file#readme
13 | GeneralUpdate128.png
14 | https://github.com/GeneralLibrary/GeneralUpdate
15 | public
16 | upgrade,update
17 | The infrastructure required to support all components is necessary, and this nuget package is essential.
18 | true
19 | 9.1.6
20 | true
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 | True
32 |
33 | GeneralUpdate.ico
34 |
35 |
36 | True
37 |
38 |
39 |
40 |
41 |
--------------------------------------------------------------------------------
/src/c#/GeneralUpdate.Common/GeneralUpdate128.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GeneralLibrary/GeneralUpdate/69c16da6d74b6a1e8cfbf571b9d49e1b5a820da2/src/c#/GeneralUpdate.Common/GeneralUpdate128.png
--------------------------------------------------------------------------------
/src/c#/GeneralUpdate.Common/HashAlgorithms/HashAlgorithmBase.cs:
--------------------------------------------------------------------------------
1 | using System.IO;
2 | using System.Security.Cryptography;
3 | using System.Text;
4 |
5 | namespace GeneralUpdate.Common.HashAlgorithms
6 | {
7 | public abstract class HashAlgorithmBase
8 | {
9 | public string ComputeHash(string fileName)
10 | {
11 | if (!System.IO.File.Exists(fileName))
12 | throw new FileNotFoundException(nameof(fileName));
13 |
14 | using var hashAlgorithm = GetHashAlgorithm();
15 | using var file = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.Read);
16 | var dataArray = hashAlgorithm.ComputeHash(file);
17 | var stringBuilder = new StringBuilder();
18 | for (int i = 0; i < dataArray.Length; i++)
19 | {
20 | stringBuilder.Append(dataArray[i].ToString("x2"));
21 | }
22 | return stringBuilder.ToString();
23 | }
24 |
25 | public byte[] ComputeHashBytes(string fileName)
26 | {
27 | if (!File.Exists(fileName))
28 | throw new FileNotFoundException(nameof(fileName));
29 |
30 | using var hashAlgorithm = GetHashAlgorithm();
31 | using var file = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.Read);
32 | return hashAlgorithm.ComputeHash(file);
33 | }
34 |
35 | protected abstract HashAlgorithm GetHashAlgorithm();
36 | }
37 | }
--------------------------------------------------------------------------------
/src/c#/GeneralUpdate.Common/HashAlgorithms/Md5HashAlgorithm.cs:
--------------------------------------------------------------------------------
1 | using System.Security.Cryptography;
2 |
3 | namespace GeneralUpdate.Common.HashAlgorithms
4 | {
5 | public class Md5HashAlgorithm : HashAlgorithmBase
6 | {
7 | protected override HashAlgorithm GetHashAlgorithm() => MD5.Create();
8 | }
9 | }
--------------------------------------------------------------------------------
/src/c#/GeneralUpdate.Common/HashAlgorithms/Sha1HashAlgorithm.cs:
--------------------------------------------------------------------------------
1 | using System.Security.Cryptography;
2 |
3 | namespace GeneralUpdate.Common.HashAlgorithms
4 | {
5 | public class Sha1HashAlgorithm : HashAlgorithmBase
6 | {
7 | protected override HashAlgorithm GetHashAlgorithm() => new SHA1Managed();
8 | }
9 | }
--------------------------------------------------------------------------------
/src/c#/GeneralUpdate.Common/HashAlgorithms/Sha256HashAlgorithm.cs:
--------------------------------------------------------------------------------
1 | using System.Security.Cryptography;
2 |
3 | namespace GeneralUpdate.Common.HashAlgorithms
4 | {
5 | public class Sha256HashAlgorithm : HashAlgorithmBase
6 | {
7 | protected override HashAlgorithm GetHashAlgorithm() => SHA256.Create();
8 | }
9 | }
--------------------------------------------------------------------------------
/src/c#/GeneralUpdate.Common/Internal/Bootstrap/AbstractBootstrap.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Concurrent;
2 | using System.Diagnostics;
3 | using System.Threading.Tasks;
4 | using GeneralUpdate.Common.Internal.Strategy;
5 |
6 | namespace GeneralUpdate.Common.Internal.Bootstrap
7 | {
8 | public abstract class AbstractBootstrap
9 | where TBootstrap : AbstractBootstrap
10 | where TStrategy : IStrategy
11 | {
12 | private readonly ConcurrentDictionary _options;
13 |
14 | protected internal AbstractBootstrap() =>
15 | _options = new ConcurrentDictionary();
16 |
17 | ///
18 | /// Launch async udpate.
19 | ///
20 | ///
21 | public abstract Task LaunchAsync();
22 |
23 | protected abstract void ExecuteStrategy();
24 |
25 | protected abstract Task ExecuteStrategyAsync();
26 |
27 | protected abstract TBootstrap StrategyFactory();
28 |
29 | ///
30 | /// Setting update configuration.
31 | ///
32 | ///
33 | /// Configuration Action Enumeration.
34 | /// Value
35 | ///
36 | public TBootstrap Option(UpdateOption option, T value)
37 | {
38 | if (value == null)
39 | {
40 | _options.TryRemove(option, out _);
41 | }
42 | else
43 | {
44 | _options[option] = new UpdateOptionValue(option, value);
45 | }
46 | return (TBootstrap)this;
47 | }
48 |
49 | protected T? GetOption(UpdateOption? option)
50 | {
51 | try
52 | {
53 | Debug.Assert(option != null && _options.Count != 0);
54 | var val = _options[option];
55 | if (val != null) return (T)val.GetValue();
56 | return default;
57 | }
58 | catch
59 | {
60 | return default;
61 | }
62 | }
63 | }
64 | }
--------------------------------------------------------------------------------
/src/c#/GeneralUpdate.Common/Internal/Bootstrap/Environments.cs:
--------------------------------------------------------------------------------
1 | using System.IO;
2 |
3 | namespace GeneralUpdate.Common.Internal.Bootstrap;
4 |
5 | public static class Environments
6 | {
7 | public static void SetEnvironmentVariable(string key, string value)
8 | {
9 | var filePath = Path.Combine(Path.GetTempPath(), $"{key}.txt");
10 | File.WriteAllText(filePath, value);
11 | }
12 |
13 | public static string GetEnvironmentVariable(string key)
14 | {
15 | var filePath = Path.Combine(Path.GetTempPath(), $"{key}.txt");
16 | if (!File.Exists(filePath))
17 | return string.Empty;
18 |
19 | var content = File.ReadAllText(filePath);
20 | File.SetAttributes(filePath, FileAttributes.Normal);
21 | File.Delete(filePath);
22 | return content;
23 | }
24 | }
--------------------------------------------------------------------------------
/src/c#/GeneralUpdate.Common/Internal/Bootstrap/UpdateOption.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Diagnostics.Contracts;
4 | using System.Text;
5 | using System.Threading;
6 |
7 | namespace GeneralUpdate.Common.Internal.Bootstrap
8 | {
9 | public abstract class UpdateOption : AbstractConstant
10 | {
11 | private class UpdateOptionPool : ConstantPool
12 | {
13 | protected override IConstant NewConstant(int id, string name) => new UpdateOption(id, name);
14 | }
15 |
16 | private static readonly UpdateOptionPool Pool = new();
17 |
18 | public static UpdateOption ValueOf(string name) => (UpdateOption)Pool.ValueOf(name);
19 |
20 | ///
21 | /// Update the file format of the package.
22 | ///
23 | public static readonly UpdateOption Format = ValueOf("COMPRESSFORMAT");
24 |
25 | ///
26 | /// Compress encoding.
27 | ///
28 | public static readonly UpdateOption Encoding = ValueOf("COMPRESSENCODING");
29 |
30 | ///
31 | /// Timeout period (unit: second). If this parameter is not specified, the default timeout period is 30 seconds.
32 | ///
33 | public static readonly UpdateOption DownloadTimeOut = ValueOf("DOWNLOADTIMEOUT");
34 |
35 | ///
36 | /// Whether to enable the driver upgrade function.
37 | ///
38 | public static readonly UpdateOption Drive = ValueOf("DRIVE");
39 |
40 | internal UpdateOption(int id, string name)
41 | : base(id, name) { }
42 |
43 | public abstract bool Set(IUpdateConfiguration configuration, object value);
44 | }
45 |
46 | public sealed class UpdateOption : UpdateOption
47 | {
48 | internal UpdateOption(int id, string name)
49 | : base(id, name)
50 | {
51 | }
52 |
53 | public void Validate(T value) => Contract.Requires(value != null);
54 |
55 | public override bool Set(IUpdateConfiguration configuration, object value) => configuration.SetOption(this, (T)value);
56 | }
57 |
58 | public abstract class ConstantPool
59 | {
60 | private readonly Dictionary constants = new Dictionary();
61 | private int nextId = 1;
62 |
63 | /// Shortcut of this.ValueOf(firstNameComponent.Name + "#" + secondNameComponent).
64 | public IConstant ValueOf(Type firstNameComponent, string secondNameComponent)
65 | {
66 | Contract.Requires(firstNameComponent != null);
67 | Contract.Requires(secondNameComponent != null);
68 | return this.ValueOf(firstNameComponent.Name + '#' + secondNameComponent);
69 | }
70 |
71 | ///
72 | /// Returns the which is assigned to the specified name.
73 | /// If there's no such , a new one will be created and returned.
74 | /// Once created, the subsequent calls with the same name will always return the previously created one
75 | /// (i.e. singleton.)
76 | ///
77 | /// the name of the
78 | public IConstant ValueOf(string name)
79 | {
80 | IConstant constant;
81 | lock (this.constants)
82 | {
83 | if (this.constants.TryGetValue(name, out constant))
84 | {
85 | return constant;
86 | }
87 | else
88 | {
89 | constant = this.NewInstance0(name);
90 | }
91 | }
92 | return constant;
93 | }
94 |
95 | /// Returns true if a exists for the given name.
96 | public bool Exists(string name)
97 | {
98 | CheckNotNullAndNotEmpty(name);
99 | lock (this.constants)
100 | return this.constants.ContainsKey(name);
101 | }
102 |
103 | ///
104 | /// Creates a new for the given name or fail with an
105 | /// if a for the given name exists.
106 | ///
107 | public IConstant NewInstance(string name)
108 | {
109 | if (this.Exists(name)) throw new ArgumentException($"'{name}' is already in use");
110 | IConstant constant = this.NewInstance0(name);
111 | return constant;
112 | }
113 |
114 | // Be careful that this dose not check whether the argument is null or empty.
115 | private IConstant NewInstance0(string name)
116 | {
117 | lock (this.constants)
118 | {
119 | IConstant constant = this.NewConstant(this.nextId, name);
120 | this.constants[name] = constant;
121 | this.nextId++;
122 | return constant;
123 | }
124 | }
125 |
126 | private static void CheckNotNullAndNotEmpty(string name) => Contract.Requires(!string.IsNullOrEmpty(name));
127 |
128 | protected abstract IConstant NewConstant(int id, string name);
129 |
130 | [Obsolete]
131 | public int NextId()
132 | {
133 | lock (this.constants)
134 | {
135 | int id = this.nextId;
136 | this.nextId++;
137 | return id;
138 | }
139 | }
140 | }
141 |
142 | public interface IConstant
143 | {
144 | /// Returns the unique number assigned to this .
145 | int Id { get; }
146 |
147 | /// Returns the name of this .
148 | string Name { get; }
149 | }
150 |
151 | public interface IUpdateConfiguration
152 | {
153 | T GetOption(UpdateOption option);
154 |
155 | bool SetOption(UpdateOption option, object value);
156 |
157 | bool SetOption(UpdateOption option, T value);
158 | }
159 |
160 | public abstract class AbstractConstant : IConstant
161 | {
162 | private static long nextUniquifier;
163 | private long volatileUniquifier;
164 |
165 | protected AbstractConstant(int id, string name)
166 | {
167 | this.Id = id;
168 | this.Name = name;
169 | }
170 |
171 | public int Id { get; }
172 |
173 | public string Name { get; }
174 |
175 | public override sealed string ToString() => this.Name;
176 |
177 | protected long Uniquifier
178 | {
179 | get
180 | {
181 | long result;
182 | if ((result = Volatile.Read(ref this.volatileUniquifier)) == 0)
183 | {
184 | result = Interlocked.Increment(ref nextUniquifier);
185 | long previousUniquifier = Interlocked.CompareExchange(ref this.volatileUniquifier, result, 0);
186 | if (previousUniquifier != 0) result = previousUniquifier;
187 | }
188 | return result;
189 | }
190 | }
191 | }
192 |
193 | public abstract class AbstractConstant : AbstractConstant, IComparable, IEquatable
194 | where T : AbstractConstant
195 | {
196 | /// Creates a new instance.
197 | protected AbstractConstant(int id, string name)
198 | : base(id, name) { }
199 |
200 | public override sealed int GetHashCode() => base.GetHashCode();
201 |
202 | public override sealed bool Equals(object obj) => base.Equals(obj);
203 |
204 | public bool Equals(T other) => ReferenceEquals(this, other);
205 |
206 | public int CompareTo(T o)
207 | {
208 | if (ReferenceEquals(this, o)) return 0;
209 | AbstractConstant other = o;
210 | int returnCode = this.GetHashCode() - other.GetHashCode();
211 | if (returnCode != 0) return returnCode;
212 | long thisUV = this.Uniquifier;
213 | long otherUV = other.Uniquifier;
214 | if (thisUV < otherUV) return -1;
215 | if (thisUV > otherUV) return 1;
216 | throw new System.Exception("failed to compare two different constants");
217 | }
218 | }
219 | }
--------------------------------------------------------------------------------
/src/c#/GeneralUpdate.Common/Internal/Bootstrap/UpdateOptionValue.cs:
--------------------------------------------------------------------------------
1 | namespace GeneralUpdate.Common.Internal.Bootstrap
2 | {
3 | public abstract class UpdateOptionValue
4 | {
5 | public abstract UpdateOption Option { get; }
6 |
7 | public abstract bool Set(IUpdateConfiguration config);
8 |
9 | public abstract object GetValue();
10 | }
11 |
12 | public sealed class UpdateOptionValue : UpdateOptionValue
13 | {
14 | public override UpdateOption Option { get; }
15 | private readonly T value;
16 |
17 | public UpdateOptionValue(UpdateOption option, T value)
18 | {
19 | this.Option = option;
20 | this.value = value;
21 | }
22 |
23 | public override object GetValue() => this.value;
24 |
25 | public override bool Set(IUpdateConfiguration config) => config.SetOption(this.Option, this.value);
26 |
27 | public override string ToString() => this.value.ToString();
28 | }
29 | }
--------------------------------------------------------------------------------
/src/c#/GeneralUpdate.Common/Internal/Event/EventManager.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Diagnostics;
4 |
5 | namespace GeneralUpdate.Common.Internal.Event
6 | {
7 | public class EventManager : IDisposable
8 | {
9 | private static readonly object _lockObj = new();
10 | private static EventManager _instance;
11 | private Dictionary _dicDelegates = new();
12 | private bool _disposed = false;
13 |
14 | private EventManager() { }
15 |
16 | public static EventManager Instance
17 | {
18 | get
19 | {
20 | if (_instance == null)
21 | {
22 | lock (_lockObj)
23 | {
24 | if (_instance == null)
25 | _instance = new EventManager();
26 | }
27 | }
28 | return _instance;
29 | }
30 | }
31 |
32 | public void AddListener(Action