From 80e89f713904e4ee791d4ecef96aa52a115afc5d Mon Sep 17 00:00:00 2001 From: Scighost Date: Tue, 21 Jan 2025 12:59:11 +0800 Subject: [PATCH] use memory cache instead dictionary --- .../GameSelector/GameSelector.xaml.cs | 42 ++++-- .../Features/HoYoPlay/HoYoPlayService.cs | 129 ++++-------------- src/Starward/Frameworks/AppService.cs | 1 + src/Starward/Starward.csproj | 1 + 4 files changed, 60 insertions(+), 113 deletions(-) diff --git a/src/Starward/Features/GameSelector/GameSelector.xaml.cs b/src/Starward/Features/GameSelector/GameSelector.xaml.cs index 1bdd6c754..cd592b380 100644 --- a/src/Starward/Features/GameSelector/GameSelector.xaml.cs +++ b/src/Starward/Features/GameSelector/GameSelector.xaml.cs @@ -22,6 +22,7 @@ using System.Numerics; using System.Runtime.InteropServices; using System.Text; +using System.Text.Json; using System.Threading; using System.Threading.Tasks; using Vanara.PInvoke; @@ -75,8 +76,9 @@ public GameSelector() public void InitializeGameSelector() { - InitializeGameIconsArea(); - InitializeGameServerArea(); + List gameInfos = GetCachedGameInfos(); + InitializeGameIconsArea(gameInfos); + InitializeGameServerArea(gameInfos); InitializeInstalledGamesCommand.Execute(null); } @@ -116,6 +118,22 @@ private async void OnMainWindowStateChanged(object? _, MainWindowStateChangedMes + private List GetCachedGameInfos() + { + try + { + string? json = AppSetting.CachedGameInfo; + if (!string.IsNullOrWhiteSpace(json)) + { + return JsonSerializer.Deserialize>(json) ?? []; + } + } + catch { } + return []; + } + + + #region Game Icon @@ -123,7 +141,7 @@ private async void OnMainWindowStateChanged(object? _, MainWindowStateChangedMes /// /// 初始化游戏图标区域 /// - private void InitializeGameIconsArea() + private void InitializeGameIconsArea(List gameInfos) { try { @@ -139,7 +157,7 @@ private void InitializeGameIconsArea() // 已知的 GameBiz GameBizIcons.Add(new GameBizIcon(biz)); } - else if (_hoyoplayService.GetCachedGameInfo(biz) is GameInfo info) + else if (gameInfos.FirstOrDefault(x => x.GameBiz == biz) is GameInfo info) { // 由 HoYoPlay API 获取,但未适配的 GameBiz GameBizIcons.Add(new GameBizIcon(info)); @@ -160,7 +178,7 @@ private void InitializeGameIconsArea() CurrentGameBizIcon.IsSelected = true; CurrentGameBiz = lastSelectedGameBiz; } - else if (_hoyoplayService.GetCachedGameInfo(lastSelectedGameBiz) is GameInfo info) + else if (gameInfos.FirstOrDefault(x => x.GameBiz == lastSelectedGameBiz) is GameInfo info) { CurrentGameBizIcon = new GameBizIcon(info); CurrentGameBizIcon.IsSelected = true; @@ -496,17 +514,16 @@ private void Border_FullBackground_Tapped(object sender, Microsoft.UI.Xaml.Input /// /// 初始化游戏服务器选择区域 /// - private void InitializeGameServerArea() + private void InitializeGameServerArea(List gameInfos) { try { var list = new List(); - var infos = _hoyoplayService.GetCachedGameInfoList(); if (LanguageUtil.FilterLanguage(CultureInfo.CurrentUICulture.Name) is "zh-cn") { // 当前语言为简体中文时,游戏信息显示从中国官服获取的内容 - foreach (var info in infos) + foreach (var info in gameInfos) { if (info.GameBiz.IsChinaServer() && !info.IsBilibiliServer()) { @@ -517,7 +534,7 @@ private void InitializeGameServerArea() else { // 当前语言不为简体中文时,游戏信息显示从国际服获取的内容 - foreach (var info in infos) + foreach (var info in gameInfos) { if (info.GameBiz.IsGlobalServer()) { @@ -541,7 +558,7 @@ private void InitializeGameServerArea() }; item.Servers.Add(server); } - else if (_hoyoplayService.GetCachedGameInfo(biz) is GameInfo info) + else if (gameInfos.FirstOrDefault(x => x.GameBiz == biz) is GameInfo info) { var server = new GameBizIcon(info) { @@ -566,9 +583,8 @@ private async Task UpdateGameInfoAsync() { try { - _hoyoplayService.ClearCache(); - await _hoyoplayService.UpdateGameInfoListAsync(); - InitializeGameServerArea(); + List gameInfos = await _hoyoplayService.UpdateGameInfoListAsync(); + InitializeGameServerArea(gameInfos); foreach (GameBizIcon icon in GameBizIcons) { if (icon.GameBiz.IsKnown()) diff --git a/src/Starward/Features/HoYoPlay/HoYoPlayService.cs b/src/Starward/Features/HoYoPlay/HoYoPlayService.cs index 5cee6bd33..3efe14ac9 100644 --- a/src/Starward/Features/HoYoPlay/HoYoPlayService.cs +++ b/src/Starward/Features/HoYoPlay/HoYoPlayService.cs @@ -1,9 +1,9 @@ -using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Caching.Memory; +using Microsoft.Extensions.Logging; using Starward.Core; using Starward.Core.HoYoPlay; using Starward.Frameworks; using System; -using System.Collections.Concurrent; using System.Collections.Generic; using System.Globalization; using System.IO; @@ -25,114 +25,44 @@ public class HoYoPlayService private readonly HttpClient _httpClient; - private readonly System.Timers.Timer _timer; + private readonly IMemoryCache _memoryCache; - public HoYoPlayService(ILogger logger, HoYoPlayClient client, HttpClient httpClient) + public HoYoPlayService(ILogger logger, HoYoPlayClient client, HttpClient httpClient, IMemoryCache memoryCache) { _logger = logger; _client = client; _httpClient = httpClient; - _timer = new System.Timers.Timer - { - AutoReset = true, - Enabled = true, - Interval = TimeSpan.FromMinutes(10).TotalMilliseconds, - }; - _timer.Elapsed += (_, _) => ClearCache(); - LoadCachedGameInfo(); + _memoryCache = memoryCache; } - private List _gameInfoList = new(); - - - private ConcurrentDictionary _gameInfo = new(); - - - private ConcurrentDictionary _gameBackground = new(); - - - private ConcurrentDictionary _gameContent = new(); - - - private ConcurrentDictionary _gamePackage = new(); - - - private ConcurrentDictionary _gameConfig = new(); - - - private ConcurrentDictionary _gameChannelSDK = new(); - - - private void LoadCachedGameInfo() - { - try - { - string? json = AppSetting.CachedGameInfo; - if (!string.IsNullOrWhiteSpace(json)) - { - var infos = JsonSerializer.Deserialize>(json); - if (infos is not null) - { - _gameInfoList = infos; - foreach (var item in infos) - { - _gameInfo[item] = item; - } - } - } - } - catch { } - } - - - - public void ClearCache() - { - _gameInfoList.Clear(); - _gameInfo.Clear(); - _gameBackground.Clear(); - _gameContent.Clear(); - _gamePackage.Clear(); - _gameChannelSDK.Clear(); - } public async Task GetGameInfoAsync(GameId gameId) { - if (!_gameInfo.TryGetValue(gameId, out GameInfo? info)) + if (!_memoryCache.TryGetValue($"{nameof(GameInfo)}_{gameId.Id}", out GameInfo? info)) { string lang = CultureInfo.CurrentUICulture.Name; var list = await _client.GetGameInfoAsync(LauncherId.FromGameId(gameId)!, lang); foreach (var item in list) { - _gameInfo[item] = item; + _memoryCache.Set($"{nameof(GameInfo)}_{item.Id}", item, TimeSpan.FromMinutes(10)); } - info = list.First(x => x == gameId); + info = list.FirstOrDefault(x => x == gameId); } - return info; - } - - - - public GameInfo? GetCachedGameInfo(GameBiz biz) - { - return _gameInfo.Values.FirstOrDefault(x => x.GameBiz == biz); - } - - - - public List GetCachedGameInfoList() - { - return _gameInfoList; + return info!; } public async Task> UpdateGameInfoListAsync(CancellationToken cancellationToken = default) { + if (_memoryCache is MemoryCache cache) + { + cache.Clear(); + } List infos = new List(); string lang = CultureInfo.CurrentUICulture.Name; if (LanguageUtil.FilterLanguage(lang) is "zh-cn") @@ -149,10 +79,9 @@ public async Task> UpdateGameInfoListAsync(CancellationToken canc { infos.AddRange(await _client.GetGameInfoAsync(launcherId, lang, cancellationToken)); } - _gameInfoList = infos; foreach (var item in infos) { - _gameInfo[item] = item; + _memoryCache.Set($"{nameof(GameInfo)}_{item.Id}", item, TimeSpan.FromMinutes(10)); } string json = JsonSerializer.Serialize(infos); AppSetting.CachedGameInfo = json; @@ -213,60 +142,60 @@ await Parallel.ForEachAsync(infos, async (info, _) => public async Task GetGameBackgroundAsync(GameId gameId) { - if (!_gameBackground.TryGetValue(gameId, out GameBackgroundInfo? background)) + if (!_memoryCache.TryGetValue($"{nameof(GameBackgroundInfo)}_{gameId.Id}", out GameBackgroundInfo? background)) { string lang = CultureInfo.CurrentUICulture.Name; var list = await _client.GetGameBackgroundAsync(LauncherId.FromGameId(gameId)!, lang); foreach (var item in list) { - _gameBackground[item.GameId] = item; + _memoryCache.Set($"{nameof(GameBackgroundInfo)}_{item.GameId.Id}", item, TimeSpan.FromMinutes(1)); } - background = list.First(x => x.GameId == gameId); + background = list.FirstOrDefault(x => x.GameId == gameId); } - return background; + return background!; } public async Task GetGameContentAsync(GameId gameId) { - if (!_gameContent.TryGetValue(gameId, out GameContent? content)) + if (!_memoryCache.TryGetValue($"{nameof(GameContent)}_{gameId.Id}", out GameContent? content)) { string lang = CultureInfo.CurrentUICulture.Name; content = await _client.GetGameContentAsync(LauncherId.FromGameId(gameId)!, lang, gameId); - _gameContent[gameId] = content; + _memoryCache.Set($"{nameof(GameContent)}_{content.GameId.Id}", content, TimeSpan.FromMinutes(1)); } - return content; + return content!; } public async Task GetGamePackageAsync(GameId gameId) { - if (!_gamePackage.TryGetValue(gameId, out GamePackage? package)) + if (!_memoryCache.TryGetValue($"{nameof(GamePackage)}_{gameId.Id}", out GamePackage? package)) { string lang = CultureInfo.CurrentUICulture.Name; var list = await _client.GetGamePackageAsync(LauncherId.FromGameId(gameId)!, lang); foreach (var item in list) { - _gamePackage[item.GameId] = item; + _memoryCache.Set($"{nameof(GamePackage)}_{item.GameId.Id}", item, TimeSpan.FromMinutes(1)); } - package = list.First(x => x.GameId == gameId); + package = list.FirstOrDefault(x => x.GameId == gameId); } - return package; + return package!; } public async Task GetGameConfigAsync(GameId gameId) { - if (!_gameConfig.TryGetValue(gameId, out GameConfig? config)) + if (!_memoryCache.TryGetValue($"{nameof(GameConfig)}_{gameId.Id}", out GameConfig? config)) { string lang = CultureInfo.CurrentUICulture.Name; var list = await _client.GetGameConfigAsync(LauncherId.FromGameId(gameId)!, lang); foreach (var item in list) { - _gameConfig[item.GameId] = item; + _memoryCache.Set($"{nameof(GameConfig)}_{item.GameId.Id}", item, TimeSpan.FromMinutes(1)); } config = list.FirstOrDefault(x => x.GameId == gameId); } @@ -293,13 +222,13 @@ public async Task> GetGameDeprecatedFilesAsync(GameId g public async Task GetGameChannelSDKAsync(GameId gameId) { - if (!_gameChannelSDK.TryGetValue(gameId, out GameChannelSDK? sdk)) + if (!_memoryCache.TryGetValue($"{nameof(GameChannelSDK)}_{gameId.Id}", out GameChannelSDK? sdk)) { string lang = CultureInfo.CurrentUICulture.Name; var list = await _client.GetGameChannelSDKAsync(LauncherId.FromGameId(gameId)!, lang); foreach (var item in list) { - _gameChannelSDK[item.GameId] = item; + _memoryCache.Set($"{nameof(GameChannelSDK)}_{item.GameId.Id}", item, TimeSpan.FromMinutes(1)); } sdk = list.FirstOrDefault(x => x.GameId == gameId); } diff --git a/src/Starward/Frameworks/AppService.cs b/src/Starward/Frameworks/AppService.cs index ae25d7c20..271598876 100644 --- a/src/Starward/Frameworks/AppService.cs +++ b/src/Starward/Frameworks/AppService.cs @@ -60,6 +60,7 @@ private static void BuildServiceProvider() Log.Information($"Welcome to Starward v{AppSetting.AppVersion}\r\nSystem: {Environment.OSVersion}\r\nCommand Line: {Environment.CommandLine}"); var sc = new ServiceCollection(); + sc.AddMemoryCache(); sc.AddLogging(c => c.AddSerilog(Log.Logger)); sc.AddHttpClient().ConfigureHttpClientDefaults(config => { diff --git a/src/Starward/Starward.csproj b/src/Starward/Starward.csproj index 4cbe7f9e5..45b8239ce 100644 --- a/src/Starward/Starward.csproj +++ b/src/Starward/Starward.csproj @@ -34,6 +34,7 @@ +