-
Notifications
You must be signed in to change notification settings - Fork 86
feat(app): 全新的公告系统 #2786
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
LinQingYuu
wants to merge
6
commits into
dev
Choose a base branch
from
feat/announcement
base: dev
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
feat(app): 全新的公告系统 #2786
Changes from all commits
Commits
Show all changes
6 commits
Select commit
Hold shift + click to select a range
5cdb34b
feat(app): 全新的公告系统
LinQingYuu c32f753
fix: invalid using
LinQingYuu a726ff0
fix: mismaatch JsonPropertyName
LinQingYuu 8388b31
fix: undefined config
LinQingYuu 56762ff
fix: undefined secret
LinQingYuu 3ebd0cd
fix: use OrderByDescending
LinQingYuu File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
102 changes: 102 additions & 0 deletions
102
PCL.Core/App/Essentials/Announcement/AnnouncementService.cs
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,102 @@ | ||
| using System; | ||
| using System.Collections.Generic; | ||
| using System.Diagnostics; | ||
| using System.Linq; | ||
| using System.Net.Http; | ||
| using System.Text.Json; | ||
| using System.Threading.Tasks; | ||
| using PCL.Core.App.Essentials.Announcement.Models; | ||
| using PCL.Core.App.IoC; | ||
| using PCL.Core.IO.Net.Http; | ||
| using PCL.Core.Logging; | ||
| using PCL.Core.UI; | ||
|
|
||
| namespace PCL.Core.App.Essentials.Announcement; | ||
|
|
||
| [LifecycleScope("announcement","公告")] | ||
| [LifecycleService(LifecycleState.Running)] | ||
| public partial class AnnouncementService | ||
| { | ||
|
|
||
| private static readonly string[] _AllowScheme = ["http", "https", "minecraft" ]; | ||
| private static readonly string[] _AnnouncementServerList = Secrets.AnnouncementServerList; | ||
|
|
||
| private static List<string> _ignored = | ||
| JsonSerializer.Deserialize<string[]>(Config.System.HiddenAnnouncement)?.ToList() ?? []; | ||
|
|
||
| [LifecycleStart] | ||
| private static async Task _Start() | ||
| { | ||
| // 可能会出现公告服务比配置服务晚关闭的情况 | ||
| Lifecycle.StateChanged += state => | ||
| { | ||
| if (state == LifecycleState.Closing) Config.System.HiddenAnnouncement = JsonSerializer.Serialize(_ignored); | ||
| }; | ||
| try | ||
| { | ||
| foreach (var source in _AnnouncementServerList) | ||
| { | ||
| var response = await HttpRequest.GetJsonAsync<List<AnnouncementDetails>>(source) | ||
| .ConfigureAwait(false); | ||
| if (response is null) continue; | ||
|
|
||
| // 对忽略的公告进行检查1,以确保仍然处于公告列表内 | ||
|
|
||
| var invalid = _ignored.Except(response.Select(a => a.Id)).ToList(); | ||
| _ignored.RemoveAll(invalid.Contains); | ||
|
|
||
| var announcements = response.OrderByDescending(a => a.Priority).Where(a => | ||
| { | ||
| var isNotAfterValid = DateTimeOffset.TryParse(a.SkipOn.NotAfter, out var notAfter); | ||
| var isNotBeforeValid = DateTimeOffset.TryParse(a.SkipOn.NotBefore, out var notBefore); | ||
| var localTime = DateTimeOffset.Now; | ||
| if (isNotAfterValid && localTime > notAfter) return false; | ||
| if (isNotBeforeValid && localTime < notBefore) return false; | ||
| var currentVersion = new Version(Basics.VersionName.Split("-")[0]); | ||
| var max = new Version(a.SkipOn.MaxVersion ?? "999.999.999"); | ||
| var min = new Version(a.SkipOn.MinVersion ?? "0.0.0"); | ||
|
|
||
| // [min,max] | ||
| return currentVersion >= min && currentVersion <= max; | ||
|
|
||
| }); | ||
| foreach (var detail in announcements) | ||
| { | ||
| Context.Debug(MsgBoxWrapper.ShowWithCustomButtons( | ||
| detail.Details, $"{detail.Title} ({detail.ReleaseDate})", _GetSelectTheme(detail.Level), | ||
| false, | ||
| detail.Buttons.Select(operation => new MsgBoxButtonInfo(operation.ButtonText, | ||
| OnClick: _GetSelectCallback(operation.Operation, operation.Argument))).ToArray()).ToString()); | ||
| } | ||
| } | ||
| } | ||
| catch (HttpRequestException ex) | ||
| { | ||
| Context.Error("加载公告失败", ex, ActionLevel.HintErr); | ||
| } | ||
| } | ||
|
|
||
| private static Action _GetSelectCallback(string operation, string arguments) => operation switch | ||
| { | ||
| "OpenWebSite" => () => | ||
| { | ||
| if (arguments.Length == 0) throw new ArgumentException("Uri is missing"); | ||
| if (_AllowScheme.All(s => new Uri(arguments).Scheme != s)) | ||
| throw new InvalidOperationException("This uri contains a unsupported scheme."); | ||
| Process.Start(new ProcessStartInfo(arguments){ UseShellExecute = true }); | ||
|
|
||
| }, | ||
| "StopShow" => () => | ||
| { | ||
| _ignored.Add(arguments); | ||
| }, | ||
| _ => static () => { } | ||
| }; | ||
|
|
||
| private static MsgBoxTheme _GetSelectTheme(AnnouncementLevel level) => level switch | ||
| { | ||
| AnnouncementLevel.Medium => MsgBoxTheme.Warning, | ||
| AnnouncementLevel.Highest => MsgBoxTheme.Error, | ||
| _ => MsgBoxTheme.Info | ||
| }; | ||
| } | ||
56 changes: 56 additions & 0 deletions
56
PCL.Core/App/Essentials/Announcement/Models/AnnouncementDetails.cs
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,56 @@ | ||
| using System; | ||
| using System.Collections.Generic; | ||
| using System.Text.Json.Serialization; | ||
|
|
||
| namespace PCL.Core.App.Essentials.Announcement.Models; | ||
|
|
||
| public record AnnouncementDetails | ||
| { | ||
| /// <summary> | ||
| /// 公告标题 | ||
| /// </summary> | ||
| [JsonPropertyName("title")] | ||
| public required string Title { get; init; } | ||
|
|
||
| /// <summary> | ||
| /// 公告内容 | ||
| /// </summary> | ||
| [JsonPropertyName("details")] | ||
| public required string Details { get; init; } | ||
|
|
||
| /// <summary> | ||
| /// 该公告的优先级,值越高优先级越高 | ||
| /// </summary> | ||
| [JsonPropertyName("priority")] | ||
| public int Priority { get; init; } | ||
|
|
||
| /// <summary> | ||
| /// 公告 ID | ||
| /// </summary> | ||
| [JsonPropertyName("id")] | ||
| public required string Id { get; init; } | ||
|
|
||
| /// <summary> | ||
| /// 该公告的等级,决定弹窗应该用什么样式 | ||
| /// </summary> | ||
| [JsonPropertyName("level")] | ||
| public required AnnouncementLevel Level { get; init; } | ||
|
|
||
| /// <summary> | ||
| /// 该公告的发布日期 | ||
| /// </summary> | ||
| [JsonPropertyName("date")] | ||
| public required string ReleaseDate { get; init; } | ||
|
|
||
| /// <summary> | ||
| /// 显示条件 | ||
| /// </summary> | ||
| [JsonPropertyName("skip")] | ||
| public required AnnouncementSkipCondition SkipOn { get; init; } | ||
|
|
||
| /// <summary> | ||
| /// 弹窗按钮信息 | ||
| /// </summary> | ||
| [JsonPropertyName("buttons")] | ||
| public required IEnumerable<AnnouncementOperation> Buttons { get; init; } | ||
| } |
17 changes: 17 additions & 0 deletions
17
PCL.Core/App/Essentials/Announcement/Models/AnnouncementLevel.cs
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,17 @@ | ||
| namespace PCL.Core.App.Essentials.Announcement.Models; | ||
|
|
||
| public enum AnnouncementLevel | ||
| { | ||
| /// <summary> | ||
| /// 最低的等级,属于可看可不看的那种 | ||
| /// </summary> | ||
| Lowest, | ||
| /// <summary> | ||
| /// 用户应该稍微有点了解的公告 | ||
| /// </summary> | ||
| Medium, | ||
| /// <summary> | ||
| /// 必须让用户知道并理解的公告内容 | ||
| /// </summary> | ||
| Highest | ||
| } |
25 changes: 25 additions & 0 deletions
25
PCL.Core/App/Essentials/Announcement/Models/AnnouncementOperation.cs
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,25 @@ | ||
| using System.Collections.Generic; | ||
| using System.Text.Json.Serialization; | ||
|
|
||
| namespace PCL.Core.App.Essentials.Announcement.Models; | ||
|
|
||
| public record AnnouncementOperation | ||
| { | ||
| /// <summary> | ||
| /// 按钮文本 | ||
| /// </summary> | ||
| [JsonPropertyName("text")] | ||
| public required string ButtonText { get; init; } | ||
|
|
||
| /// <summary> | ||
| /// 按下后的操作 | ||
| /// </summary> | ||
| [JsonPropertyName("exec")] | ||
| public required string Operation { get; init; } | ||
|
|
||
| /// <summary> | ||
| /// 参数列表 | ||
| /// </summary> | ||
| [JsonPropertyName("argument")] | ||
| public required string Argument { get; init; } | ||
| } |
16 changes: 16 additions & 0 deletions
16
PCL.Core/App/Essentials/Announcement/Models/AnnouncementSkipCondition.cs
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,16 @@ | ||
| using System.Text.Json.Serialization; | ||
|
|
||
| namespace PCL.Core.App.Essentials.Announcement.Models; | ||
|
|
||
| public class AnnouncementSkipCondition | ||
| { | ||
| [JsonPropertyName("min")] | ||
| public string? MinVersion { get; init; } | ||
| [JsonPropertyName("max")] | ||
| public string? MaxVersion { get; init; } | ||
| [JsonPropertyName("notAfter")] | ||
| public string? NotAfter { get; init; } | ||
| [JsonPropertyName("notBefore")] | ||
| public string? NotBefore { get; init; } | ||
|
|
||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
suggestion: 某一个公告服务器失败会中止后续服务器的处理。
因为
foreach (var source in _AnnouncementServerList)循环被包裹在一个统一的try/catch (HttpRequestException)中,只要任意一个服务器抛出异常,就会阻止后续服务器被处理。请针对每个服务器单独处理HttpRequestException(例如,在每次迭代外包一层,或者在GetJsonAsync内部捕获),以避免单个失败的端点阻塞其它端点。建议实现方式:
要完整实现你在审查意见中建议的“按服务器分别处理错误”,可以:
foreach (var source in _AnnouncementServerList)循环。source公告的GetJsonAsync/HttpClient调用)包裹在各自的try/catch (HttpRequestException ex)块中。catch中,使用Context.Error("加载公告失败", ex, ActionLevel.HintErr);(或带上服务器/来源标识的变体)记录失败日志,然后使用continue;继续处理下一个服务器,而不是中止整个循环。_AnnouncementServerList循环的外层try/catch (HttpRequestException),这样单个失败的端点就不会阻止后续端点被处理。Original comment in English
suggestion: A failure on one announcement server aborts processing of subsequent servers.
Because the
foreach (var source in _AnnouncementServerList)loop is inside a singletry/catch (HttpRequestException), an exception from any server will prevent later servers from being processed. Please handleHttpRequestExceptionper server (e.g., around each iteration or insideGetJsonAsync) so one failing endpoint doesn’t block the rest.Suggested implementation:
To fully implement per-server error handling as suggested in your review comment, you should:
foreach (var source in _AnnouncementServerList)loop earlier in this method.GetJsonAsync/HttpClientcall that fetches announcements for thatsource) in its owntry/catch (HttpRequestException ex)block.catch, log the failure usingContext.Error("加载公告失败", ex, ActionLevel.HintErr);(or a variant that includes the server/source identifier) and thencontinue;to proceed to the next server instead of aborting the loop.try/catch (HttpRequestException)that wraps the entire_AnnouncementServerListloop, so that one failing endpoint does not prevent subsequent servers from being processed.