mirror of
https://github.com/netchx/netch.git
synced 2026-05-11 23:45:06 +08:00
Update async
This commit is contained in:
1
Netch/.gitignore
vendored
1
Netch/.gitignore
vendored
@@ -1,3 +1,4 @@
|
||||
/bin
|
||||
/obj
|
||||
/*.csproj.user
|
||||
FodyWeavers.xsd
|
||||
@@ -25,6 +25,6 @@ public static class Constants
|
||||
public const string WintunDllFile = "bin\\wintun.dll";
|
||||
public const string DisableModeDirectoryFileName = "disabled";
|
||||
|
||||
public const string DefaultPrimaryDNS = "1.1.1.1:53";
|
||||
public const string DefaultCNPrimaryDNS = "223.5.5.5:53";
|
||||
public const string DefaultPrimaryDNS = "1.1.1.1";
|
||||
public const string DefaultCNPrimaryDNS = "223.5.5.5";
|
||||
}
|
||||
@@ -23,8 +23,8 @@ public class DNSController : IController
|
||||
throw new MessageException("AioDNS start failed.");
|
||||
}
|
||||
|
||||
public async Task StopAsync()
|
||||
public Task StopAsync()
|
||||
{
|
||||
await FreeAsync();
|
||||
return FreeAsync();
|
||||
}
|
||||
}
|
||||
@@ -67,7 +67,7 @@ public abstract class Guard
|
||||
{
|
||||
State = State.Starting;
|
||||
|
||||
_logFileStream = File.Open(LogPath, FileMode.Create, FileAccess.Write, FileShare.Read);
|
||||
_logFileStream = new FileStream(LogPath, FileMode.Create, FileAccess.Write, FileShare.Read, 4096, true);
|
||||
_logStreamWriter = new StreamWriter(_logFileStream) { AutoFlush = true };
|
||||
|
||||
Instance.StartInfo.Arguments = argument;
|
||||
@@ -79,8 +79,8 @@ public abstract class Guard
|
||||
|
||||
if (RedirectOutput)
|
||||
{
|
||||
Task.Run(() => ReadOutput(Instance.StandardOutput)).Forget();
|
||||
Task.Run(() => ReadOutput(Instance.StandardError)).Forget();
|
||||
ReadOutputAsync(Instance.StandardOutput).Forget();
|
||||
ReadOutputAsync(Instance.StandardError).Forget();
|
||||
|
||||
if (!StartedKeywords.Any())
|
||||
{
|
||||
@@ -110,12 +110,12 @@ public abstract class Guard
|
||||
}
|
||||
}
|
||||
|
||||
private void ReadOutput(TextReader reader)
|
||||
private async Task ReadOutputAsync(TextReader reader)
|
||||
{
|
||||
string? line;
|
||||
while ((line = reader.ReadLine()) != null)
|
||||
while ((line = await reader.ReadLineAsync()) != null)
|
||||
{
|
||||
_logStreamWriter!.WriteLine(line);
|
||||
await _logStreamWriter!.WriteLineAsync(line);
|
||||
OnReadNewLine(line);
|
||||
|
||||
if (State == State.Starting)
|
||||
@@ -133,9 +133,9 @@ public abstract class Guard
|
||||
State = State.Stopped;
|
||||
}
|
||||
|
||||
public virtual async Task StopAsync()
|
||||
public virtual Task StopAsync()
|
||||
{
|
||||
await StopGuardAsync();
|
||||
return StopGuardAsync();
|
||||
}
|
||||
|
||||
protected async Task StopGuardAsync()
|
||||
|
||||
@@ -169,18 +169,18 @@ public static class MainController
|
||||
PortCheck(port, portName, PortType.TCP);
|
||||
}
|
||||
|
||||
public static async Task<NatTypeTestResult> DiscoveryNatTypeAsync(CancellationToken ctx = default)
|
||||
public static Task<NatTypeTestResult> DiscoveryNatTypeAsync(CancellationToken ctx = default)
|
||||
{
|
||||
Debug.Assert(Socks5Server != null, nameof(Socks5Server) + " != null");
|
||||
return await Socks5ServerTestUtils.DiscoveryNatTypeAsync(Socks5Server, ctx);
|
||||
return Socks5ServerTestUtils.DiscoveryNatTypeAsync(Socks5Server, ctx);
|
||||
}
|
||||
|
||||
public static async Task<int?> HttpConnectAsync(CancellationToken ctx = default)
|
||||
public static Task<int?> HttpConnectAsync(CancellationToken ctx = default)
|
||||
{
|
||||
Debug.Assert(Socks5Server != null, nameof(Socks5Server) + " != null");
|
||||
try
|
||||
{
|
||||
return await Socks5ServerTestUtils.HttpConnectAsync(Socks5Server, ctx);
|
||||
return Socks5ServerTestUtils.HttpConnectAsync(Socks5Server, ctx);
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
@@ -191,6 +191,6 @@ public static class MainController
|
||||
Log.Warning(e, "Unhandled Socks5ServerTestUtils.HttpConnectAsync Exception");
|
||||
}
|
||||
|
||||
return null;
|
||||
return Task.FromResult<int?>(null);
|
||||
}
|
||||
}
|
||||
@@ -76,9 +76,9 @@ public class NFController : IModeController
|
||||
throw new MessageException("Redirector start failed.");
|
||||
}
|
||||
|
||||
public async Task StopAsync()
|
||||
public Task StopAsync()
|
||||
{
|
||||
await FreeAsync();
|
||||
return FreeAsync();
|
||||
}
|
||||
|
||||
#region CheckRule
|
||||
|
||||
@@ -92,10 +92,11 @@ public class TUNController : Guard, IModeController
|
||||
_tun = NetRoute.TemplateBuilder(_tunConfig.Gateway, tunIndex);
|
||||
|
||||
Global.MainForm.StatusText(i18N.Translate("Assign Unicast IP"));
|
||||
if (!RouteHelper.CreateUnicastIP(AddressFamily.InterNetwork,
|
||||
_tunConfig.Address,
|
||||
(byte)Utils.Utils.SubnetToCidr(_tunConfig.Netmask),
|
||||
(ulong)tunIndex))
|
||||
if (!await Task.Run(() => RouteHelper.CreateUnicastIP(AddressFamily.InterNetwork,
|
||||
_tunConfig.Address,
|
||||
(byte)Utils.Utils.SubnetToCidr(_tunConfig.Netmask),
|
||||
(ulong)tunIndex))
|
||||
)
|
||||
{
|
||||
Log.Error("Create Unicast IP failed");
|
||||
throw new MessageException("Create Unicast IP failed");
|
||||
|
||||
3
Netch/FodyWeavers.xml
Normal file
3
Netch/FodyWeavers.xml
Normal file
@@ -0,0 +1,3 @@
|
||||
<Weavers xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="FodyWeavers.xsd">
|
||||
<ConfigureAwait />
|
||||
</Weavers>
|
||||
@@ -3,6 +3,7 @@ using Netch.Utils;
|
||||
|
||||
namespace Netch.Forms;
|
||||
|
||||
[Fody.ConfigureAwait(true)]
|
||||
public partial class AboutForm : Form
|
||||
{
|
||||
public AboutForm()
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
namespace Netch.Forms;
|
||||
|
||||
[Fody.ConfigureAwait(true)]
|
||||
public class BindingForm : Form
|
||||
{
|
||||
private readonly Dictionary<Control, Func<string, bool>> _checkActions = new();
|
||||
|
||||
@@ -4,6 +4,7 @@ using Netch.Utils;
|
||||
|
||||
namespace Netch.Forms;
|
||||
|
||||
[Fody.ConfigureAwait(true)]
|
||||
public partial class GlobalBypassIPForm : Form
|
||||
{
|
||||
public GlobalBypassIPForm()
|
||||
|
||||
@@ -5,6 +5,7 @@ using static Windows.Win32.PInvoke;
|
||||
|
||||
namespace Netch.Forms;
|
||||
|
||||
[Fody.ConfigureAwait(true)]
|
||||
public partial class LogForm : Form
|
||||
{
|
||||
private readonly Form _parent;
|
||||
|
||||
@@ -18,6 +18,7 @@ using Netch.Utils;
|
||||
|
||||
namespace Netch.Forms;
|
||||
|
||||
[Fody.ConfigureAwait(true)]
|
||||
public partial class MainForm : Form
|
||||
{
|
||||
#region Start
|
||||
@@ -447,10 +448,13 @@ public partial class MainForm : Form
|
||||
|
||||
var downloaded = false;
|
||||
if (File.Exists(updateFileFullName))
|
||||
if (Utils.Utils.SHA256CheckSum(updateFileFullName) == sha256)
|
||||
{
|
||||
var fileHash = await Utils.Utils.Sha256CheckSumAsync(updateFileFullName);
|
||||
if (fileHash == sha256)
|
||||
downloaded = true;
|
||||
else
|
||||
File.Delete(updateFileFullName);
|
||||
}
|
||||
|
||||
if (!downloaded)
|
||||
{
|
||||
@@ -464,7 +468,8 @@ public partial class MainForm : Form
|
||||
throw new MessageException($"Download Update File Failed: {e1.Message}");
|
||||
}
|
||||
|
||||
if (Utils.Utils.SHA256CheckSum(updateFileFullName) != sha256)
|
||||
var fileHash = await Utils.Utils.Sha256CheckSumAsync(updateFileFullName);
|
||||
if (fileHash != sha256)
|
||||
throw new MessageException(i18N.Translate("The downloaded file has the wrong hash"));
|
||||
}
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@ using Netch.Utils;
|
||||
|
||||
namespace Netch.Forms.ModeForms;
|
||||
|
||||
[Fody.ConfigureAwait(true)]
|
||||
public partial class ProcessForm : BindingForm
|
||||
{
|
||||
private readonly bool IsCreateMode;
|
||||
|
||||
@@ -6,6 +6,7 @@ using Netch.Utils;
|
||||
|
||||
namespace Netch.Forms.ModeForms;
|
||||
|
||||
[Fody.ConfigureAwait(true)]
|
||||
public partial class RouteForm : BindingForm
|
||||
{
|
||||
private readonly bool IsCreateMode;
|
||||
|
||||
@@ -7,6 +7,7 @@ using Netch.Utils;
|
||||
namespace Netch.Forms;
|
||||
|
||||
[DesignerCategory(@"Code")]
|
||||
[Fody.ConfigureAwait(true)]
|
||||
public abstract class ServerForm : Form
|
||||
{
|
||||
private const int ControlLineHeight = 28;
|
||||
|
||||
@@ -4,6 +4,7 @@ using Netch.Utils;
|
||||
|
||||
namespace Netch.Forms;
|
||||
|
||||
[Fody.ConfigureAwait(true)]
|
||||
public partial class SettingForm : BindingForm
|
||||
{
|
||||
public SettingForm()
|
||||
|
||||
@@ -4,6 +4,7 @@ using Netch.Utils;
|
||||
|
||||
namespace Netch.Forms;
|
||||
|
||||
[Fody.ConfigureAwait(true)]
|
||||
public partial class SubscriptionForm : Form
|
||||
{
|
||||
public SubscriptionForm()
|
||||
|
||||
@@ -13,14 +13,14 @@ public static class AioDNS
|
||||
return aiodns_dial(name, Encoding.UTF8.GetBytes(value));
|
||||
}
|
||||
|
||||
public static async Task<bool> InitAsync()
|
||||
public static Task<bool> InitAsync()
|
||||
{
|
||||
return await Task.Run(Init).ConfigureAwait(false);
|
||||
return Task.Run(Init);
|
||||
}
|
||||
|
||||
public static async Task FreeAsync()
|
||||
public static Task FreeAsync()
|
||||
{
|
||||
await Task.Run(Free).ConfigureAwait(false);
|
||||
return Task.Run(Free);
|
||||
}
|
||||
|
||||
[DllImport(aiodns_bin, CallingConvention = CallingConvention.Cdecl)]
|
||||
|
||||
@@ -43,14 +43,14 @@ public static class Redirector
|
||||
return aio_dial(name, value);
|
||||
}
|
||||
|
||||
public static async Task<bool> InitAsync()
|
||||
public static Task<bool> InitAsync()
|
||||
{
|
||||
return await Task.Run(aio_init).ConfigureAwait(false);
|
||||
return Task.Run(aio_init);
|
||||
}
|
||||
|
||||
public static async Task<bool> FreeAsync()
|
||||
public static Task<bool> FreeAsync()
|
||||
{
|
||||
return await Task.Run(aio_free).ConfigureAwait(false);
|
||||
return Task.Run(aio_free);
|
||||
}
|
||||
|
||||
private const string Redirector_bin = "Redirector.bin";
|
||||
|
||||
@@ -77,17 +77,15 @@ public abstract class Server : ICloneable
|
||||
var list = new Task<int>[3];
|
||||
for (var i = 0; i < 3; i++)
|
||||
{
|
||||
async Task<int> PingCoreAsync()
|
||||
Task<int> PingCoreAsync()
|
||||
{
|
||||
try
|
||||
{
|
||||
return Global.Settings.ServerTCPing
|
||||
? await Utils.Utils.TCPingAsync(destination, Port)
|
||||
: await Utils.Utils.ICMPingAsync(destination);
|
||||
return Global.Settings.ServerTCPing ? Utils.Utils.TCPingAsync(destination, Port) : Utils.Utils.ICMPingAsync(destination);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
return -4;
|
||||
return Task.FromResult(-4);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -37,6 +37,13 @@
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="ConfigureAwait.Fody" Version="3.3.1">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Fody" Version="6.6.0">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="HMBSbige.SingleInstance" Version="6.0.0" />
|
||||
<PackageReference Include="MaxMind.GeoIP2" Version="4.0.1" />
|
||||
<PackageReference Include="Microsoft.Diagnostics.Tracing.TraceEvent" Version="2.0.73" GeneratePathProperty="true" />
|
||||
|
||||
@@ -91,7 +91,7 @@ public static class Program
|
||||
i18N.Load(Global.Settings.Language);
|
||||
|
||||
// log environment information
|
||||
Task.Run(LogEnvironment).Forget();
|
||||
LogEnvironmentAsync().Forget();
|
||||
CheckClr();
|
||||
CheckOS();
|
||||
|
||||
@@ -108,11 +108,11 @@ public static class Program
|
||||
|
||||
#pragma warning restore VSTHRD002
|
||||
|
||||
private static void LogEnvironment()
|
||||
private static async Task LogEnvironmentAsync()
|
||||
{
|
||||
Log.Information("Netch Version: {Version}", $"{UpdateChecker.Owner}/{UpdateChecker.Repo}@{UpdateChecker.Version}");
|
||||
Log.Information("OS: {OSVersion}", Environment.OSVersion);
|
||||
Log.Information("SHA256: {Hash}", $"{Utils.Utils.SHA256CheckSum(Global.NetchExecutable)}");
|
||||
Log.Information("SHA256: {Hash}", $"{await Utils.Utils.Sha256CheckSumAsync(Global.NetchExecutable)}");
|
||||
Log.Information("System Language: {Language}", CultureInfo.CurrentCulture.Name);
|
||||
|
||||
#if RELEASE
|
||||
|
||||
@@ -14,6 +14,7 @@ using Netch.Controllers;
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
[assembly: System.Runtime.Versioning.SupportedOSPlatformAttribute("Windows7.0")]
|
||||
[assembly: Fody.ConfigureAwait(false)]
|
||||
|
||||
// 将 ComVisible 设置为 false 会使此程序集中的类型
|
||||
//对 COM 组件不可见。如果需要从 COM 访问此程序集中的类型
|
||||
|
||||
@@ -3,6 +3,7 @@ using Netch.Utils;
|
||||
|
||||
namespace Netch.Servers;
|
||||
|
||||
[Fody.ConfigureAwait(true)]
|
||||
public class ShadowsocksForm : ServerForm
|
||||
{
|
||||
public ShadowsocksForm(ShadowsocksServer? server = default)
|
||||
|
||||
@@ -3,6 +3,7 @@ using Netch.Utils;
|
||||
|
||||
namespace Netch.Servers;
|
||||
|
||||
[Fody.ConfigureAwait(true)]
|
||||
public class ShadowsocksRForm : ServerForm
|
||||
{
|
||||
public ShadowsocksRForm(ShadowsocksRServer? server = default)
|
||||
|
||||
@@ -6,12 +6,12 @@ public class Socks5Controller : V2rayController
|
||||
{
|
||||
public override string Name { get; } = "Socks5";
|
||||
|
||||
public override async Task<Socks5LocalServer> StartAsync(Server s)
|
||||
public override Task<Socks5LocalServer> StartAsync(Server s)
|
||||
{
|
||||
var server = (Socks5Server)s;
|
||||
if (!server.Auth())
|
||||
throw new ArgumentException();
|
||||
|
||||
return await base.StartAsync(s);
|
||||
return base.StartAsync(s);
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
namespace Netch.Servers;
|
||||
|
||||
[Fody.ConfigureAwait(true)]
|
||||
public class Socks5Form : ServerForm
|
||||
{
|
||||
public Socks5Form(Socks5Server? server = default)
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
namespace Netch.Servers;
|
||||
|
||||
[Fody.ConfigureAwait(true)]
|
||||
public class TrojanForm : ServerForm
|
||||
{
|
||||
public TrojanForm(TrojanServer? server = default)
|
||||
|
||||
@@ -2,6 +2,7 @@ using Netch.Forms;
|
||||
|
||||
namespace Netch.Servers;
|
||||
|
||||
[Fody.ConfigureAwait(true)]
|
||||
internal class VLESSForm : ServerForm
|
||||
{
|
||||
public VLESSForm(VLESSServer? server = default)
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
namespace Netch.Servers;
|
||||
|
||||
[Fody.ConfigureAwait(true)]
|
||||
public class VMessForm : ServerForm
|
||||
{
|
||||
public VMessForm(VMessServer? server = default)
|
||||
|
||||
@@ -64,7 +64,7 @@ public static class Configuration
|
||||
|
||||
await using (var fs = new FileStream(filename, FileMode.Open, FileAccess.Read, FileShare.Read, 4096, true))
|
||||
{
|
||||
settings = (await JsonSerializer.DeserializeAsync<Setting>(fs, JsonSerializerOptions).ConfigureAwait(false))!;
|
||||
settings = (await JsonSerializer.DeserializeAsync<Setting>(fs, JsonSerializerOptions))!;
|
||||
}
|
||||
|
||||
CheckSetting(settings);
|
||||
@@ -126,7 +126,7 @@ public static class Configuration
|
||||
{
|
||||
if (!File.Exists(FileFullName))
|
||||
{
|
||||
await File.Create(FileFullName).DisposeAsync();
|
||||
await using var fs = new FileStream(FileFullName, FileMode.Create, FileAccess.ReadWrite, FileShare.None, 4096, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -39,7 +39,7 @@ public static class DnsUtils
|
||||
private static async Task<IPAddress?> LookupNoCacheAsync(string hostname, AddressFamily inet = AddressFamily.Unspecified, int timeout = 3000)
|
||||
{
|
||||
using var task = Dns.GetHostAddressesAsync(hostname);
|
||||
using var resTask = await Task.WhenAny(task, Task.Delay(timeout)).ConfigureAwait(false);
|
||||
using var resTask = await Task.WhenAny(task, Task.Delay(timeout));
|
||||
|
||||
if (resTask == task)
|
||||
{
|
||||
|
||||
@@ -7,9 +7,9 @@ public static class SubscriptionUtil
|
||||
{
|
||||
private static readonly object ServerLock = new();
|
||||
|
||||
public static async Task UpdateServersAsync(string? proxyServer = default)
|
||||
public static Task UpdateServersAsync(string? proxyServer = default)
|
||||
{
|
||||
await Task.WhenAll(Global.Settings.Subscription.Select(item => UpdateServerCoreAsync(item, proxyServer)));
|
||||
return Task.WhenAll(Global.Settings.Subscription.Select(item => UpdateServerCoreAsync(item, proxyServer)));
|
||||
}
|
||||
|
||||
private static async Task UpdateServerCoreAsync(Subscription item, string? proxyServer)
|
||||
|
||||
@@ -92,12 +92,12 @@ public static class Utils
|
||||
return country;
|
||||
}
|
||||
|
||||
public static string SHA256CheckSum(string filePath)
|
||||
public static async Task<string> Sha256CheckSumAsync(string filePath)
|
||||
{
|
||||
try
|
||||
{
|
||||
using var fileStream = File.OpenRead(filePath);
|
||||
return SHA256ComputeCore(fileStream);
|
||||
await using var fileStream = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.Read, 4096, true);
|
||||
return await Sha256ComputeCoreAsync(fileStream);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
@@ -106,10 +106,11 @@ public static class Utils
|
||||
}
|
||||
}
|
||||
|
||||
private static string SHA256ComputeCore(Stream stream)
|
||||
private static async Task<string> Sha256ComputeCoreAsync(Stream stream)
|
||||
{
|
||||
using var sha256 = SHA256.Create();
|
||||
return string.Concat(sha256.ComputeHash(stream).Select(b => b.ToString("x2")));
|
||||
var hash = await sha256.ComputeHashAsync(stream);
|
||||
return string.Concat(hash.Select(b => b.ToString("x2")));
|
||||
}
|
||||
|
||||
public static string GetFileVersion(string file)
|
||||
|
||||
@@ -28,69 +28,55 @@ public static class WebUtil
|
||||
return req;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 异步下载
|
||||
/// </summary>
|
||||
/// <param name="req"></param>
|
||||
/// <returns></returns>
|
||||
public static async Task<byte[]> DownloadBytesAsync(HttpWebRequest req)
|
||||
{
|
||||
using var webResponse = await req.GetResponseAsync();
|
||||
await using var memoryStream = new MemoryStream();
|
||||
await using var input = webResponse.GetResponseStream();
|
||||
|
||||
await input.CopyToAsync(memoryStream);
|
||||
return memoryStream.ToArray();
|
||||
var memoryStream = new MemoryStream();
|
||||
await using (memoryStream)
|
||||
{
|
||||
var input = webResponse.GetResponseStream();
|
||||
await using (input)
|
||||
{
|
||||
await input.CopyToAsync(memoryStream);
|
||||
return memoryStream.ToArray();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 异步下载并编码为字符串
|
||||
/// </summary>
|
||||
/// <param name="req"></param>
|
||||
/// <param name="encoding">编码,默认UTF-8</param>
|
||||
/// <returns></returns>
|
||||
public static (HttpStatusCode, string) DownloadString(HttpWebRequest req, Encoding? encoding = null)
|
||||
{
|
||||
encoding ??= Encoding.UTF8;
|
||||
using var rep = (HttpWebResponse)req.GetResponse();
|
||||
using var responseStream = rep.GetResponseStream();
|
||||
using var streamReader = new StreamReader(responseStream, encoding);
|
||||
|
||||
return (rep.StatusCode, streamReader.ReadToEnd());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 异步下载并编码为字符串
|
||||
/// </summary>
|
||||
/// <param name="req"></param>
|
||||
/// <param name="encoding">编码,默认UTF-8</param>
|
||||
/// <returns></returns>
|
||||
public static async Task<(HttpStatusCode, string)> DownloadStringAsync(HttpWebRequest req, Encoding? encoding = null)
|
||||
{
|
||||
encoding ??= Encoding.UTF8;
|
||||
using var webResponse = (HttpWebResponse)await req.GetResponseAsync();
|
||||
await using var responseStream = webResponse.GetResponseStream();
|
||||
using var streamReader = new StreamReader(responseStream, encoding);
|
||||
|
||||
return (webResponse.StatusCode, await streamReader.ReadToEndAsync());
|
||||
var responseStream = webResponse.GetResponseStream();
|
||||
await using (responseStream)
|
||||
{
|
||||
using var streamReader = new StreamReader(responseStream, encoding);
|
||||
|
||||
return (webResponse.StatusCode, await streamReader.ReadToEndAsync());
|
||||
}
|
||||
}
|
||||
|
||||
public static async Task DownloadFileAsync(string address, string fileFullPath, IProgress<int>? progress = null)
|
||||
public static Task DownloadFileAsync(string address, string fileFullPath, IProgress<int>? progress = null)
|
||||
{
|
||||
await DownloadFileAsync(CreateRequest(address), fileFullPath, progress);
|
||||
return DownloadFileAsync(CreateRequest(address), fileFullPath, progress);
|
||||
}
|
||||
|
||||
public static async Task DownloadFileAsync(HttpWebRequest req, string fileFullPath, IProgress<int>? progress)
|
||||
{
|
||||
await using (var fileStream = File.Open(fileFullPath, FileMode.Create, FileAccess.Write))
|
||||
using (var webResponse = (HttpWebResponse)await req.GetResponseAsync())
|
||||
await using (var input = webResponse.GetResponseStream())
|
||||
using (var downloadTask = input.CopyToAsync(fileStream))
|
||||
var fileStream = new FileStream(fileFullPath, FileMode.Create, FileAccess.Write, FileShare.None, 4096, true);
|
||||
await using (fileStream)
|
||||
{
|
||||
if (progress != null)
|
||||
ReportProgressAsync(webResponse.ContentLength, downloadTask, fileStream, progress, 200).Forget();
|
||||
using var webResponse = (HttpWebResponse)await req.GetResponseAsync();
|
||||
var input = webResponse.GetResponseStream();
|
||||
await using (input)
|
||||
{
|
||||
using var downloadTask = input.CopyToAsync(fileStream);
|
||||
if (progress != null)
|
||||
ReportProgressAsync(webResponse.ContentLength, downloadTask, fileStream, progress, 200).Forget();
|
||||
|
||||
await downloadTask;
|
||||
await downloadTask;
|
||||
}
|
||||
}
|
||||
|
||||
progress?.Report(100);
|
||||
@@ -108,7 +94,7 @@ public static class WebUtil
|
||||
progress.Report(n);
|
||||
}
|
||||
|
||||
await Task.Delay(interval).ConfigureAwait(false);
|
||||
await Task.Delay(interval);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user