Skip to content
This repository was archived by the owner on Jan 25, 2026. It is now read-only.
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
66 commits
Select commit Hold shift + click to select a range
38b0dff
ref: 迁移 UpdateRestart 函数
wtommy932 Nov 15, 2025
56a4fd0
ref: 移动文件夹, 并添加 IUpdateSource 接口
wtommy932 Nov 16, 2025
8b4ce18
ref: 移动文件夹
wtommy932 Nov 16, 2025
561cf82
ref: 95% 的 UpdateMinioSource.cs, 以及比这多得多的优化重构
wtommy932 Nov 29, 2025
98047b3
fix: 修复路径问题(并在 Basics.cs 添加了 TempPath 常量)
wtommy932 Nov 29, 2025
a4f7caf
ref: 合合乐
wtommy932 Nov 29, 2025
aaa1e91
feat: 异常处理
wtommy932 Nov 29, 2025
97468b7
feat: 优化异常处理
wtommy932 Nov 29, 2025
f1b2622
ref: 吸取 Copilot 帮助
wtommy932 Nov 30, 2025
8fdb73d
ref: 重构, 没法描述重构了什么东西
wtommy932 Dec 2, 2025
6d74954
fix: 修复二义
wtommy932 Dec 2, 2025
8756036
feat: 优化等待逻辑
wtommy932 Dec 2, 2025
d723525
fix: 漏了一个 true
wtommy932 Dec 2, 2025
b2c0080
ref: 拆开以便维护
wtommy932 Dec 3, 2025
a20cec2
fix: 修复 Hint
wtommy932 Dec 22, 2025
1ae4871
feat: 搞定 SourceController.cs
wtommy932 Dec 27, 2025
a82a9a0
fix: AsyncStart
wtommy932 Dec 27, 2025
e8977ff
Potential fix for pull request finding 'Call to System.IO.Path.Combine'
wtommy932 Dec 27, 2025
6a46075
ref: refactor some code. for friendly logic (#156)
whitecat346 Dec 27, 2025
4a94573
Potential fix for pull request finding 'Use of default ToString()'
wtommy932 Dec 27, 2025
fed6a24
chore: use object?
wtommy932 Dec 27, 2025
3e09dde
feat: use scope
wtommy932 Dec 28, 2025
4d60247
Potential fix for pull request finding 'Generic catch clause'
wtommy932 Dec 28, 2025
b0e0515
Potential fix for pull request finding 'Generic catch clause'
wtommy932 Dec 28, 2025
1231dba
Potential fix for pull request finding 'Generic catch clause'
wtommy932 Dec 28, 2025
34f94ab
fix: 大括号和 catch 居然分家了, 这 AI 真牛逼
wtommy932 Dec 28, 2025
c688112
Potential fix for pull request finding 'Generic catch clause'
wtommy932 Dec 31, 2025
628fb3c
fix: 这 AI 写的什么玩意
wtommy932 Dec 31, 2025
fce461b
feat: 我改了什么呀...谁能告诉我...
wtommy932 Jan 1, 2026
4a3acb8
ref: 根据主线修改 UpdateHelper.Restart 方法
wtommy932 Jan 3, 2026
2466bbe
refactor: Resolved conversation
wtommy932 Jan 4, 2026
57d5688
fix: replace DownloadItem with DownloadTask and streamline download p…
wtommy932 Jan 4, 2026
5787397
refactor: improve update check and download error handling; enhance u…
wtommy932 Jan 5, 2026
0a55350
refactor: streamline update checking and downloading process
wtommy932 Jan 6, 2026
86ea1b4
fix: rebase 之后出 Bug 了...
wtommy932 Jan 9, 2026
d822376
refactor: remove unnecessary whitespace in Basics.cs
wtommy932 Jan 9, 2026
ec816bb
refactor: remove invisible character from Basics.cs
wtommy932 Jan 9, 2026
0afbc85
refactor: 写一半存个档
wtommy932 Jan 9, 2026
8489fe1
refactor: 完善 Json 重构
wtommy932 Jan 10, 2026
6180693
refactor: streamline download task handling and improve logging messages
wtommy932 Jan 11, 2026
b961e77
refactor: update CheckUpdateService to use LatestVersion and improve …
wtommy932 Jan 11, 2026
736f1c7
Merge branch 'main' into feat/update
wtommy932 Jan 11, 2026
231d1f8
fix: update IsAvailable property to check for non-empty baseUrl
wtommy932 Jan 11, 2026
dd693d5
refactor: update log messages to English for consistency
wtommy932 Jan 12, 2026
2b867ac
refactor: update version handling to use VersionData instead of Versi…
wtommy932 Jan 12, 2026
15ce4af
refactor: rename CheckUpdateService to UpdateService for clarity
wtommy932 Jan 13, 2026
6baa9f7
ref: add new update source for Naids
wtommy932 Jan 13, 2026
b5db3fe
ref: change IsUpdateDownloaded property to private setter
wtommy932 Jan 13, 2026
5219293
Merge branch 'main' into feat/update
wtommy932 Jan 13, 2026
b572e2e
refactor: migrate data models to UpdateMinioSource.cs
wtommy932 Jan 13, 2026
39bcb48
refactor: remove unused using directive in VersionAnnouncementDataModel
wtommy932 Jan 13, 2026
20638c9
refactor: add current source tracking and improve error handling
wtommy932 Jan 13, 2026
c9d8eab
fix: improve error handling for update source exceptions
wtommy932 Jan 13, 2026
bde3942
Merge branch 'main' into feat/update
wtommy932 Jan 15, 2026
5be0ada
refactor: 改了一坨...(还是用中文 commit mesage 吧)
wtommy932 Jan 15, 2026
0074b5a
refactor: 改点名字
wtommy932 Jan 16, 2026
c8f71c7
refactor: 把 UpdateMinioSource 的日志改回中文
wtommy932 Jan 16, 2026
19dc15c
refactor: SourceController 的日志, 还有别的东西
wtommy932 Jan 16, 2026
571942f
refactor: 日志改中文
wtommy932 Jan 16, 2026
450b2c2
refactor: 简化记录定义
wtommy932 Jan 16, 2026
7a44766
refactor: 加个回车
wtommy932 Jan 16, 2026
12041cd
fix: 修复一个 Bug
wtommy932 Jan 16, 2026
28a9bfa
fix: 用错了
wtommy932 Jan 16, 2026
c8111f2
fix: 修复不正确的退出逻辑
wtommy932 Jan 16, 2026
08bc253
refactor: 改个名
wtommy932 Jan 16, 2026
f7656ff
refactor: 手动回滚 UpdateService
wtommy932 Jan 16, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
152 changes: 152 additions & 0 deletions App/Updates/CheckUpdateService.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
using PCL.Core.App.Updates.Sources;
using PCL.Core.UI;
using System;
using System.IO;
using System.Threading.Tasks;

namespace PCL.Core.App.Updates;

[LifecycleService(LifecycleState.Running)]
[LifecycleScope("check-update", "检查更新")]
public sealed partial class CheckUpdateService
{
private static readonly SourceController _SourceController = new([
new UpdateMinioSource("https://s3.pysio.online/pcl2-ce/", "Pysio"),
new UpdateMinioSource("https://staticassets.naids.com/resources/pclce/", "Naids")
]);

public static VersionData? LatestVersion { get; private set; }

public static bool IsUpdateDownloaded { get; private set; }

[LifecycleStart]
private static async Task _Start()
{
if (Config.System.Update.UpdateMode == 3)
{
Context.Info("更新模式为禁用,跳过检查");
return;
}

Context.Info("检查更新中...");
if (!await TryCheckUpdate() || LatestVersion is null) return;

if (!LatestVersion.IsAvailable)
{
Context.Info("已经是最新版本,跳过更新");
return;
}

Context.Info($"发现新版本: {LatestVersion.Version.Code}, 准备更新");

if (Config.System.Update.UpdateMode == 2 && !_PromptUpdate()) return;

if (!await TryDownloadUpdate()) return;

if (Config.System.Update.UpdateMode == 1 && !_PromptInstall()) return;

Context.Info("准备重启并安装...");
UpdateHelper.Restart(true, true);
}

#region Public Methods

public static async Task<bool> TryCheckUpdate()
{
try
{
LatestVersion = await _SourceController.CheckUpdateAsync().ConfigureAwait(false);
return true;
}
catch (InvalidOperationException ex)
{
if (ex.Message.Contains("不可用"))
{
Context.Warn("所有更新源均不可用", ex);
HintWrapper.Show("所有更新源均不可用,可能是网络问题", HintTheme.Error);
}
else
{
Context.Warn("检查更新时发生未知异常", ex);
HintWrapper.Show("检查更新时发生未知异常,可能是网络问题", HintTheme.Error);
}
}
catch (Exception ex)
{
Context.Warn("检查更新时发生未知异常", ex);
HintWrapper.Show("检查更新时发生未知异常,可能是网络问题", HintTheme.Error);
}
return false;
}

public static async Task<bool> TryDownloadUpdate()
{
Context.Info("下载更新包中...");
try
{
var outputPath = Path.Combine(
Basics.ExecutableDirectory,
"PCL",
"Plain Craft Launcher Community Edition.exe");
if (LatestVersion == null) return false;
await _SourceController.DownloadAsync(outputPath).ConfigureAwait(false);
Context.Info("更新包下载完成");
IsUpdateDownloaded = true;
return true;
}
catch (InvalidOperationException ex)
{
if (ex.Message.Contains("不可用"))
{
Context.Warn("所有更新源均不可用", ex);
HintWrapper.Show("所有更新源均不可用,可能是网络问题", HintTheme.Error);
}
else
{
Context.Warn("下载更新包时发生未知异常", ex);
HintWrapper.Show("下载更新包时发生未知异常,可能是网络问题", HintTheme.Error);
}
}
catch (Exception ex)
{
Context.Warn("下载更新包时发生未知异常", ex);
HintWrapper.Show("下载更新包时发生未知异常,可能是网络问题", HintTheme.Error);
}
return false;
}

#endregion

#region Prompt Wrappers

private static bool _PromptUpdate()
{
if (LatestVersion == null) return false;

if (MsgBoxWrapper.Show(
$"启动器有新版本可用 ({Basics.VersionName} -> {LatestVersion.Version.Name})\r\n" +
$"是否立即下载并安装?\r\n" +
"你也可以稍后在 设置 -> 检查更新 界面中更新。",
"发现新版本", MsgBoxTheme.Info, true, "立刻更新", "以后再说") == 1) return true;

Context.Info("用户取消更新");
return false;
}

private static bool _PromptInstall()
{
if (LatestVersion == null) return false;
if (!IsUpdateDownloaded) return false;

if (MsgBoxWrapper.Show(
$"启动器有新版本可用 ({Basics.VersionName} -> {LatestVersion.Version.Name})\r\n" +
$"已自动下载,是否立即安装?\r\n" +
"你也可以稍后在 设置 -> 检查更新 界面中安装。",
"发现新版本", MsgBoxTheme.Info, true, "立刻更新", "以后再说") == 1) return true;

Context.Info("用户取消安装");
return false;
}

#endregion
}
39 changes: 39 additions & 0 deletions App/Updates/Sources/DataModel.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
using System.Text.Json.Serialization;
using PCL.Core.Utils;

namespace PCL.Core.App.Updates.Sources;

public sealed record VersionInfoData(
[property: JsonPropertyName("name")] string Name,
[property: JsonPropertyName("code")] int Code
);

public sealed record VersionData (
[property: JsonPropertyName("version")] VersionInfoData Version,
[property: JsonPropertyName("sha256")] string Sha256,
[property: JsonPropertyName("changelog")] string ChangeLog,
[property: JsonPropertyName("patches")] string[] Patches,
[property: JsonPropertyName("downloads")] string[] Downloads
) {
public bool IsAvailable => Version.Code > Basics.VersionCode &&
SemVer.Parse(Version.Name) > SemVer.Parse(Basics.VersionName);
}

public record AnnouncementsList(
[property: JsonPropertyName("content")] AnnouncementContent[] Contents
);

public record AnnouncementContent(
[property: JsonPropertyName("title")] string Title,
[property: JsonPropertyName("detail")] string Detail,
[property: JsonPropertyName("id")] string Id,
[property: JsonPropertyName("date")] string Date,
[property: JsonPropertyName("btn1")] AnnouncementBtnInfo? Btn1,
[property: JsonPropertyName("btn2")] AnnouncementBtnInfo? Btn2
);

public record AnnouncementBtnInfo (
[property: JsonPropertyName("text")] string Text,
[property: JsonPropertyName("command")] string Command,
[property: JsonPropertyName("command_paramter")] string CommandParameter
);
34 changes: 34 additions & 0 deletions App/Updates/Sources/IUpdateSource.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
using System.Threading.Tasks;

namespace PCL.Core.App.Updates.Sources;

public interface IUpdateSource
{
/// <summary>
/// 检查更新
/// </summary>
/// <returns>检查更新结果</returns>
public Task<VersionData> CheckUpdateAsync();

/// <summary>
/// 获取版本公告列表
/// </summary>
/// <returns>版本公告列表</returns>
public Task<AnnouncementsList> GetAnnouncementAsync();

/// <summary>
/// 下载更新文件
/// </summary>
/// <param name="outputPath">输出路径</param>
public Task DownloadAsync(string outputPath);

/// <summary>
/// 更新源名称
/// </summary>
public string SourceName { get; }

/// <summary>
/// 更新源是否可用
/// </summary>
public bool IsAvailable { get; }
}
118 changes: 118 additions & 0 deletions App/Updates/Sources/SourceController.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
using PCL.Core.Logging;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;

namespace PCL.Core.App.Updates.Sources;

/// <summary>
/// 管理多个更新源,尝试找到可用源并调用。
/// </summary>
public sealed class SourceController
{
private readonly List<IUpdateSource> _availableSources;

private readonly SemaphoreSlim _semaphore = new(1, 1);

/// <summary>
/// 初始化并过滤出可用的更新源。
/// </summary>
public SourceController(IEnumerable<IUpdateSource> sources)
{
_availableSources = sources
.Where(s => s.IsAvailable)
.ToList();
}

/// <summary>
/// 尝试使用当前源处理操作,若失败则遍历其他可用源直至成功或无可用源。
/// </summary>
/// <param name="action">指定操作</param>
/// <typeparam name="T">返回类型</typeparam>
/// <returns>操作返回值</returns>
/// <exception cref="InvalidOperationException">所有更新源均不可用时抛出</exception>
private async Task<T> _TryFindSourceAsync<T>(Func<IUpdateSource, Task<T>> action)
{
await _semaphore.WaitAsync().ConfigureAwait(false);
try
{
foreach (var source in _availableSources)
{
try
{
var res = await action(source).ConfigureAwait(false);
_LogInfo($"源 {source.SourceName} 处理成功");
return res;
}
catch (Exception ex)
{
_LogWarning($"源 {source.SourceName} 不可用,使用下一个源", ex);
}
}

throw new InvalidOperationException("所有源均不可用");
}
finally
{
_semaphore.Release();
}
}

/// <summary>
/// 尝试使用当前源处理操作,若失败则遍历其他可用源直至成功或无可用源。
/// </summary>
/// <param name="action">指定操作</param>
/// <exception cref="InvalidOperationException">所有更新源均不可用时抛出</exception>
private async Task _TryFindSourceAsync(Func<IUpdateSource, Task> action)
{
await _TryFindSourceAsync<object?>(async s =>
{
await action(s).ConfigureAwait(false);
return null;
}).ConfigureAwait(false);
}

/// <summary>
/// 检查是否有新版本并返回结果。
/// </summary>
public Task<VersionData> CheckUpdateAsync() =>
_TryFindSourceAsync(s => s.CheckUpdateAsync());

/// <summary>
/// 获取公告列表。
/// </summary>
public Task<AnnouncementsList> GetAnnouncementListAsync() =>
_TryFindSourceAsync(s => s.GetAnnouncementAsync());

/// <summary>
/// 使用可用源下载到指定路径。
/// </summary>
public Task DownloadAsync(string outputPath) =>
_TryFindSourceAsync(s => s.DownloadAsync(outputPath));

#region Logger Wrapper

private void _LogInfo(string msg)
{
LogWrapper.Info("Update", msg);
}

private void _LogWarning(string msg, Exception? ex = null)
{
LogWrapper.Warn(ex, "Update", msg);
}

private void _LogError(string msg, Exception? ex = null)
{
LogWrapper.Error(ex, "Update", msg);
}

private void _LogTrace(string msg)
{
LogWrapper.Trace("Update", msg);
}

#endregion
}
Loading
Loading