feat: 对镜像进行延迟测试,并选择最优镜像

This commit is contained in:
ChingCdesu
2023-07-04 17:56:37 +08:00
parent 2cc28ceeeb
commit ecdabcb80e
3 changed files with 91 additions and 32 deletions

View File

@@ -13,6 +13,7 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Net;
using System.Net.Http;
@@ -72,6 +73,34 @@ namespace MaaWpfGui.Services.Web
BuildDownloaderHttpClient();
}
public async Task<double> HeadAsync(Uri uri, Dictionary<string, string> extraHeader = null)
{
try
{
var request = new HttpRequestMessage { RequestUri = uri, Method = HttpMethod.Head, };
if (extraHeader != null)
{
foreach (var kvp in extraHeader)
{
request.Headers.Add(kvp.Key, kvp.Value);
}
}
var stopwatch = Stopwatch.StartNew();
var response = await _client.SendAsync(request);
stopwatch.Stop();
response.Log();
return response.IsSuccessStatusCode is false ? -1.0 : stopwatch.Elapsed.TotalMilliseconds;
}
catch (Exception e)
{
_logger.Error(e, "Failed to send GET request to {Uri}", uri);
return -1.0;
}
}
public async Task<string> GetStringAsync(Uri uri, Dictionary<string, string> extraHeader = null)
{
var response = await GetAsync(uri, extraHeader);
@@ -96,15 +125,11 @@ namespace MaaWpfGui.Services.Web
return null;
}
public async Task<HttpResponseMessage> GetAsync(Uri uri, Dictionary<string, string> extraHeader = null)
public async Task<HttpResponseMessage> GetAsync(Uri uri, Dictionary<string, string> extraHeader = null, HttpCompletionOption httpCompletionOption = HttpCompletionOption.ResponseContentRead)
{
try
{
var request = new HttpRequestMessage
{
RequestUri = uri,
Method = HttpMethod.Get,
};
var request = new HttpRequestMessage { RequestUri = uri, Method = HttpMethod.Get, };
if (extraHeader != null)
{
@@ -114,7 +139,7 @@ namespace MaaWpfGui.Services.Web
}
}
var response = await _client.SendAsync(request);
var response = await _client.SendAsync(request, httpCompletionOption);
response.Log();
return response.IsSuccessStatusCode is false ? null : response;
@@ -145,7 +170,7 @@ namespace MaaWpfGui.Services.Web
}
}
public async Task<bool> DownloadFileAsync(Uri uri, string fileName, string contentType = null)
public async Task<bool> DownloadFileAsync(Uri uri, string fileName, string contentType = "application/octet-stream")
{
string fileDir = Directory.GetCurrentDirectory();
string fileNameWithTemp = fileName + ".temp";
@@ -153,7 +178,7 @@ namespace MaaWpfGui.Services.Web
string fullFilePathWithTemp = Path.Combine(fileDir, fileNameWithTemp);
_logger.Information("Start to download file from {Uri} and save to {TempPath}", uri, fullFilePathWithTemp);
var response = await GetAsync(uri, extraHeader: new Dictionary<string, string> { { "Accept", contentType } });
var response = await GetAsync(uri, extraHeader: new Dictionary<string, string> { { "Accept", contentType } }, httpCompletionOption: HttpCompletionOption.ResponseHeadersRead);
if (response is null)
{

View File

@@ -21,6 +21,14 @@ namespace MaaWpfGui.Services.Web
{
public interface IHttpService
{
/// <summary>
/// Test url available and return legacy
/// </summary>
/// <param name="uri">Target Uri</param>
/// <param name="extraHeader">Extra HTTP Request Headers</param>
/// <returns>Legacy in ms, -1 when response code not equal 200</returns>
Task<double> HeadAsync(Uri uri, Dictionary<string, string> extraHeader = null);
/// <summary>
/// Send HTTP GET request and get a string response
/// </summary>
@@ -43,7 +51,7 @@ namespace MaaWpfGui.Services.Web
/// <param name="uri">Target Uri</param>
/// <param name="extraHeader">Extra HTTP Request Headers</param>
/// <returns><see cref="HttpRequestMessage"/> object</returns>
Task<HttpResponseMessage> GetAsync(Uri uri, Dictionary<string, string> extraHeader = null);
Task<HttpResponseMessage> GetAsync(Uri uri, Dictionary<string, string> extraHeader = null, HttpCompletionOption httpCompletionOption = HttpCompletionOption.ResponseContentRead);
/// <summary>
/// Send HTTP POST request and a string reponse

View File

@@ -117,7 +117,7 @@ namespace MaaWpfGui.ViewModels.UI
}
public FlowDocument UpdateInfoDoc => Markdig.Wpf.Markdown.ToFlowDocument(UpdateInfo,
new MarkdownPipelineBuilder().UseSupportedExtensions().Build());
new MarkdownPipelineBuilder().UseSupportedExtensions().Build());
private string _updateUrl;
@@ -199,8 +199,8 @@ namespace MaaWpfGui.ViewModels.UI
{
using var toast = new ToastNotification(LocalizationHelper.GetString("NewVersionZipFileFoundTitle"));
toast.AppendContentText(LocalizationHelper.GetString("NewVersionZipFileFoundDescDecompressing"))
.AppendContentText(UpdateTag)
.ShowUpdateVersion(row: 2);
.AppendContentText(UpdateTag)
.ShowUpdateVersion(row: 2);
});
string curDir = Directory.GetCurrentDirectory();
@@ -224,8 +224,8 @@ namespace MaaWpfGui.ViewModels.UI
{
using var toast = new ToastNotification(LocalizationHelper.GetString("NewVersionZipFileBrokenTitle"));
toast.AppendContentText(LocalizationHelper.GetString("NewVersionZipFileBrokenDescFilename") + UpdatePackageName)
.AppendContentText(LocalizationHelper.GetString("NewVersionZipFileBrokenDescDeleted"))
.ShowUpdateVersion();
.AppendContentText(LocalizationHelper.GetString("NewVersionZipFileBrokenDescDeleted"))
.ShowUpdateVersion();
});
return false;
}
@@ -422,7 +422,7 @@ namespace MaaWpfGui.ViewModels.UI
return version;
}
else if (SemVersion.TryParse(version, SemVersionStyles.AllowLowerV, out var semVersion) &&
isNightlyVersion(semVersion))
isNightlyVersion(semVersion))
{
// v4.6.6-1.g{Hash}
// v4.6.7-beta.2.8.g{Hash}
@@ -465,9 +465,7 @@ namespace MaaWpfGui.ViewModels.UI
#pragma warning restore IDE0042
Execute.OnUIThread(() =>
{
using var toast = new ToastNotification((otaFound ?
LocalizationHelper.GetString("NewVersionFoundTitle") :
LocalizationHelper.GetString("NewVersionFoundButNoPackageTitle")) + " : " + UpdateTag);
using var toast = new ToastNotification((otaFound ? LocalizationHelper.GetString("NewVersionFoundTitle") : LocalizationHelper.GetString("NewVersionFoundButNoPackageTitle")) + " : " + UpdateTag);
if (goDownload)
{
OutputDownloadProgress(downloading: false, output: LocalizationHelper.GetString("NewVersionDownloadPreparing"));
@@ -526,17 +524,45 @@ namespace MaaWpfGui.ViewModels.UI
urls.Add(rawUrl);
}
foreach (var url in urls)
_logger.Information("Start test legacy download urls");
// run legacy test parallel
var tasks = urls.ConvertAll(url => Instances.HttpService.HeadAsync(new Uri(url)));
var legacies = await Task.WhenAll(tasks);
// select the fastest mirror
_logger.Information("Selecting the fastest mirror:");
var selected = 0;
for (int i = 0; i < legacies.Length; i++)
{
downloaded = await DownloadGithubAssets(url, _assetsObject);
if (downloaded)
if (legacies[i].Equals(-1.0))
{
OutputDownloadProgress(downloading: false, output: LocalizationHelper.GetString("NewVersionDownloadCompletedTitle"));
break;
_logger.Warning("\turl: {0} not available", urls[i]);
continue;
}
_logger.Information("\turl: {0}, legacy: {1:0.00}ms", urls[i], legacies[i]);
if (legacies[i] < legacies[selected])
{
selected = i;
}
}
if (!downloaded)
if (legacies[selected].Equals(-1.0))
{
_logger.Error("All mirrors are not available");
return CheckUpdateRetT.NetworkError;
}
_logger.Information("Selected mirror: {0}", urls[selected]);
downloaded = await DownloadGithubAssets(urls[selected], _assetsObject);
if (downloaded)
{
OutputDownloadProgress(downloading: false, output: LocalizationHelper.GetString("NewVersionDownloadCompletedTitle"));
}
else
{
OutputDownloadProgress(downloading: false, output: LocalizationHelper.GetString("NewVersionDownloadFailedTitle"));
Execute.OnUIThread(() =>
@@ -544,8 +570,8 @@ namespace MaaWpfGui.ViewModels.UI
using var toast = new ToastNotification(LocalizationHelper.GetString("NewVersionDownloadFailedTitle"));
toast.ButtonSystemUrl = UpdateUrl;
toast.AppendContentText(LocalizationHelper.GetString("NewVersionDownloadFailedDesc"))
.AddButtonLeft(openUrlToastButton.text, openUrlToastButton.action)
.Show();
.AddButtonLeft(openUrlToastButton.text, openUrlToastButton.action)
.Show();
});
return CheckUpdateRetT.NoNeedToUpdate;
}
@@ -728,8 +754,8 @@ namespace MaaWpfGui.ViewModels.UI
break;
}
}
}
while (string.IsNullOrEmpty(response) && retryTimes-- > 0);
} while (string.IsNullOrEmpty(response) && retryTimes-- > 0);
return response;
}
#pragma warning restore IDE0051 // 删除未使用的私有成员
@@ -746,9 +772,9 @@ namespace MaaWpfGui.ViewModels.UI
try
{
return await Instances.HttpService.DownloadFileAsync(
new Uri(url),
assetsObject["name"].ToString(),
assetsObject["content_type"]?.ToString())
new Uri(url),
assetsObject["name"].ToString(),
assetsObject["content_type"]?.ToString())
.ConfigureAwait(false);
}
catch (Exception)