Skip to content
Open
103 changes: 54 additions & 49 deletions Plain Craft Launcher 2/Modules/ModSecret.vb
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ Imports System.ComponentModel
Imports System.Management
Imports System.Net.Http
Imports System.Runtime.InteropServices
Imports System.Security
Imports System.Security.Cryptography
Imports PCL.Core.IO
Imports PCL.Core.UI
Expand Down Expand Up @@ -682,20 +683,26 @@ PCL-Community 及其成员与龙腾猫跃无从属关系,且均不会为您的
Public IsCheckingUpdates As Boolean = False
Public IsUpdateWaitingRestart As Boolean = False
Public RemoteServer As New UpdatesWrapperModel({
New UpdatesGitHubModel() With {.SourceName = "GitHub Nightly"},
New UpdatesMirrorChyanModel(),
New UpdatesRandomModel({
New UpdatesMinioModel("https://s3.pysio.online/pcl2-ce/", "Pysio"),
New UpdatesMinioModel("https://staticassets.naids.com/resources/pclce/", "Naids")
}),
New UpdatesMinioModel("https://github.com/PCL-Community/PCL2_CE_Server/raw/main/", "GitHub")
})
Public ReadOnly Property IsUpdBetaChannel
Get
If VersionBaseName.Contains("beta") Then Return True
Return Setup.Get("SystemSystemUpdateBranch") = 1
End Get
End Property

Public Function GetCurrentUpdateChannel() As UpdateChannel
Select Case CType(Setup.Get("SystemSystemUpdateBranch"), Integer)
Case 1
Return UpdateChannel.beta
Case 2
Return UpdateChannel.nightly
Case Else
Return UpdateChannel.stable
End Select
End Function

Public Sub UpdateCheckByButton()
If IsCheckingUpdates Then
Hint("正在检查更新中,请稍后再试……")
Expand All @@ -714,7 +721,7 @@ PCL-Community 及其成员与龙腾猫跃无从属关系,且均不会为您的
Public Function IsVerisonLatest() As Boolean
Try
Return RemoteServer.IsLatest(
If(IsUpdBetaChannel, UpdateChannel.beta, UpdateChannel.stable),
GetCurrentUpdateChannel(),
If(IsArm64System, UpdateArch.arm64, UpdateArch.x64),
SemVer.Parse(VersionBaseName),
VersionCode)
Expand All @@ -724,15 +731,15 @@ PCL-Community 及其成员与龙腾猫跃无从属关系,且均不会为您的
End Try
End Function
Public Sub NoticeUserUpdate(Optional Silent As Boolean = False)
Dim channel = GetCurrentUpdateChannel()

If Not IsVerisonLatest() Then
Dim latest As VersionDataModel = Nothing
Dim checkUpdateEx As Exception = Nothing
RunInNewThread(
Sub()
Try
latest = RemoteServer.GetLatestVersion(
If(IsUpdBetaChannel, UpdateChannel.beta, UpdateChannel.stable),
If(IsArm64System, UpdateArch.arm64, UpdateArch.x64))
latest = RemoteServer.GetLatestVersion(channel, If(IsArm64System, UpdateArch.arm64, UpdateArch.x64))
Catch ex As Exception
checkUpdateEx = ex
End Try
Expand All @@ -758,41 +765,37 @@ PCL-Community 及其成员与龙腾猫跃无从属关系,且均不会为您的
Public Sub UpdateStart(Slient As Boolean, Optional ReceivedKey As String = Nothing, Optional ForceValidated As Boolean = False)
Dim DlTargetPath As String = ExePath + "PCL\Plain Craft Launcher Community Edition.exe"
RunInNewThread(Sub()
Try
Dim version = RemoteServer.GetLatestVersion(
If(IsUpdBetaChannel, UpdateChannel.beta, UpdateChannel.stable),
If(IsArm64System, UpdateArch.arm64, UpdateArch.x64))
WriteFile($"{PathTemp}CEUpdateLog.md", version.Changelog)
'构造步骤加载器
Dim Loaders As New List(Of LoaderBase)
'下载
Loaders.AddRange(RemoteServer.GetDownloadLoader(
If(IsUpdBetaChannel, UpdateChannel.beta, UpdateChannel.stable),
If(IsArm64System, UpdateArch.arm64, UpdateArch.x64), DlTargetPath))
Loaders.Add(New LoaderTask(Of Integer, Integer)("校验更新", Sub()
Dim curHash = GetFileSHA256(DlTargetPath)
If curHash <> version.SHA256 Then
Throw New Exception($"更新文件 SHA256 不正确,应该为 {version.SHA256},实际为 {curHash}")
End If
End Sub))
If Not Slient Then
Loaders.Add(New LoaderTask(Of Integer, Integer)("安装更新", Sub() UpdateRestart(True)))
End If
'启动
Dim Loader As New LoaderCombo(Of JObject)("启动器更新", Loaders)
Loader.Start()
If Slient Then
IsUpdateWaitingRestart = True
Else
LoaderTaskbarAdd(Loader)
FrmMain.BtnExtraDownload.ShowRefresh()
FrmMain.BtnExtraDownload.Ribble()
End If
Catch ex As Exception
Log(ex, "[Update] 下载启动器更新文件失败", LogLevel.Hint)
Hint("下载启动器更新文件失败,请检查网络连接", HintType.Critical)
End Try
End Sub)
Try
Dim channel = GetCurrentUpdateChannel()
Dim version = RemoteServer.GetLatestVersion(channel, If(IsArm64System, UpdateArch.arm64, UpdateArch.x64))
WriteFile($"{PathTemp}CEUpdateLog.md", version.Changelog)
'构造步骤加载器
Dim Loaders As New List(Of LoaderBase)
Loaders.AddRange(RemoteServer.GetDownloadLoader(channel, If(IsArm64System, UpdateArch.arm64, UpdateArch.x64), DlTargetPath))
Loaders.Add(New LoaderTask(Of Integer, Integer)("校验更新", Sub()
Dim curHash = GetFileSHA256(DlTargetPath)
If curHash <> version.SHA256 Then
Throw New SecurityException($"更新文件 SHA256 不正确,应该为 {version.SHA256},实际为 {curHash}")
End If
End Sub))
If Not Slient Then
Loaders.Add(New LoaderTask(Of Integer, Integer)("安装更新", Sub() UpdateRestart(True)))
End If
'启动
Dim Loader As New LoaderCombo(Of JObject)("启动器更新", Loaders)
Loader.Start()
If Slient Then
IsUpdateWaitingRestart = True
Else
LoaderTaskbarAdd(Loader)
FrmMain.BtnExtraDownload.ShowRefresh()
FrmMain.BtnExtraDownload.Ribble()
End If
Catch ex As Exception
Log(ex, "[Update] 下载启动器更新文件失败", LogLevel.Hint)
Hint("下载启动器更新文件失败,请检查网络连接", HintType.Critical)
End Try
End Sub)
End Sub
Public Sub UpdateRestart(TriggerRestartAndByEnd As Boolean)
Try
Expand Down Expand Up @@ -905,12 +908,14 @@ PCL-Community 及其成员与龙腾猫跃无从属关系,且均不会为您的
Dim UpdateDesire = Setup.Get("SystemSystemUpdate")
Dim AnnouncementDesire = Setup.Get("SystemSystemActivity")
Select Case UpdateDesire
Case 0
If Not IsVerisonLatest() Then
Case 0, 1
If GetCurrentUpdateChannel() = UpdateChannel.nightly Then
NoticeUserUpdate(True) ' Nightly 通道强制检查更新
ElseIf UpdateDesire = 0 AndAlso Not IsVerisonLatest() Then
UpdateStart(True) '静默更新
ElseIf UpdateDesire = 1 Then
NoticeUserUpdate(True)
End If
Case 1
NoticeUserUpdate(True)
Case 2, 3
Exit Sub
End Select
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
Public Enum UpdateChannel
stable
beta
nightly
End Enum

Public Enum UpdateArch
Expand Down
100 changes: 100 additions & 0 deletions Plain Craft Launcher 2/Modules/Updates/UpdatesGitHubModel.vb
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
Imports System.IO.Compression
Imports Newtonsoft.Json
Imports PCL.Core.Utils

Public Class UpdatesGitHubModel
Implements IUpdateSource

Private Const NightlyJsonUrl As String = "https://github.com/PCL-Community/PCL2-CE/releases/download/nightly/nightly.json"
' Private Const NightlyJsonUrl As String = "https://r2.230225.xyz/nightly.json"
Private _nightlyInfo As NightlyJsonModel

Public Property SourceName As String Implements IUpdateSource.SourceName

Public Function IsAvailable() As Boolean Implements IUpdateSource.IsAvailable
Return True ' Assume network is available
End Function

Public Function RefreshCache() As Boolean Implements IUpdateSource.RefreshCache
Try
Dim jsonContent = NetGetCodeByRequestRetry(NightlyJsonUrl)
_nightlyInfo = JsonConvert.DeserializeObject(Of NightlyJsonModel)(jsonContent)
Return _nightlyInfo IsNot Nothing
Catch ex As Exception
Log(ex, "[Update] Failed to fetch nightly.json from GitHub")
Return False
End Try
End Function

Public Function GetLatestVersion(channel As UpdateChannel, arch As UpdateArch) As VersionDataModel Implements IUpdateSource.GetLatestVersion
If channel <> UpdateChannel.nightly Then Throw New NotSupportedException("UpdatesGitHubModel only supports the Nightly channel.")
If _nightlyInfo Is Nothing AndAlso Not RefreshCache() Then Throw New InvalidOperationException("Failed to get nightly update info.")

Dim asset = GetAssetForArch(arch)

Return New VersionDataModel With {
.VersionName = _nightlyInfo.version,
.VersionCode = _nightlyInfo.version_code,
.SHA256 = asset.sha256,
.Source = SourceName,
.Changelog = _nightlyInfo.changelog
}
End Function

Public Function IsLatest(channel As UpdateChannel, arch As UpdateArch, currentVersion As SemVer, currentVersionCode As Integer) As Boolean Implements IUpdateSource.IsLatest
If channel <> UpdateChannel.nightly Then Throw New NotSupportedException("UpdatesGitHubModel only supports the Nightly channel.")
If _nightlyInfo Is Nothing AndAlso Not RefreshCache() Then Return True ' If we can't get info, assume we're latest to avoid errors

Return currentVersionCode >= _nightlyInfo.version_code
End Function

Public Function GetAnnouncementList() As VersionAnnouncementDataModel Implements IUpdateSource.GetAnnouncementList
Throw New Exception("GitHub Nightly 无公告系统")
End Function

Public Function GetDownloadLoader(channel As UpdateChannel, arch As UpdateArch, output As String) As List(Of LoaderBase) Implements IUpdateSource.GetDownloadLoader
If channel <> UpdateChannel.nightly Then Throw New NotSupportedException("UpdatesGitHubModel only supports the Nightly channel.")
If _nightlyInfo Is Nothing AndAlso Not RefreshCache() Then Throw New InvalidOperationException("Failed to get nightly update info for download.")

Dim asset = GetAssetForArch(arch)
Dim downloadUrl = asset.download_url
Dim tempPath = IO.Path.Combine(PathTemp, "Cache", "Update", "Download", $"{asset.sha256}.zip")

Dim loaders As New List(Of LoaderBase)
' 1. 下载更新包
loaders.Add(New LoaderDownload("下载更新", New List(Of NetFile) From {New NetFile({downloadUrl}, tempPath)}))

' 2. 解压更新包,将 .exe 文件提取到 ModSecret 指定的 output 路径
loaders.Add(New LoaderTask(Of String, Integer)("提取文件", Sub()
Using fs As New IO.FileStream(tempPath, IO.FileMode.Open, IO.FileAccess.Read, IO.FileShare.Read)
Using zip As New ZipArchive(fs)
Dim entry = zip.Entries.FirstOrDefault(Function(x) x.Name.EndsWith(".exe", StringComparison.OrdinalIgnoreCase))
If entry Is Nothing Then Throw New InvalidOperationException("在下载的更新包中找不到可执行文件。")
entry.ExtractToFile(output, True)
End Using
End Using
End Sub))
Return loaders
End Function

Private Function GetAssetForArch(arch As UpdateArch) As NightlyAsset
Dim archName = If(arch = UpdateArch.arm64, "arm64", "x64")
Dim asset = _nightlyInfo.assets.FirstOrDefault(Function(a) a.arch.Equals(archName, StringComparison.OrdinalIgnoreCase))
If asset Is Nothing Then Throw New InvalidOperationException($"Nightly build for architecture {archName} not found.")
Return asset
End Function

End Class

Public Class NightlyJsonModel
Public Property version As String
Public Property version_code As Integer
Public Property changelog As String
Public Property assets As List(Of NightlyAsset)
End Class

Public Class NightlyAsset
Public Property arch As String
Public Property download_url As String
Public Property sha256 As String
End Class
3 changes: 2 additions & 1 deletion Plain Craft Launcher 2/Pages/PageSetup/PageSetupSystem.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -144,9 +144,10 @@
</local:MyComboBox>
<TextBlock VerticalAlignment="Center" HorizontalAlignment="Left" Text="启动器更新通道" Margin="0,0,25,0" Grid.Row="2"/>
<local:MyComboBox x:Name="ComboSystemUpdateBranch" Tag="SystemSystemUpdateBranch" Grid.Column="1" Grid.Row="2"
ToolTip="PCL 社区版提供了两种更新通道:&#xa;Slow Ring:较为稳定,功能通常已经过测试。&#xa;Fast Ring:更新较快,但可能包含未经充分测试的功能,可能不稳定。&#xa;&#xa;Fast Ring 仅推荐具有一定基础知识和能力的用户使用,且不适合用于制作整合包。&#xa;在升级到 Fast Ring 版本后,只能手动重新下载启动器来切换回 Slow Ring。&#xa;&#xa;如果你不知道你在干什么,请选择 Slow Ring。">
ToolTip="PCL 社区版提供了三种更新通道:&#xa;Slow Ring:较为稳定,功能通常已经过测试。&#xa;Fast Ring:更新较快,但可能包含未经充分测试的功能,可能不稳定。&#xa;Nightly:每日构建,包含 dev 分支的最新更改,仅供测试使用,极不稳定。&#xa;&#xa;Fast Ring 和 Nightly 仅推荐具有一定基础知识和能力的用户使用,且不适合用于制作整合包。&#xa;在升级到 Fast Ring 或 Nightly 版本后,只能手动重新下载启动器来切换回 Slow Ring。&#xa;&#xa;如果你不知道你在干什么,请选择 Slow Ring。">
<local:MyComboBoxItem Content="Slow Ring" />
<local:MyComboBoxItem Content="Fast Ring" />
<local:MyComboBoxItem Content="Nightly" />
</local:MyComboBox>
<TextBlock VerticalAlignment="Center" HorizontalAlignment="Left" Text="启动器公告" Margin="0,0,25,0" Grid.Row="4" />
<local:MyComboBox x:Name="ComboSystemActivity" Tag="SystemSystemActivity" Grid.Column="1" Grid.Row="4">
Expand Down
Loading
Loading