From b05090791a9d688ca51c7c057adc0ade54ade20a Mon Sep 17 00:00:00 2001 From: jfjia Date: Thu, 19 Mar 2026 16:21:48 +0800 Subject: [PATCH] perf: avoid blocking update checks in editor window --- .../Editor/Services/PackageUpdateService.cs | 41 +++++++- .../Editor/Windows/MCPForUnityEditorWindow.cs | 96 +++++++++++-------- 2 files changed, 96 insertions(+), 41 deletions(-) diff --git a/MCPForUnity/Editor/Services/PackageUpdateService.cs b/MCPForUnity/Editor/Services/PackageUpdateService.cs index 5f594e9ca..c6a905b2e 100644 --- a/MCPForUnity/Editor/Services/PackageUpdateService.cs +++ b/MCPForUnity/Editor/Services/PackageUpdateService.cs @@ -14,6 +14,7 @@ namespace MCPForUnity.Editor.Services /// public class PackageUpdateService : IPackageUpdateService { + private const int DefaultRequestTimeoutMs = 3000; private const string LastCheckDateKey = EditorPrefKeys.LastUpdateCheck; private const string CachedVersionKey = EditorPrefKeys.LatestKnownVersion; private const string LastBetaCheckDateKey = EditorPrefKeys.LastUpdateCheck + ".beta"; @@ -265,7 +266,7 @@ protected virtual string FetchLatestVersionFromGitHub(string branch) // - More reliable - doesn't require releases to be published // - Direct source of truth from the main branch - using (var client = new WebClient()) + using (var client = CreateWebClient()) { client.Headers.Add("User-Agent", "Unity-MCPForUnity-UpdateChecker"); string packageJsonUrl = string.Equals(branch, "beta", StringComparison.OrdinalIgnoreCase) @@ -304,7 +305,7 @@ protected virtual string FetchLatestVersionFromAssetStoreJson() { try { - using (var client = new WebClient()) + using (var client = CreateWebClient()) { client.Headers.Add("User-Agent", "Unity-MCPForUnity-AssetStoreUpdateChecker"); string jsonContent = client.DownloadString(AssetStoreVersionUrl); @@ -322,5 +323,41 @@ protected virtual string FetchLatestVersionFromAssetStoreJson() return null; } } + + protected virtual WebClient CreateWebClient() + { + return new TimeoutWebClient(GetRequestTimeoutMs()); + } + + protected virtual int GetRequestTimeoutMs() + { + return DefaultRequestTimeoutMs; + } + + private sealed class TimeoutWebClient : WebClient + { + private readonly int _timeoutMs; + + public TimeoutWebClient(int timeoutMs) + { + _timeoutMs = timeoutMs; + } + + protected override WebRequest GetWebRequest(Uri address) + { + var request = base.GetWebRequest(address); + if (request != null) + { + request.Timeout = _timeoutMs; + + if (request is HttpWebRequest httpRequest) + { + httpRequest.ReadWriteTimeout = _timeoutMs; + } + } + + return request; + } + } } } diff --git a/MCPForUnity/Editor/Windows/MCPForUnityEditorWindow.cs b/MCPForUnity/Editor/Windows/MCPForUnityEditorWindow.cs index bf41353a6..d6ab5277e 100644 --- a/MCPForUnity/Editor/Windows/MCPForUnityEditorWindow.cs +++ b/MCPForUnity/Editor/Windows/MCPForUnityEditorWindow.cs @@ -50,8 +50,9 @@ public class MCPForUnityEditorWindow : EditorWindow private bool toolsLoaded = false; private bool resourcesLoaded = false; private double lastRefreshTime = 0; - private const double RefreshDebounceSeconds = 0.5; - private bool updateCheckQueued = false; + private const double RefreshDebounceSeconds = 0.5; + private bool updateCheckQueued = false; + private bool updateCheckInFlight = false; private enum ActivePanel { @@ -350,53 +351,70 @@ private void UpdateVersionLabel() : $"MCP For Unity v{version}"; } - private void QueueUpdateCheck() - { - if (updateCheckQueued) - { - return; - } + private void QueueUpdateCheck() + { + if (updateCheckQueued || updateCheckInFlight) + { + return; + } updateCheckQueued = true; EditorApplication.delayCall += CheckForPackageUpdates; } - private void CheckForPackageUpdates() - { - updateCheckQueued = false; - - if (updateNotification == null || updateNotificationText == null) + private void CheckForPackageUpdates() + { + updateCheckQueued = false; + + if (updateNotification == null || updateNotificationText == null) { return; } string currentVersion = AssetPathUtility.GetPackageVersion(); - if (string.IsNullOrEmpty(currentVersion) || currentVersion == "unknown") - { - updateNotification.RemoveFromClassList("visible"); - return; - } - - try - { - var result = MCPServiceLocator.Updates.CheckForUpdate(currentVersion); - if (result.CheckSucceeded && result.UpdateAvailable && !string.IsNullOrEmpty(result.LatestVersion)) - { - updateNotificationText.text = $"Update available: v{result.LatestVersion} (current: v{currentVersion})"; - updateNotificationText.tooltip = $"Latest version: v{result.LatestVersion}\nCurrent version: v{currentVersion}"; - updateNotification.AddToClassList("visible"); - } - else - { - updateNotification.RemoveFromClassList("visible"); - } - } - catch (Exception ex) - { - McpLog.Info($"Package update check skipped: {ex.Message}"); - updateNotification.RemoveFromClassList("visible"); - } - } + if (string.IsNullOrEmpty(currentVersion) || currentVersion == "unknown") + { + updateNotification.RemoveFromClassList("visible"); + return; + } + + updateCheckInFlight = true; + Task.Run(() => + { + try + { + return MCPServiceLocator.Updates.CheckForUpdate(currentVersion); + } + catch (Exception ex) + { + McpLog.Info($"Package update check skipped: {ex.Message}"); + return null; + } + }).ContinueWith(t => + { + EditorApplication.delayCall += () => + { + updateCheckInFlight = false; + + if (this == null || updateNotification == null || updateNotificationText == null) + { + return; + } + + var result = t.Status == TaskStatus.RanToCompletion ? t.Result : null; + if (result != null && result.CheckSucceeded && result.UpdateAvailable && !string.IsNullOrEmpty(result.LatestVersion)) + { + updateNotificationText.text = $"Update available: v{result.LatestVersion} (current: v{currentVersion})"; + updateNotificationText.tooltip = $"Latest version: v{result.LatestVersion}\nCurrent version: v{currentVersion}"; + updateNotification.AddToClassList("visible"); + } + else + { + updateNotification.RemoveFromClassList("visible"); + } + }; + }, TaskScheduler.Default); + } private void EnsureToolsLoaded() {