From d7bce536f124d21d7e6967ac53672a028e587d81 Mon Sep 17 00:00:00 2001 From: OsakaRuma Date: Wed, 4 Sep 2024 00:17:05 +0800 Subject: [PATCH] optimized the speed of DNS resolution during streaming downloads. Signed-off-by: OsakaRuma --- .../Http/Extensions/UriIpAddressExtensions.cs | 167 ------------- .../Http/HttpPartialDnsResolve.cs | 115 +++++++++ .../Http/HttpPartialDownloadStreamUri.cs | 125 ++++++++++ .../SingleFileHttpPartialDownloadStream.cs | 222 +++++++++--------- .../VolumesFileHttpPartialDownloadStream.cs | 49 ++-- .../SingleFileZipFileDownloadFactory.cs | 18 +- .../VolumesFileZipFileDownloadFactory.cs | 21 +- 7 files changed, 414 insertions(+), 303 deletions(-) delete mode 100644 src/Starward.Core.ZipStreamDownload/Http/Extensions/UriIpAddressExtensions.cs create mode 100644 src/Starward.Core.ZipStreamDownload/Http/HttpPartialDnsResolve.cs create mode 100644 src/Starward.Core.ZipStreamDownload/Http/HttpPartialDownloadStreamUri.cs diff --git a/src/Starward.Core.ZipStreamDownload/Http/Extensions/UriIpAddressExtensions.cs b/src/Starward.Core.ZipStreamDownload/Http/Extensions/UriIpAddressExtensions.cs deleted file mode 100644 index 7eda1d667..000000000 --- a/src/Starward.Core.ZipStreamDownload/Http/Extensions/UriIpAddressExtensions.cs +++ /dev/null @@ -1,167 +0,0 @@ -using System.Net; -using System.Net.Sockets; - -namespace Starward.Core.ZipStreamDownload.Http.Extensions; - -public static class UriIpAddressExtensions -{ - /// - /// 对一个迭代器对象进行随机排序 - /// - /// 一个迭代器的实例 - /// 迭代器的类型 - /// 一个已经打乱顺序的列表。 - private static List ConfuseEnumerable(IEnumerable enumerable) - { - var random = new Random(); - return enumerable.OrderBy(_ => random.Next()).ToList(); - } - - /// - /// 获取使用IP地址作为主机名的的实例。(异步) - /// - /// 的实例 - /// 取消令牌 - /// 一个任务,可以获取的实例。 - public static async Task GetIpAddressUriAsync(this Uri uri, CancellationToken cancellationToken = default) - { - var ipAddress = await GetIpAddressAsync(uri, cancellationToken).ConfigureAwait(false); - var uriBuilder = new UriBuilder(uri) - { - Host = ipAddress.ToString() - }; - return uriBuilder.Uri; - } - - /// - /// 取使用IP地址作为主机名的的实例。 - /// - /// 的实例 - /// 的实例。 - public static Uri GetIpAddressUri(this Uri uri) - { - var ipAddress = GetIpAddress(uri); - var uriBuilder = new UriBuilder(uri) - { - Host = ipAddress.ToString() - }; - return uriBuilder.Uri; - } - - /// - /// 返回Uri主机名解析后的IP地址。(异步) - /// - /// 的实例 - /// 取消令牌 - /// 一个任务,可获取一个的实例。 - /// 如果为域名,解析后测试连接,并随机返回一个可用的IP地址,如果为IP地址则直接返回。 - public static async Task GetIpAddressAsync(this Uri uri, CancellationToken cancellationToken = default) - { - switch (uri.HostNameType) - { - case UriHostNameType.IPv4 or UriHostNameType.IPv6: - return IPAddress.Parse(uri.Host); - case UriHostNameType.Dns: - { - var addresses = new List(); - try - { - var addressesV6 = ConfuseEnumerable( - await Dns.GetHostAddressesAsync(uri.Host, AddressFamily.InterNetworkV6, cancellationToken) - .ConfigureAwait(false)); - addresses.AddRange(addressesV6); - } - catch (SocketException e) when (e.SocketErrorCode == SocketError.NoData) - { - } - try - { - var addressesV4 = ConfuseEnumerable( - await Dns.GetHostAddressesAsync(uri.Host, AddressFamily.InterNetwork, cancellationToken) - .ConfigureAwait(false)); - addresses.AddRange(addressesV4); - } - catch (SocketException e) when (e.SocketErrorCode == SocketError.NoData) - { - } - IPAddress? result = null; - Exception? lastException = null; - foreach (var address in addresses) - { - try - { - using var client = new TcpClient(); - var endPoint = new IPEndPoint(address, uri.Port); - await client.ConnectAsync(endPoint, cancellationToken).ConfigureAwait(false); - result = address; - break; - } - catch (Exception ex) when (ex is not OperationCanceledException) - { - lastException = ex; - } - } - if (result == null) throw lastException ?? new SocketException((int)SocketError.HostNotFound); - return result; - } - default: - throw new ArgumentException(); - } - } - - /// - /// 返回Uri主机名解析后的IP地址。 - /// - /// 的实例 - /// 一个的实例。 - /// 如果为域名,解析后测试连接,并随机返回一个可用的IP地址,如果为IP地址则直接返回。 - public static IPAddress GetIpAddress(this Uri uri) - { - switch (uri.HostNameType) - { - case UriHostNameType.IPv4 or UriHostNameType.IPv6: - return IPAddress.Parse(uri.Host); - case UriHostNameType.Dns: - { - var addresses = new List(); - try - { - var addressesV6 = ConfuseEnumerable(Dns.GetHostAddresses(uri.Host, AddressFamily.InterNetworkV6)); - addresses.AddRange(addressesV6); - } - catch (SocketException e) when (e.SocketErrorCode == SocketError.NoData) - { - } - try - { - var addressesV4 = ConfuseEnumerable(Dns.GetHostAddresses(uri.Host, AddressFamily.InterNetwork)); - addresses.AddRange(addressesV4); - } - catch (SocketException e) when (e.SocketErrorCode == SocketError.NoData) - { - } - IPAddress? result = null; - Exception? lastException = null; - foreach (var address in addresses) - { - try - { - using var client = new TcpClient(); - var endPoint = new IPEndPoint(address, uri.Port); - client.Connect(endPoint); - result = address; - break; - } - catch (Exception ex) when (ex is not OperationCanceledException) - { - lastException = ex; - } - } - if (result == null) throw lastException ?? new SocketException((int)SocketError.HostNotFound); - return result; - } - default: - throw new ArgumentException(); - } - } -} \ No newline at end of file diff --git a/src/Starward.Core.ZipStreamDownload/Http/HttpPartialDnsResolve.cs b/src/Starward.Core.ZipStreamDownload/Http/HttpPartialDnsResolve.cs new file mode 100644 index 000000000..c8fd884b6 --- /dev/null +++ b/src/Starward.Core.ZipStreamDownload/Http/HttpPartialDnsResolve.cs @@ -0,0 +1,115 @@ +using System.Collections.Concurrent; +using System.Net; +using System.Net.Sockets; + +namespace Starward.Core.ZipStreamDownload.Http; + +/// +/// DNS解析、IP地址测试和缓存 +/// +/// 此类的作用是保证多个实例共享一个缓存池。 +/// +/// +public class HttpPartialDnsResolve +{ + /// + /// DNS缓存(主机名与IP地址列表的线程安全字典) + /// + private readonly ConcurrentDictionary>> _hostIpAddresses = new(); + + /// + /// 获取可用的IP地址列表(TCP连接测试,异步) + /// + /// 主机名 + /// 用于测试的TCP端口号 + /// 一个任务,可用获取可用的IP地址列表 + public Task GetIpAddressesAsync(string host, int port) + { + ArgumentOutOfRangeException.ThrowIfNegativeOrZero(port); + ArgumentOutOfRangeException.ThrowIfGreaterThan(port, 0xffff); + var iPAddress = + _hostIpAddresses.GetOrAdd(host, h => new Lazy>(() => GetIpAddressAsyncCore(h, port))); + return iPAddress.Value; + } + + /// + /// 获取可用的IP地址列表(TCP连接测试) + /// + /// 主机名 + /// 用于测试的TCP端口号 + /// 可用的IP地址列表 + public IPAddress[] GetIpAddresses(string host, int port) + { + ArgumentOutOfRangeException.ThrowIfNegativeOrZero(port); + ArgumentOutOfRangeException.ThrowIfGreaterThan(port, 0xffff); + var iPAddress = + _hostIpAddresses.GetOrAdd(host, h => new Lazy>(() => GetIpAddressAsyncCore(h, port))); + return iPAddress.Value.GetAwaiter().GetResult(); + } + + /// + /// 获取可用的IP地址列表(内部,无缓存) + /// + /// 主机名 + /// >用于测试的TCP端口号 + /// 可用的IP地址列表 + private static async Task GetIpAddressAsyncCore(string host, int port) + { + Exception? lastException = null; + List? addresses = null; + try + { + addresses = ConfuseEnumerable( + await Dns.GetHostAddressesAsync(host, AddressFamily.InterNetworkV6) + .ConfigureAwait(false)); + } + catch (SocketException e) when (e.SocketErrorCode == SocketError.NoData) + { + } + if (addresses != null) return (await TestAddressesAsync(addresses).ConfigureAwait(false)).ToArray(); + try + { + addresses = ConfuseEnumerable( + await Dns.GetHostAddressesAsync(host, AddressFamily.InterNetwork) + .ConfigureAwait(false)); + } + catch (SocketException e) when (e.SocketErrorCode == SocketError.NoData) + { + } + if (addresses != null) return (await TestAddressesAsync(addresses).ConfigureAwait(false)).ToArray(); + throw lastException ?? new SocketException((int)SocketError.HostNotFound); + + async Task> TestAddressesAsync(List testAddresses) + { + var result = new List(); + foreach (var address in testAddresses) + { + try + { + using var client = new TcpClient(); + var endPoint = new IPEndPoint(address, port); + await client.ConnectAsync(endPoint).ConfigureAwait(false); + result.Add(address); + } + catch (Exception ex) when (ex is not OperationCanceledException) + { + lastException = ex; + } + } + if (result.Count == 0) throw lastException ?? new SocketException((int)SocketError.HostNotFound); + return result; + } + } + + /// + /// 对一个迭代器对象进行随机排序 + /// + /// 一个迭代器的实例 + /// 迭代器的类型 + /// 一个已经打乱顺序的列表。 + private static List ConfuseEnumerable(IEnumerable enumerable) + { + var random = new Random(); + return enumerable.OrderBy(_ => random.Next()).ToList(); + } +} \ No newline at end of file diff --git a/src/Starward.Core.ZipStreamDownload/Http/HttpPartialDownloadStreamUri.cs b/src/Starward.Core.ZipStreamDownload/Http/HttpPartialDownloadStreamUri.cs new file mode 100644 index 000000000..da5b1facc --- /dev/null +++ b/src/Starward.Core.ZipStreamDownload/Http/HttpPartialDownloadStreamUri.cs @@ -0,0 +1,125 @@ +using System.Net; + +namespace Starward.Core.ZipStreamDownload.Http; + +/// +/// HTTP部分下载流使用的自定义URI对象。 +/// +/// +/// 此类的作用是保证在第一次获取IP地址前将URL中的域名进行解析,并测试可用地址。 +/// 确保在DNS返回多个地址的整个部分下载过程中,只使用相同IP地址进行下载。 +/// 多进程下载时将请求轮询调度负载分担到DNS解析到的多个IP上。 +/// +/// 一个的实例,表示一个URI地址。 +/// 一个的实例,用于DNS解析、IP地址测试和缓存。 +public class HttpPartialDownloadStreamUri(Uri uri, HttpPartialDnsResolve httpPartialDnsResolve) +{ + /// + /// 获取对象初始化时传入的 + /// + public Uri Uri { get; } = uri; + + /// + /// 获取对象初始化时传入的中的主机名 + /// + public string Host { get; } = uri.Host; + + /// + /// 获取的实例,用于DNS解析、IP地址测试和缓存 + /// + public HttpPartialDnsResolve HttpPartialDnsResolve { get; } = httpPartialDnsResolve; + + /// + /// 已经获取IP地址的总次数 + /// + private ulong _ipAddressesRequestCount; + + /// + /// 可用的IP地址(异步懒初始化) + /// + private readonly Lazy> _ipAddresses = new (async () => + { + return uri.HostNameType switch + { + UriHostNameType.IPv4 or UriHostNameType.IPv6 => [IPAddress.Parse(uri.Host)], + UriHostNameType.Dns => await httpPartialDnsResolve.GetIpAddressesAsync(uri.Host, uri.Port) + .ConfigureAwait(false), + _ => throw new ArgumentException() + }; + }); + + /// + /// 获取一个IP地址作为Host的(异步) + /// + /// 一个任务,可获取一个IP地址作为Host的 + public async Task GetIpAddressUriAsync() + { + var ipAddresses = await _ipAddresses.Value; + var ipAddressesRequestCount = Interlocked.Increment(ref _ipAddressesRequestCount); + var ipAddress = ipAddresses[(int)(ipAddressesRequestCount % (ulong)ipAddresses.Length)]; + return GetIpAddressUri(Uri, ipAddress); + } + + /// + /// 获取一个IP地址作为Host的 + /// + /// 一个IP地址作为Host的 + public Uri GetIpAddressUri() + { + var ipAddresses = _ipAddresses.Value.GetAwaiter().GetResult(); + var ipAddressesRequestCount = Interlocked.Increment(ref _ipAddressesRequestCount); + var ipAddress = ipAddresses[(int)(ipAddressesRequestCount % (ulong)ipAddresses.Length)]; + return GetIpAddressUri(Uri, ipAddress); + } + + /// + /// 获取指定实例的规范字符串表示形式。 + /// + /// Uri实例的未转义规范表示。除了#、?和%。 + public override string ToString() => Uri.ToString(); + + public static implicit operator Uri(HttpPartialDownloadStreamUri uri) => uri.Uri; + + /// + /// HTTP部分下载流使用的自定义URI对象。 + /// + /// + /// 此类的作用是保证在第一次获取IP地址前将URL中的域名进行解析,并测试可用地址。 + /// 确保在DNS返回多个地址的整个部分下载过程中,只使用相同IP地址进行下载。 + /// 多进程下载时将请求轮询调度负载分担到DNS解析到的多个IP上。 + /// + /// 一个字符串,表示一个URI地址。 + /// 一个的实例,用于DNS解析、IP地址测试和缓存。 + public HttpPartialDownloadStreamUri(string uri, HttpPartialDnsResolve httpPartialDnsResolve) : + this(new Uri(uri), httpPartialDnsResolve) + { + + } + + /// + /// 对一个迭代器对象进行随机排序 + /// + /// 一个迭代器的实例 + /// 迭代器的类型 + /// 一个已经打乱顺序的列表。 + private static List ConfuseEnumerable(IEnumerable enumerable) + { + var random = new Random(); + return enumerable.OrderBy(_ => random.Next()).ToList(); + } + + /// + /// 获取使用IP地址作为主机名的的实例。 + /// + /// 的实例 + /// 的实例 + /// 的实例。 + private static Uri GetIpAddressUri(Uri uri, IPAddress ipAddress) + { + var uriBuilder = new UriBuilder(uri) + { + Host = ipAddress.ToString() + }; + return uriBuilder.Uri; + } +} \ No newline at end of file diff --git a/src/Starward.Core.ZipStreamDownload/Http/SingleFileHttpPartialDownloadStream.cs b/src/Starward.Core.ZipStreamDownload/Http/SingleFileHttpPartialDownloadStream.cs index 10f2ddf69..fc69d09c3 100644 --- a/src/Starward.Core.ZipStreamDownload/Http/SingleFileHttpPartialDownloadStream.cs +++ b/src/Starward.Core.ZipStreamDownload/Http/SingleFileHttpPartialDownloadStream.cs @@ -66,9 +66,8 @@ public HttpRequestMessage? HttpRequestMessage private readonly Uri _ipAddressUri; private SingleFileHttpPartialDownloadStream(HttpClient httpClient, - HttpResponseMessage responseMessage, Stream responseReadStream, - Uri fileUri, Uri ipAddressUri, AutoRetryOptions autoRetryOptions, string? mediaType, long? fileLength, - DateTimeOffset? fileLastModifiedTime) + HttpResponseMessage responseMessage, Stream responseReadStream, Uri fileUri, Uri ipAddressUri, + AutoRetryOptions autoRetryOptions, string? mediaType, long? fileLength, DateTimeOffset? fileLastModifiedTime) { ValidatePartialHttpResponseMessage(responseMessage, mediaType, fileLength, fileLastModifiedTime); _httpClient = httpClient; @@ -87,9 +86,9 @@ private SingleFileHttpPartialDownloadStream(HttpClient httpClient, if (contentHeaders.LastModified.HasValue) FileLastModifiedTime = contentHeaders.LastModified.Value; } - public static SingleFileHttpPartialDownloadStream GetInstance(HttpClient httpClient, Uri fileUri, - long? startBytes, long? endBytes, AutoRetryOptions autoRetryOptions, string? mediaType, long? fileLength, - DateTimeOffset? fileLastModifiedTime) + public static SingleFileHttpPartialDownloadStream GetInstance(HttpClient httpClient, + HttpPartialDownloadStreamUri fileUri, long? startBytes, long? endBytes, AutoRetryOptions autoRetryOptions, + string? mediaType, long? fileLength, DateTimeOffset? fileLastModifiedTime) { ValidateStartBytesAndEndBytes(startBytes, endBytes, fileLength); var ipAddressUri = fileUri.GetIpAddressUri(); @@ -101,8 +100,8 @@ public static SingleFileHttpPartialDownloadStream GetInstance(HttpClient httpCli { try { - return Core(httpClient, fileUri, startBytes, endBytes + (startBytes.HasValue ? -1 : 0), - autoRetryOptions, mediaType, fileLength, fileLastModifiedTime, ipAddressUri); + return Core(httpClient, fileUri, ipAddressUri, startBytes, endBytes + (startBytes.HasValue ? -1 : 0), + autoRetryOptions, mediaType, fileLength, fileLastModifiedTime); } catch (Exception e) when(e is HttpRequestException or SocketException or HttpIOException or IOException) { @@ -112,9 +111,9 @@ public static SingleFileHttpPartialDownloadStream GetInstance(HttpClient httpCli } } - static SingleFileHttpPartialDownloadStream Core(HttpClient httpClient, Uri fileUri, long? startBytes, - long? endBytes, AutoRetryOptions autoRetryOptions, string? mediaType, long? fileLength, - DateTimeOffset? fileLastModifiedTime, Uri ipAddressUri) + static SingleFileHttpPartialDownloadStream Core(HttpClient httpClient, Uri fileUri, Uri ipAddressUri, + long? startBytes, long? endBytes, AutoRetryOptions autoRetryOptions, string? mediaType, long? fileLength, + DateTimeOffset? fileLastModifiedTime) { HttpResponseMessage responseMessage; if (httpClient.DefaultRequestVersion >= System.Net.HttpVersion.Version20 || @@ -138,12 +137,12 @@ static SingleFileHttpPartialDownloadStream Core(HttpClient httpClient, Uri fileU } } - public static async Task GetInstanceAsync(HttpClient httpClient, Uri fileUri, - long? startBytes, long? endBytes, AutoRetryOptions autoRetryOptions, string? mediaType, long? fileLength, - DateTimeOffset? fileLastModifiedTime, CancellationToken cancellationToken = default) + public static async Task GetInstanceAsync(HttpClient httpClient, + HttpPartialDownloadStreamUri fileUri, long? startBytes, long? endBytes, AutoRetryOptions autoRetryOptions, + string? mediaType, long? fileLength, DateTimeOffset? fileLastModifiedTime, CancellationToken cancellationToken = default) { ValidateStartBytesAndEndBytes(startBytes, endBytes, fileLength); - var ipAddressUri = await fileUri.GetIpAddressUriAsync(cancellationToken).ConfigureAwait(false); + var ipAddressUri = await fileUri.GetIpAddressUriAsync().ConfigureAwait(false); var retryTimes = 0; var autoRetryTimesOnNetworkError = autoRetryOptions.RetryTimesOnNetworkError; @@ -152,9 +151,9 @@ public static async Task GetInstanceAsync(H { try { - return await CoreAsync(httpClient, fileUri, startBytes, endBytes + (startBytes.HasValue ? -1 : 0), - autoRetryOptions, mediaType, fileLength, fileLastModifiedTime, ipAddressUri, cancellationToken) - .ConfigureAwait(false); + return await CoreAsync(httpClient, fileUri, ipAddressUri, startBytes, + endBytes + (startBytes.HasValue ? -1 : 0), autoRetryOptions, mediaType, fileLength, + fileLastModifiedTime, cancellationToken).ConfigureAwait(false); } catch (Exception e) when(e is HttpRequestException or SocketException or HttpIOException or IOException) { @@ -165,8 +164,8 @@ public static async Task GetInstanceAsync(H } static async Task CoreAsync(HttpClient httpClient, Uri fileUri, - long? startBytes, long? endBytes, AutoRetryOptions autoRetryOptions, string? mediaType, long? fileLength, - DateTimeOffset? fileLastModifiedTime, Uri ipAddressUri, CancellationToken cancellationToken = default) + Uri ipAddressUri, long? startBytes, long? endBytes, AutoRetryOptions autoRetryOptions, string? mediaType, + long? fileLength, DateTimeOffset? fileLastModifiedTime, CancellationToken cancellationToken = default) { var responseMessage = await httpClient.GetPartialAsync(ipAddressUri, fileUri.Host, startBytes, endBytes, mediaType, cancellationToken).ConfigureAwait(false); @@ -716,199 +715,212 @@ contentRange.To is null or < 0 || contentRange.To < contentRange.From || #region 重载方法 - public static SingleFileHttpPartialDownloadStream GetInstance(HttpClient httpClient, Uri fileUri, - AutoRetryOptions autoRetryOptions) + public static SingleFileHttpPartialDownloadStream GetInstance(HttpClient httpClient, + HttpPartialDownloadStreamUri fileUri, AutoRetryOptions autoRetryOptions) => GetInstance(httpClient, fileUri, null, null, autoRetryOptions, null, null, null); - public static SingleFileHttpPartialDownloadStream GetInstance(HttpClient httpClient, Uri fileUri) + public static SingleFileHttpPartialDownloadStream GetInstance(HttpClient httpClient, + HttpPartialDownloadStreamUri fileUri) => GetInstance(httpClient, fileUri, null, null, new AutoRetryOptions(), null, null, null); - public static SingleFileHttpPartialDownloadStream GetInstance(HttpClient httpClient, Uri fileUri, - long? startBytes, long? endBytes, AutoRetryOptions autoRetryOptions) + public static SingleFileHttpPartialDownloadStream GetInstance(HttpClient httpClient, + HttpPartialDownloadStreamUri fileUri, long? startBytes, long? endBytes, AutoRetryOptions autoRetryOptions) => GetInstance(httpClient, fileUri, startBytes, endBytes, autoRetryOptions, null, null, null); - public static SingleFileHttpPartialDownloadStream GetInstance(HttpClient httpClient, Uri fileUri, - long? startBytes, long? endBytes) + public static SingleFileHttpPartialDownloadStream GetInstance(HttpClient httpClient, + HttpPartialDownloadStreamUri fileUri, long? startBytes, long? endBytes) => GetInstance(httpClient, fileUri, startBytes, endBytes, new AutoRetryOptions(), null, null, null); - public static SingleFileHttpPartialDownloadStream GetInstance(HttpClient httpClient, Uri fileUri, - long? startBytes, AutoRetryOptions autoRetryOptions) + public static SingleFileHttpPartialDownloadStream GetInstance(HttpClient httpClient, + HttpPartialDownloadStreamUri fileUri, long? startBytes, AutoRetryOptions autoRetryOptions) => GetInstance(httpClient, fileUri, startBytes, null, autoRetryOptions, null, null, null); - public static SingleFileHttpPartialDownloadStream GetInstance(HttpClient httpClient, Uri fileUri, - long? startBytes) + public static SingleFileHttpPartialDownloadStream GetInstance(HttpClient httpClient, + HttpPartialDownloadStreamUri fileUri, long? startBytes) => GetInstance(httpClient, fileUri, startBytes, null, new AutoRetryOptions(), null, null, null); - public static SingleFileHttpPartialDownloadStream GetInstance(HttpClient httpClient, Uri fileUri, - long? startBytes, long? endBytes, AutoRetryOptions autoRetryOptions, string? mediaType) + public static SingleFileHttpPartialDownloadStream GetInstance(HttpClient httpClient, + HttpPartialDownloadStreamUri fileUri, long? startBytes, long? endBytes, AutoRetryOptions autoRetryOptions, + string? mediaType) => GetInstance(httpClient, fileUri, startBytes, endBytes, autoRetryOptions, mediaType, null, null); - public static SingleFileHttpPartialDownloadStream GetInstance(HttpClient httpClient, Uri fileUri, - long? startBytes, long? endBytes, string? mediaType) + public static SingleFileHttpPartialDownloadStream GetInstance(HttpClient httpClient, + HttpPartialDownloadStreamUri fileUri, long? startBytes, long? endBytes, string? mediaType) => GetInstance(httpClient, fileUri, startBytes, endBytes, new AutoRetryOptions(), mediaType, null, null); - public static SingleFileHttpPartialDownloadStream GetInstance(HttpClient httpClient, Uri fileUri, - long? startBytes, AutoRetryOptions autoRetryOptions, string? mediaType) + public static SingleFileHttpPartialDownloadStream GetInstance(HttpClient httpClient, + HttpPartialDownloadStreamUri fileUri, long? startBytes, AutoRetryOptions autoRetryOptions, string? mediaType) => GetInstance(httpClient, fileUri, startBytes, null, autoRetryOptions, mediaType, null, null); - public static SingleFileHttpPartialDownloadStream GetInstance(HttpClient httpClient, Uri fileUri, - long? startBytes, string? mediaType) + public static SingleFileHttpPartialDownloadStream GetInstance(HttpClient httpClient, + HttpPartialDownloadStreamUri fileUri, long? startBytes, string? mediaType) => GetInstance(httpClient, fileUri, startBytes, null, new AutoRetryOptions(), mediaType, null, null); - public static SingleFileHttpPartialDownloadStream GetInstance(HttpClient httpClient, Uri fileUri, - AutoRetryOptions autoRetryOptions, string? mediaType) + public static SingleFileHttpPartialDownloadStream GetInstance(HttpClient httpClient, + HttpPartialDownloadStreamUri fileUri, AutoRetryOptions autoRetryOptions, string? mediaType) => GetInstance(httpClient, fileUri, null, null, autoRetryOptions, mediaType, null, null); - public static SingleFileHttpPartialDownloadStream GetInstance(HttpClient httpClient, Uri fileUri, string? mediaType) + public static SingleFileHttpPartialDownloadStream GetInstance(HttpClient httpClient, + HttpPartialDownloadStreamUri fileUri, string? mediaType) => GetInstance(httpClient, fileUri, null, null, new AutoRetryOptions(), mediaType, null, null); - public static SingleFileHttpPartialDownloadStream GetInstance(HttpClient httpClient, Uri fileUri, - string? mediaType, long? fileLength, AutoRetryOptions autoRetryOptions, DateTimeOffset? fileLastModifiedTime) + public static SingleFileHttpPartialDownloadStream GetInstance(HttpClient httpClient, + HttpPartialDownloadStreamUri fileUri, string? mediaType, long? fileLength, AutoRetryOptions autoRetryOptions, + DateTimeOffset? fileLastModifiedTime) => GetInstance(httpClient, fileUri, null, null, autoRetryOptions, mediaType, fileLength, fileLastModifiedTime); - public static SingleFileHttpPartialDownloadStream GetInstance(HttpClient httpClient, Uri fileUri, - string? mediaType, long? fileLength, DateTimeOffset? fileLastModifiedTime) + public static SingleFileHttpPartialDownloadStream GetInstance(HttpClient httpClient, + HttpPartialDownloadStreamUri fileUri, string? mediaType, long? fileLength, DateTimeOffset? fileLastModifiedTime) => GetInstance(httpClient, fileUri, null, null, new AutoRetryOptions(), mediaType, fileLength, fileLastModifiedTime); - public static SingleFileHttpPartialDownloadStream GetInstance(HttpClient httpClient, Uri fileUri, - long? startBytes, long? endBytes, AutoRetryOptions autoRetryOptions, long? fileLength, - DateTimeOffset? fileLastModifiedTime) + public static SingleFileHttpPartialDownloadStream GetInstance(HttpClient httpClient, + HttpPartialDownloadStreamUri fileUri, long? startBytes, long? endBytes, AutoRetryOptions autoRetryOptions, + long? fileLength, DateTimeOffset? fileLastModifiedTime) => GetInstance(httpClient, fileUri, startBytes, endBytes, autoRetryOptions, null, fileLength, fileLastModifiedTime); - public static SingleFileHttpPartialDownloadStream GetInstance(HttpClient httpClient, Uri fileUri, - long? startBytes, long? endBytes, long? fileLength, DateTimeOffset? fileLastModifiedTime) + public static SingleFileHttpPartialDownloadStream GetInstance(HttpClient httpClient, + HttpPartialDownloadStreamUri fileUri, long? startBytes, long? endBytes, long? fileLength, + DateTimeOffset? fileLastModifiedTime) => GetInstance(httpClient, fileUri, startBytes, endBytes, new AutoRetryOptions(), null, fileLength, fileLastModifiedTime); - public static SingleFileHttpPartialDownloadStream GetInstance(HttpClient httpClient, Uri fileUri, - long? startBytes, AutoRetryOptions autoRetryOptions, long? fileLength, DateTimeOffset? fileLastModifiedTime) + public static SingleFileHttpPartialDownloadStream GetInstance(HttpClient httpClient, + HttpPartialDownloadStreamUri fileUri, long? startBytes, AutoRetryOptions autoRetryOptions, long? fileLength, + DateTimeOffset? fileLastModifiedTime) => GetInstance(httpClient, fileUri, startBytes, null, autoRetryOptions, null, fileLength, fileLastModifiedTime); - public static SingleFileHttpPartialDownloadStream GetInstance(HttpClient httpClient, Uri fileUri, - long? fileLength, DateTimeOffset? fileLastModifiedTime) + public static SingleFileHttpPartialDownloadStream GetInstance(HttpClient httpClient, + HttpPartialDownloadStreamUri fileUri, long? fileLength, DateTimeOffset? fileLastModifiedTime) => GetInstance(httpClient, fileUri, null, null, new AutoRetryOptions(), null, fileLength, fileLastModifiedTime); - public static SingleFileHttpPartialDownloadStream GetInstance(HttpClient httpClient, Uri fileUri, long? startBytes, - long? endBytes, string? mediaType, long? fileLength, + public static SingleFileHttpPartialDownloadStream GetInstance(HttpClient httpClient, + HttpPartialDownloadStreamUri fileUri, long? startBytes, long? endBytes, string? mediaType, long? fileLength, DateTimeOffset? fileLastModifiedTime) => GetInstance(httpClient, fileUri, startBytes, endBytes, new AutoRetryOptions(), mediaType, fileLength, fileLastModifiedTime); - public static Task GetInstanceAsync(HttpClient httpClient, Uri fileUri, - AutoRetryOptions autoRetryOptions, CancellationToken cancellationToken = default) + public static Task GetInstanceAsync(HttpClient httpClient, + HttpPartialDownloadStreamUri fileUri, AutoRetryOptions autoRetryOptions, + CancellationToken cancellationToken = default) => GetInstanceAsync(httpClient, fileUri, null, null, autoRetryOptions, null, null, null, cancellationToken); - public static Task GetInstanceAsync(HttpClient httpClient, Uri fileUri, - CancellationToken cancellationToken = default) + public static Task GetInstanceAsync(HttpClient httpClient, + HttpPartialDownloadStreamUri fileUri, CancellationToken cancellationToken = default) => GetInstanceAsync(httpClient, fileUri, null, null, new AutoRetryOptions(), null, null, null, cancellationToken); - public static Task GetInstanceAsync(HttpClient httpClient, Uri fileUri, - long? startBytes, long? endBytes, AutoRetryOptions autoRetryOptions, + public static Task GetInstanceAsync(HttpClient httpClient, + HttpPartialDownloadStreamUri fileUri, long? startBytes, long? endBytes, AutoRetryOptions autoRetryOptions, CancellationToken cancellationToken = default) => GetInstanceAsync(httpClient, fileUri, startBytes, endBytes, autoRetryOptions, null, null, null, cancellationToken); - public static Task GetInstanceAsync(HttpClient httpClient, Uri fileUri, - long? startBytes, long? endBytes, CancellationToken cancellationToken = default) + public static Task GetInstanceAsync(HttpClient httpClient, + HttpPartialDownloadStreamUri fileUri, long? startBytes, long? endBytes, + CancellationToken cancellationToken = default) => GetInstanceAsync(httpClient, fileUri, startBytes, endBytes, new AutoRetryOptions(), null, null, null, cancellationToken); - public static Task GetInstanceAsync(HttpClient httpClient, Uri fileUri, - long? startBytes, AutoRetryOptions autoRetryOptions, CancellationToken cancellationToken = default) + public static Task GetInstanceAsync(HttpClient httpClient, + HttpPartialDownloadStreamUri fileUri, long? startBytes, AutoRetryOptions autoRetryOptions, + CancellationToken cancellationToken = default) => GetInstanceAsync(httpClient, fileUri, startBytes, null, autoRetryOptions, null, null, null, cancellationToken); - public static Task GetInstanceAsync(HttpClient httpClient, Uri fileUri, - long? startBytes, CancellationToken cancellationToken = default) + public static Task GetInstanceAsync(HttpClient httpClient, + HttpPartialDownloadStreamUri fileUri, long? startBytes, CancellationToken cancellationToken = default) => GetInstanceAsync(httpClient, fileUri, startBytes, null, new AutoRetryOptions(), null, null, null, cancellationToken); - public static Task GetInstanceAsync(HttpClient httpClient, Uri fileUri, - long? startBytes, long? endBytes, AutoRetryOptions autoRetryOptions, string? mediaType, - CancellationToken cancellationToken = default) + public static Task GetInstanceAsync(HttpClient httpClient, + HttpPartialDownloadStreamUri fileUri, long? startBytes, long? endBytes, AutoRetryOptions autoRetryOptions, + string? mediaType, CancellationToken cancellationToken = default) => GetInstanceAsync(httpClient, fileUri, startBytes, endBytes, autoRetryOptions, mediaType, null, null, cancellationToken); - public static Task GetInstanceAsync(HttpClient httpClient, Uri fileUri, - long? startBytes, long? endBytes, string? mediaType, CancellationToken cancellationToken = default) + public static Task GetInstanceAsync(HttpClient httpClient, + HttpPartialDownloadStreamUri fileUri, long? startBytes, long? endBytes, string? mediaType, + CancellationToken cancellationToken = default) => GetInstanceAsync(httpClient, fileUri, startBytes, endBytes, new AutoRetryOptions(), mediaType, null, null, cancellationToken); - public static Task GetInstanceAsync(HttpClient httpClient, Uri fileUri, - long? startBytes, AutoRetryOptions autoRetryOptions, string? mediaType, + public static Task GetInstanceAsync(HttpClient httpClient, + HttpPartialDownloadStreamUri fileUri, long? startBytes, AutoRetryOptions autoRetryOptions, string? mediaType, CancellationToken cancellationToken = default) => GetInstanceAsync(httpClient, fileUri, startBytes, null, autoRetryOptions, mediaType, null, null, cancellationToken); - public static Task GetInstanceAsync(HttpClient httpClient, Uri fileUri, - long? startBytes, string? mediaType, CancellationToken cancellationToken = default) + public static Task GetInstanceAsync(HttpClient httpClient, + HttpPartialDownloadStreamUri fileUri, long? startBytes, string? mediaType, + CancellationToken cancellationToken = default) => GetInstanceAsync(httpClient, fileUri, startBytes, null, new AutoRetryOptions(), mediaType, null, null, cancellationToken); - public static Task GetInstanceAsync(HttpClient httpClient, Uri fileUri, - AutoRetryOptions autoRetryOptions, string? mediaType, CancellationToken cancellationToken = default) + public static Task GetInstanceAsync(HttpClient httpClient, + HttpPartialDownloadStreamUri fileUri, AutoRetryOptions autoRetryOptions, string? mediaType, + CancellationToken cancellationToken = default) => GetInstanceAsync(httpClient, fileUri, null, null, autoRetryOptions, mediaType, null, null, cancellationToken); - public static Task GetInstanceAsync(HttpClient httpClient, Uri fileUri, - string? mediaType, CancellationToken cancellationToken = default) + public static Task GetInstanceAsync(HttpClient httpClient, + HttpPartialDownloadStreamUri fileUri, string? mediaType, CancellationToken cancellationToken = default) => GetInstanceAsync(httpClient, fileUri, null, null, new AutoRetryOptions(), mediaType, null, null, cancellationToken); - public static Task GetInstanceAsync(HttpClient httpClient, Uri fileUri, - AutoRetryOptions autoRetryOptions, string? mediaType, long? fileLength, DateTimeOffset? fileLastModifiedTime, - CancellationToken cancellationToken = default) + public static Task GetInstanceAsync(HttpClient httpClient, + HttpPartialDownloadStreamUri fileUri, AutoRetryOptions autoRetryOptions, string? mediaType, long? fileLength, + DateTimeOffset? fileLastModifiedTime, CancellationToken cancellationToken = default) => GetInstanceAsync(httpClient, fileUri, null, null, autoRetryOptions, mediaType, fileLength, fileLastModifiedTime, cancellationToken); - public static Task GetInstanceAsync(HttpClient httpClient, Uri fileUri, - string? mediaType, long? fileLength, DateTimeOffset? fileLastModifiedTime, + public static Task GetInstanceAsync(HttpClient httpClient, + HttpPartialDownloadStreamUri fileUri, string? mediaType, long? fileLength, DateTimeOffset? fileLastModifiedTime, CancellationToken cancellationToken = default) => GetInstanceAsync(httpClient, fileUri, null, null, new AutoRetryOptions(), mediaType, fileLength, fileLastModifiedTime, cancellationToken); - public static Task GetInstanceAsync(HttpClient httpClient, Uri fileUri, - long? startBytes, long? endBytes, AutoRetryOptions autoRetryOptions, long? fileLength, - DateTimeOffset? fileLastModifiedTime, CancellationToken cancellationToken = default) + public static Task GetInstanceAsync(HttpClient httpClient, + HttpPartialDownloadStreamUri fileUri, long? startBytes, long? endBytes, AutoRetryOptions autoRetryOptions, + long? fileLength, DateTimeOffset? fileLastModifiedTime, CancellationToken cancellationToken = default) => GetInstanceAsync(httpClient, fileUri, startBytes, endBytes, autoRetryOptions, null, fileLength, fileLastModifiedTime, cancellationToken); - public static Task GetInstanceAsync(HttpClient httpClient, Uri fileUri, - long? startBytes, long? endBytes, long? fileLength, DateTimeOffset? fileLastModifiedTime, - CancellationToken cancellationToken = default) + public static Task GetInstanceAsync(HttpClient httpClient, + HttpPartialDownloadStreamUri fileUri, long? startBytes, long? endBytes, long? fileLength, + DateTimeOffset? fileLastModifiedTime, CancellationToken cancellationToken = default) => GetInstanceAsync(httpClient, fileUri, startBytes, endBytes, new AutoRetryOptions(), null, fileLength, fileLastModifiedTime, cancellationToken); - public static Task GetInstanceAsync(HttpClient httpClient, Uri fileUri, - long? startBytes, AutoRetryOptions autoRetryOptions, long? fileLength, DateTimeOffset? fileLastModifiedTime, - CancellationToken cancellationToken = default) + public static Task GetInstanceAsync(HttpClient httpClient, + HttpPartialDownloadStreamUri fileUri, long? startBytes, AutoRetryOptions autoRetryOptions, long? fileLength, + DateTimeOffset? fileLastModifiedTime, CancellationToken cancellationToken = default) => GetInstanceAsync(httpClient, fileUri, startBytes, null, autoRetryOptions, null, fileLength, fileLastModifiedTime, cancellationToken); - public static Task GetInstanceAsync(HttpClient httpClient, Uri fileUri, - long? startBytes, long? fileLength, DateTimeOffset? fileLastModifiedTime, + public static Task GetInstanceAsync(HttpClient httpClient, + HttpPartialDownloadStreamUri fileUri, long? startBytes, long? fileLength, DateTimeOffset? fileLastModifiedTime, CancellationToken cancellationToken = default) => GetInstanceAsync(httpClient, fileUri, startBytes, null, new AutoRetryOptions(), null, fileLength, fileLastModifiedTime, cancellationToken); - public static Task GetInstanceAsync(HttpClient httpClient, Uri fileUri, - AutoRetryOptions autoRetryOptions, long? fileLength, DateTimeOffset? fileLastModifiedTime, - CancellationToken cancellationToken = default) + public static Task GetInstanceAsync(HttpClient httpClient, + HttpPartialDownloadStreamUri fileUri, AutoRetryOptions autoRetryOptions, long? fileLength, + DateTimeOffset? fileLastModifiedTime, CancellationToken cancellationToken = default) => GetInstanceAsync(httpClient, fileUri, null, null, autoRetryOptions, null, fileLength, fileLastModifiedTime, cancellationToken); - public static Task GetInstanceAsync(HttpClient httpClient, Uri fileUri, - long? fileLength, DateTimeOffset? fileLastModifiedTime, CancellationToken cancellationToken = default) + public static Task GetInstanceAsync(HttpClient httpClient, + HttpPartialDownloadStreamUri fileUri, long? fileLength, DateTimeOffset? fileLastModifiedTime, + CancellationToken cancellationToken = default) => GetInstanceAsync(httpClient, fileUri, null, null, new AutoRetryOptions(), null, fileLength, fileLastModifiedTime, cancellationToken); - public static Task GetInstanceAsync(HttpClient httpClient, Uri fileUri, - long? startBytes, long? endBytes, string? mediaType, long? fileLength, + public static Task GetInstanceAsync(HttpClient httpClient, + HttpPartialDownloadStreamUri fileUri, long? startBytes, long? endBytes, string? mediaType, long? fileLength, DateTimeOffset? fileLastModifiedTime, CancellationToken cancellationToken = default) => GetInstanceAsync(httpClient, fileUri, startBytes, endBytes, new AutoRetryOptions(), mediaType, fileLength, fileLastModifiedTime, cancellationToken); diff --git a/src/Starward.Core.ZipStreamDownload/Http/VolumesFileHttpPartialDownloadStream.cs b/src/Starward.Core.ZipStreamDownload/Http/VolumesFileHttpPartialDownloadStream.cs index f47e3524c..5ec23a4e9 100644 --- a/src/Starward.Core.ZipStreamDownload/Http/VolumesFileHttpPartialDownloadStream.cs +++ b/src/Starward.Core.ZipStreamDownload/Http/VolumesFileHttpPartialDownloadStream.cs @@ -3,12 +3,13 @@ namespace Starward.Core.ZipStreamDownload.Http; -internal class VolumesFileHttpPartialDownloadStream : HttpPartialDownloadStream +internal sealed class VolumesFileHttpPartialDownloadStream : HttpPartialDownloadStream { - public class SingleFileInit(Uri fileUri, long? fileLength = null, DateTimeOffset? fileLastModifiedTime = null) + public class SingleFileInit(HttpPartialDownloadStreamUri fileUri, long? fileLength = null, + DateTimeOffset? fileLastModifiedTime = null) { - public Uri FileUri { get; } = fileUri; + public HttpPartialDownloadStreamUri FileUri { get; } = fileUri; public long? FileLength { get; } = fileLength; @@ -348,38 +349,39 @@ public static VolumesFileHttpPartialDownloadStream GetInstance(HttpClient httpCl => GetInstance(httpClient, files, null, null, new AutoRetryOptions(), null); public static VolumesFileHttpPartialDownloadStream GetInstance(HttpClient httpClient, - IEnumerable fileUris, long? startBytes, long? endBytes, AutoRetryOptions autoRetryOptions, - string? mediaType) + IEnumerable fileUris, long? startBytes, long? endBytes, + AutoRetryOptions autoRetryOptions, string? mediaType) => GetInstance(httpClient, fileUris.Select(f => new SingleFileInit(f)), startBytes, endBytes, autoRetryOptions, mediaType); public static VolumesFileHttpPartialDownloadStream GetInstance(HttpClient httpClient, - IEnumerable fileUris, long? startBytes, long? endBytes, string? mediaType) + IEnumerable fileUris, long? startBytes, long? endBytes, string? mediaType) => GetInstance(httpClient, fileUris.Select(f => new SingleFileInit(f)), startBytes, endBytes, new AutoRetryOptions(), mediaType); public static VolumesFileHttpPartialDownloadStream GetInstance(HttpClient httpClient, - IEnumerable fileUris, long? startBytes, long? endBytes, AutoRetryOptions autoRetryOptions) + IEnumerable fileUris, long? startBytes, long? endBytes, + AutoRetryOptions autoRetryOptions) => GetInstance(httpClient, fileUris, startBytes, endBytes, autoRetryOptions, null); public static VolumesFileHttpPartialDownloadStream GetInstance(HttpClient httpClient, - IEnumerable fileUris, long? startBytes, long? endBytes) + IEnumerable fileUris, long? startBytes, long? endBytes) => GetInstance(httpClient, fileUris, startBytes, endBytes, new AutoRetryOptions(), null); public static VolumesFileHttpPartialDownloadStream GetInstance(HttpClient httpClient, - IEnumerable fileUris, AutoRetryOptions autoRetryOptions, string? mediaType) + IEnumerable fileUris, AutoRetryOptions autoRetryOptions, string? mediaType) => GetInstance(httpClient, fileUris, null, null, autoRetryOptions, mediaType); public static VolumesFileHttpPartialDownloadStream GetInstance(HttpClient httpClient, - IEnumerable fileUris, string? mediaType) + IEnumerable fileUris, string? mediaType) => GetInstance(httpClient, fileUris, null, null, new AutoRetryOptions(), mediaType); public static VolumesFileHttpPartialDownloadStream GetInstance(HttpClient httpClient, - IEnumerable fileUris, AutoRetryOptions autoRetryOptions) + IEnumerable fileUris, AutoRetryOptions autoRetryOptions) => GetInstance(httpClient, fileUris, null, null, autoRetryOptions, null); public static VolumesFileHttpPartialDownloadStream GetInstance(HttpClient httpClient, - IEnumerable fileUris) + IEnumerable fileUris) => GetInstance(httpClient, fileUris, null, null, new AutoRetryOptions(), null); public static VolumesFileHttpPartialDownloadStream GetInstance(HttpClient httpClient, @@ -417,42 +419,45 @@ public static Task GetInstanceAsync(HttpCl => GetInstanceAsync(httpClient, files, null, null, new AutoRetryOptions(), null, cancellationToken); public static Task GetInstanceAsync(HttpClient httpClient, - IEnumerable fileUris, long? startBytes, long? endBytes, AutoRetryOptions autoRetryOptions, - string? mediaType, CancellationToken cancellationToken = default) + IEnumerable fileUris, long? startBytes, long? endBytes, + AutoRetryOptions autoRetryOptions, string? mediaType, CancellationToken cancellationToken = default) => GetInstanceAsync(httpClient, fileUris.Select(f => new SingleFileInit(f)), startBytes, endBytes, autoRetryOptions, mediaType, cancellationToken); public static Task GetInstanceAsync(HttpClient httpClient, - IEnumerable fileUris, long? startBytes, long? endBytes, string? mediaType, + IEnumerable fileUris, long? startBytes, long? endBytes, string? mediaType, CancellationToken cancellationToken = default) => GetInstanceAsync(httpClient, fileUris.Select(f => new SingleFileInit(f)), startBytes, endBytes, new AutoRetryOptions(), mediaType, cancellationToken); public static Task GetInstanceAsync(HttpClient httpClient, - IEnumerable fileUris, long? startBytes, long? endBytes, AutoRetryOptions autoRetryOptions, - CancellationToken cancellationToken = default) + IEnumerable fileUris, long? startBytes, long? endBytes, + AutoRetryOptions autoRetryOptions, CancellationToken cancellationToken = default) => GetInstanceAsync(httpClient, fileUris, startBytes, endBytes, autoRetryOptions, null, cancellationToken); public static Task GetInstanceAsync(HttpClient httpClient, - IEnumerable fileUris, long? startBytes, long? endBytes, CancellationToken cancellationToken = default) + IEnumerable fileUris, long? startBytes, long? endBytes, + CancellationToken cancellationToken = default) => GetInstanceAsync(httpClient, fileUris, startBytes, endBytes, new AutoRetryOptions(), null, cancellationToken); public static Task GetInstanceAsync(HttpClient httpClient, - IEnumerable fileUris, AutoRetryOptions autoRetryOptions, string? mediaType, + IEnumerable fileUris, AutoRetryOptions autoRetryOptions, string? mediaType, CancellationToken cancellationToken = default) => GetInstanceAsync(httpClient, fileUris, null, null, autoRetryOptions, mediaType, cancellationToken); public static Task GetInstanceAsync(HttpClient httpClient, - IEnumerable fileUris, string? mediaType, CancellationToken cancellationToken = default) + IEnumerable fileUris, string? mediaType, + CancellationToken cancellationToken = default) => GetInstanceAsync(httpClient, fileUris, null, null, new AutoRetryOptions(), mediaType, cancellationToken); public static Task GetInstanceAsync(HttpClient httpClient, - IEnumerable fileUris, AutoRetryOptions autoRetryOptions, CancellationToken cancellationToken = default) + IEnumerable fileUris, AutoRetryOptions autoRetryOptions, + CancellationToken cancellationToken = default) => GetInstanceAsync(httpClient, fileUris, null, null, autoRetryOptions, null, cancellationToken); public static Task GetInstanceAsync(HttpClient httpClient, - IEnumerable fileUris, CancellationToken cancellationToken = default) + IEnumerable fileUris, CancellationToken cancellationToken = default) => GetInstanceAsync(httpClient, fileUris, null, null, new AutoRetryOptions(), null, cancellationToken); public static Task GetInstanceAsync(HttpClient httpClient, diff --git a/src/Starward.Core.ZipStreamDownload/SingleFileZipFileDownloadFactory.cs b/src/Starward.Core.ZipStreamDownload/SingleFileZipFileDownloadFactory.cs index fff9423d7..d9d0596f2 100644 --- a/src/Starward.Core.ZipStreamDownload/SingleFileZipFileDownloadFactory.cs +++ b/src/Starward.Core.ZipStreamDownload/SingleFileZipFileDownloadFactory.cs @@ -15,14 +15,14 @@ public class SingleFileZipFileDownloadFactory(HttpClient httpClient) : IZipFileD [StringSyntax(StringSyntaxAttribute.Uri)] public string? ZipFileUrl { - get => ZipFileUri?.ToString(); - set => ZipFileUri = value == null ? null : new Uri(value); + get => _zipFileUri?.ToString(); + set => _zipFileUri = value == null ? null : new HttpPartialDownloadStreamUri(value, _httpPartialDnsResolve); } /// /// ZIP文件URL的URI对象。 /// - public Uri? ZipFileUri { get; set; } + public Uri? ZipFileUri => _zipFileUri?.Uri; /// /// 获取或设置一个一个返回实例的委托,表示按字节下载限速的限速器的选项。 @@ -34,6 +34,16 @@ public string? ZipFileUrl /// public AutoRetryOptions AutoRetryOptions { get; } = new(); + /// + /// ZIP文件URL(内部,类型)。 + /// + private HttpPartialDownloadStreamUri? _zipFileUri; + + /// + /// 一个的实例,用于DNS解析、IP地址测试和缓存。 + /// + private readonly HttpPartialDnsResolve _httpPartialDnsResolve = new(); + /// /// 获取一个用于单文件下载的类的新实例。 /// @@ -42,6 +52,6 @@ public string? ZipFileUrl public ZipFileDownload GetInstance() => new(async (startBytes, endBytes) => await SingleFileHttpPartialDownloadStream.GetInstanceAsync(httpClient, - ZipFileUri ?? throw new InvalidOperationException(), startBytes, endBytes, AutoRetryOptions, + _zipFileUri ?? throw new InvalidOperationException(), startBytes, endBytes, AutoRetryOptions, ZipFileDownload.MediaType).ConfigureAwait(false), DownloadBytesRateLimiterOptionBuilder); } \ No newline at end of file diff --git a/src/Starward.Core.ZipStreamDownload/VolumesFileZipFileDownloadFactory.cs b/src/Starward.Core.ZipStreamDownload/VolumesFileZipFileDownloadFactory.cs index d368743e4..6ac8d2338 100644 --- a/src/Starward.Core.ZipStreamDownload/VolumesFileZipFileDownloadFactory.cs +++ b/src/Starward.Core.ZipStreamDownload/VolumesFileZipFileDownloadFactory.cs @@ -14,15 +14,16 @@ public class VolumesFileZipFileDownloadFactory(HttpClient httpClient) : IZipFile /// 必须按照分卷顺序传入。 public List? ZipFileUrlList { - get => ZipFileUriList?.Select(u => u.ToString()).ToList(); - set => ZipFileUriList = value?.Select(u => new Uri(u)).ToList(); + get => _zipFileUriList?.Select(u => u.ToString()).ToList(); + set => _zipFileUriList = value?.Select(u => new HttpPartialDownloadStreamUri(u, _httpPartialDnsResolve)) + .ToList(); } /// /// 分卷ZIP文件的URL的URI对象的列表。 /// /// 必须按照分卷顺序传入。 - public List? ZipFileUriList { get; set; } + public List? ZipFileUriList => _zipFileUriList?.Select(u => u.Uri).ToList(); /// /// ZIP文件URL的URI对象。 @@ -32,7 +33,7 @@ public Uri? ZipFileUri { get { - var url = ZipFileUriList?.FirstOrDefault()?.ToString(); + var url = _zipFileUriList?.FirstOrDefault()?.ToString(); if (url == null) return null; var querySplit = url.IndexOf('?'); //去除Query。 var query = ""; @@ -56,6 +57,16 @@ public Uri? ZipFileUri /// public AutoRetryOptions AutoRetryOptions { get; } = new(); + /// + /// 分卷ZIP文件的URL的URI对象的列表(内部,类型)。 + /// + private List? _zipFileUriList; + + /// + /// 一个的实例,用于DNS解析、IP地址测试和缓存。 + /// + private readonly HttpPartialDnsResolve _httpPartialDnsResolve = new(); + /// /// 获取一个用于分卷文件下载的类的新实例。 /// @@ -64,6 +75,6 @@ public Uri? ZipFileUri public ZipFileDownload GetInstance() => new(async (startBytes, endBytes) => await VolumesFileHttpPartialDownloadStream.GetInstanceAsync(httpClient, - ZipFileUriList ?? throw new InvalidOperationException(), startBytes, endBytes, AutoRetryOptions, + _zipFileUriList ?? throw new InvalidOperationException(), startBytes, endBytes, AutoRetryOptions, ZipFileDownload.MediaType).ConfigureAwait(false), DownloadBytesRateLimiterOptionBuilder); } \ No newline at end of file