perf(wpf): 当热更资源命中时, 不再二次加载资源 (#15907)

perf: 当热更资源命中时, 不再二次加载资源
This commit is contained in:
Status102
2026-03-08 20:49:17 +08:00
committed by GitHub
parent a8d5d95c20
commit e8ec73a67c
4 changed files with 53 additions and 44 deletions

View File

@@ -91,14 +91,12 @@ public class StageManager
}
}
var webStages = await LoadWebStages();
if (webStages is null)
var loaded = await LoadWebStages();
if (!loaded)
{
return;
}
MergePermanentAndActivityStages(webStages);
_ = Execute.OnUIThreadAsync(() => {
var growlInfo = new GrowlInfo {
IsCustom = true,
@@ -123,9 +121,9 @@ public class StageManager
return clientType;
}
private static JObject LoadLocalStages()
private static JObject? LoadLocalStages()
{
JObject activity = Instances.MaaApiService.LoadApiCache(StageApi);
JObject? activity = Instances.MaaApiService.LoadApiCache(StageApi);
return activity;
}
@@ -137,7 +135,7 @@ public class StageManager
const string AllFileDownloadCompleteFile = "allFileDownloadComplete.json";
JObject localLastUpdatedJson = Instances.MaaApiService.LoadApiCache(StageAndTasksUpdateTime);
JObject allFileDownloadCompleteJson = Instances.MaaApiService.LoadApiCache(AllFileDownloadCompleteFile);
JObject webLastUpdatedJson = await Instances.MaaApiService.RequestMaaApiWithCache(StageAndTasksUpdateTime).ConfigureAwait(false);
var (_, webLastUpdatedJson) = await Instances.MaaApiService.RequestMaaApiWithCache(StageAndTasksUpdateTime).ConfigureAwait(false);
if (localLastUpdatedJson?["timestamp"] == null || webLastUpdatedJson?["timestamp"] == null)
{
@@ -151,7 +149,7 @@ public class StageManager
}
*/
private static async Task<JObject?> LoadWebStages()
private async Task<bool> LoadWebStages()
{
var clientType = GetClientType();
@@ -160,9 +158,10 @@ public class StageManager
await Task.WhenAll(activityTask, tasksTask);
var activityJson = await activityTask;
var tasksJson = await tasksTask;
var (activityCached, activityJson) = await activityTask;
var (taskCached, tasksJson) = await tasksTask;
JObject? globalTasksJson = null;
bool globalTasksCached = true;
if (clientType != ClientType.Official && tasksJson != null)
{
var tasksPath = "resource/global/" + clientType + '/' + TasksApi;
@@ -170,23 +169,31 @@ public class StageManager
// Download the client specific resources only when the Official ones are successfully downloaded so that the client specific resource version is the actual version
// TODO: There may be an issue when the CN resource is loaded from cache (e.g. network down) while global resource is downloaded (e.g. network up again)
// var tasksJsonClient = fromWeb ? WebService.RequestMaaApiWithCache(tasksPath) : WebService.RequestMaaApiWithCache(tasksPath);
globalTasksJson = await Instances.MaaApiService.RequestMaaApiWithCache(tasksPath, false);
(globalTasksCached, globalTasksJson) = await Instances.MaaApiService.RequestMaaApiWithCache(tasksPath, false);
}
if (activityJson is null || tasksJson is null)
{
return null;
return false;
}
if (clientType != ClientType.Official && globalTasksJson is null)
{
return null;
return false;
}
await Task.Run(() => {
_ = Instances.AsstProxy.LoadResourceWhenIdleAsync();
});
return activityJson;
if (!taskCached || !globalTasksCached)
{
await Task.Run(() => {
_ = Instances.AsstProxy.LoadResourceWhenIdleAsync();
});
}
if (!activityCached)
{
MergePermanentAndActivityStages(activityJson);
}
return true;
}
private void MergePermanentAndActivityStages(JObject? activity)

View File

@@ -10,7 +10,7 @@
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY
// </copyright>
#nullable enable
using System.Threading.Tasks;
using Newtonsoft.Json.Linq;
@@ -18,7 +18,7 @@ namespace MaaWpfGui.Services.Web;
public interface IMaaApiService
{
Task<JObject> RequestMaaApiWithCache(string api, bool allowFallbackToCache = true);
Task<(bool Cached, JObject? Response)> RequestMaaApiWithCache(string api, bool allowFallbackToCache = true);
JObject LoadApiCache(string api);
JObject? LoadApiCache(string api);
}

View File

@@ -26,67 +26,69 @@ public class MaaApiService : IMaaApiService
{
private static readonly string CacheDir = PathsHelper.CacheDir;
public async Task<JObject?> RequestMaaApiWithCache(string api, bool allowFallbackToCache = true)
public async Task<(bool Cached, JObject? Response)> RequestMaaApiWithCache(string api, bool allowFallbackToCache = true)
{
return await RequestWithFallback(api, MaaUrls.MaaApi, MaaUrls.MaaApi2, allowFallbackToCache);
}
private async Task<JObject?> RequestWithFallback(string api, string primaryBaseUrl, string? fallbackBaseUrl = null, bool allowFallbackToCache = true)
private async Task<(bool Cached, JObject? Response)> RequestWithFallback(string api, string primaryBaseUrl, string? fallbackBaseUrl = null, bool allowFallbackToCache = true)
{
var json = await TryRequest(api, primaryBaseUrl, allowFallbackToCache);
if (json != null || string.IsNullOrEmpty(fallbackBaseUrl))
var result = await TryRequest(api, primaryBaseUrl, allowFallbackToCache);
if (result.Response != null || string.IsNullOrEmpty(fallbackBaseUrl))
{
return json;
return result;
}
return await TryRequest(api, fallbackBaseUrl, allowFallbackToCache);
}
private async Task<JObject?> TryRequest(string api, string baseUrl, bool allowFallbackToCache = true)
private async Task<(bool Cached, JObject? Response)> TryRequest(string api, string baseUrl, bool allowFallbackToCache = true)
{
var url = baseUrl + api;
var cache = Path.Combine(CacheDir, api);
var response = await ETagCache.FetchResponseWithEtag(url, !File.Exists(cache));
if (response == null)
var cachePath = Path.Combine(CacheDir, api);
var response = await ETagCache.FetchResponseWithEtag(url, !File.Exists(cachePath));
if (response?.StatusCode == System.Net.HttpStatusCode.NotModified)
{
return allowFallbackToCache ? LoadApiCache(api) : null;
var cache = LoadApiCache(api);
return (cache != null, cache);
}
if (response.StatusCode == System.Net.HttpStatusCode.NotModified)
if (response == null || response.StatusCode != System.Net.HttpStatusCode.OK)
{
return LoadApiCache(api);
}
if (!allowFallbackToCache)
{
return (false, null);
}
if (response.StatusCode != System.Net.HttpStatusCode.OK)
{
return allowFallbackToCache ? LoadApiCache(api) : null;
var cache = LoadApiCache(api);
return (cache != null, cache);
}
var body = await HttpResponseHelper.GetStringAsync(response);
if (string.IsNullOrEmpty(body))
{
return LoadApiCache(api);
var cache = LoadApiCache(api);
return (cache != null, cache);
}
try
{
var json = (JObject?)JsonConvert.DeserializeObject(body);
string? directoryPath = Path.GetDirectoryName(cache);
string? directoryPath = Path.GetDirectoryName(cachePath);
if (!Directory.Exists(directoryPath))
{
Directory.CreateDirectory(directoryPath!);
}
await File.WriteAllTextAsync(cache, body);
await File.WriteAllTextAsync(cachePath, body);
ETagCache.Set(response, url);
return json;
return (false, json);
}
catch
{
return null;
return (false, null);
}
}

View File

@@ -880,7 +880,7 @@ public class VersionUpdateDialogViewModel : Screen
private async Task<CheckUpdateRetT> CheckUpdateByMaaApi()
{
JObject json = await Instances.MaaApiService.RequestMaaApiWithCache(MaaUpdateApi);
var (_, json) = await Instances.MaaApiService.RequestMaaApiWithCache(MaaUpdateApi);
if (json is null)
{
@@ -908,7 +908,7 @@ public class VersionUpdateDialogViewModel : Screen
private async Task<CheckUpdateRetT> GetVersionDetailsByMaaApi(string versionType)
{
var json = await Instances.MaaApiService.RequestMaaApiWithCache($"version/{versionType}.json", false);
var (_, json) = await Instances.MaaApiService.RequestMaaApiWithCache($"version/{versionType}.json", false);
if (json is null)
{
return CheckUpdateRetT.NetworkError;