mirror of
https://github.com/BeyondDimension/SteamTools.git
synced 2026-10-28 05:56:52 +08:00
Compare commits
41
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c749fad3be | ||
|
|
25afcb2b3f | ||
|
|
45683c78a8 | ||
|
|
a477cd87cf | ||
|
|
a2cf95f0c1 | ||
|
|
88ddc7a320 | ||
|
|
e5463f44d2 | ||
|
|
816d1c9b0c | ||
|
|
69296f9587 | ||
|
|
6577ed9fa0 | ||
|
|
a54e988441 | ||
|
|
db508a04f0 | ||
|
|
eb065d7c7e | ||
|
|
1b639291e4 | ||
|
|
c8810f7926 | ||
|
|
073b5885c6 | ||
|
|
ed6df52998 | ||
|
|
88b4aac622 | ||
|
|
9504413ff7 | ||
|
|
0f28de1e94 | ||
|
|
ad11654cb4 | ||
|
|
f43aa16c6a | ||
|
|
c0e757dc12 | ||
|
|
fcecb2c14c | ||
|
|
408911de4a | ||
|
|
23932298fc | ||
|
|
7c554190af | ||
|
|
2f2065e453 | ||
|
|
1480b5d4df | ||
|
|
9ae326ce9f | ||
|
|
3dd83886b8 | ||
|
|
3a1a256198 | ||
|
|
84f9ae5227 | ||
|
|
ce85b39328 | ||
|
|
6c23ac30a3 | ||
|
|
bbe9596d8d | ||
|
|
5c42a2336d | ||
|
|
afa4ad9e91 | ||
|
|
50a3c7624e | ||
|
|
b84fd825b3 | ||
|
|
1732c84606 |
@@ -997,6 +997,15 @@
|
||||
"Summary": "加速后自动唤起 Watt 加速器界面",
|
||||
"IsRegionOrEndregion": null,
|
||||
"IsValueType": null
|
||||
},
|
||||
{
|
||||
"TypeName": "bool",
|
||||
"PropertyName": "ProxyBeforeDNSCheck",
|
||||
"DefaultValue": "true",
|
||||
"DefaultValueIsConst": true,
|
||||
"Summary": "加速前进行 DNS 可用性检查",
|
||||
"IsRegionOrEndregion": null,
|
||||
"IsValueType": null
|
||||
}
|
||||
],
|
||||
"Usings": ""
|
||||
|
||||
+1
-1
Submodule ref/DirectoryPackages updated: adcb50a330...e85de9b2cd
+1
-1
Submodule ref/SteamClient updated: d276f9eefa...6f3eb5e36c
Submodule ref/WTTS.MicroServices.ClientSDK updated: 213b92d243...27e9c1c2c6
+1
-1
Submodule ref/WinAuth updated: 4e698bc59d...de5b795ccf
@@ -16,14 +16,14 @@ public static partial class AssemblyInfo
|
||||
/// <summary>
|
||||
/// 预览版本号,范围 1~9,只增不减
|
||||
/// </summary>
|
||||
const string ver_for_preview = "9";
|
||||
const string ver_for_preview = "0";
|
||||
|
||||
/// <summary>
|
||||
/// RC 版本号,范围 0~9,只增不减
|
||||
/// </summary>
|
||||
const string ver_for_rc = "13";
|
||||
const string ver_for_rc = "16";
|
||||
|
||||
public const string FileVersion = $"{Version2}.{ver_for_rc}1{ver_for_preview}.0";
|
||||
public const string FileVersion = $"{Version2}.{ver_for_rc}2{ver_for_preview}.0";
|
||||
|
||||
//public const string InformationalVersion = Version;
|
||||
//public const string InformationalVersion = $"{Version}-preview.{ver_for_preview}";
|
||||
|
||||
@@ -4,7 +4,7 @@ namespace Avalonia.Controls;
|
||||
public static class AvaloniaControlsInternalsWindowExtensions
|
||||
{
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static void CloseCore_(this Window window, WindowCloseReason reason, bool isProgrammatic) => window.CloseCore(reason, isProgrammatic);
|
||||
public static void CloseCore_(this Window window, WindowCloseReason reason, bool isProgrammatic, bool ignoreCancel) => window.CloseCore(reason, isProgrammatic, ignoreCancel);
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static void HandleResized_(this Window window, Size clientSize, WindowResizeReason reason) => window.HandleResized(clientSize, reason);
|
||||
|
||||
@@ -174,7 +174,7 @@ namespace Avalonia.Controls.ApplicationLifetimes
|
||||
{
|
||||
if (w.Owner is null)
|
||||
{
|
||||
w.CloseCore_(WindowCloseReason.ApplicationShutdown, isProgrammatic);
|
||||
w.CloseCore_(WindowCloseReason.ApplicationShutdown, isProgrammatic, false);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -295,33 +295,42 @@ sealed partial class Program : Startup
|
||||
|
||||
protected override ActiveUserRecordDTO GetActiveUserRecord()
|
||||
{
|
||||
#if !__MOBILE__ && !MAUI
|
||||
var app = UI.App.Instance;
|
||||
var window = app.GetFirstOrDefaultWindow();
|
||||
var screens = window?.Screens;
|
||||
#else
|
||||
var mainDisplayInfo = DeviceDisplay.MainDisplayInfo;
|
||||
var mainDisplayInfoH = mainDisplayInfo.Height.ToInt32(NumberToInt32Format.Ceiling);
|
||||
var mainDisplayInfoW = mainDisplayInfo.Width.ToInt32(NumberToInt32Format.Ceiling);
|
||||
#endif
|
||||
var result = new ActiveUserRecordDTO
|
||||
{
|
||||
#if __MOBILE__ || MAUI
|
||||
ScreenCount = 1,
|
||||
PrimaryScreenPixelDensity = mainDisplayInfo.Density,
|
||||
PrimaryScreenWidth = mainDisplayInfoW,
|
||||
PrimaryScreenHeight = mainDisplayInfoH,
|
||||
SumScreenWidth = mainDisplayInfoW,
|
||||
SumScreenHeight = mainDisplayInfoH,
|
||||
#else
|
||||
ScreenCount = screens?.ScreenCount ?? default,
|
||||
PrimaryScreenPixelDensity = screens?.Primary?.Scaling ?? default,
|
||||
PrimaryScreenWidth = screens?.Primary?.Bounds.Width ?? default,
|
||||
PrimaryScreenHeight = screens?.Primary?.Bounds.Height ?? default,
|
||||
SumScreenWidth = screens?.All.Sum(x => x.Bounds.Width) ?? default,
|
||||
SumScreenHeight = screens?.All.Sum(x => x.Bounds.Height) ?? default,
|
||||
#endif
|
||||
};
|
||||
SetScreen(result);
|
||||
static void SetScreen(ActiveUserRecordDTO m)
|
||||
{
|
||||
try
|
||||
{
|
||||
#if !__MOBILE__ && !MAUI
|
||||
var app = UI.App.Instance;
|
||||
var window = app.GetFirstOrDefaultWindow();
|
||||
var screens = window?.Screens;
|
||||
|
||||
m.ScreenCount = screens?.ScreenCount ?? default;
|
||||
m.PrimaryScreenPixelDensity = screens?.Primary?.Scaling ?? default;
|
||||
m.PrimaryScreenWidth = screens?.Primary?.Bounds.Width ?? default;
|
||||
m.PrimaryScreenHeight = screens?.Primary?.Bounds.Height ?? default;
|
||||
m.SumScreenWidth = screens?.All?.Sum(x => x.Bounds.Width) ?? default;
|
||||
m.SumScreenHeight = screens?.All?.Sum(x => x.Bounds.Height) ?? default;
|
||||
#else
|
||||
var mainDisplayInfo = DeviceDisplay.MainDisplayInfo;
|
||||
var mainDisplayInfoH = mainDisplayInfo.Height.ToInt32(NumberToInt32Format.Ceiling);
|
||||
var mainDisplayInfoW = mainDisplayInfo.Width.ToInt32(NumberToInt32Format.Ceiling);
|
||||
|
||||
m.ScreenCount = 1;
|
||||
m.PrimaryScreenPixelDensity = mainDisplayInfo.Density;
|
||||
m.PrimaryScreenWidth = mainDisplayInfoW;
|
||||
m.PrimaryScreenHeight = mainDisplayInfoH;
|
||||
m.SumScreenWidth = mainDisplayInfoW;
|
||||
m.SumScreenHeight = mainDisplayInfoH;
|
||||
#endif
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
@@ -45,7 +45,7 @@ public sealed partial class App : Application
|
||||
{
|
||||
if (ApplicationLifetime is ClassicDesktopStyleApplicationLifetime classicDesktopStyleApplicationLifetime)
|
||||
{
|
||||
window = classicDesktopStyleApplicationLifetime.Windows.FirstOrDefault(x => x != null);
|
||||
window = classicDesktopStyleApplicationLifetime.Windows?.FirstOrDefault(x => x != null);
|
||||
}
|
||||
}
|
||||
return window;
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:ms="https://steampp.net/settings"
|
||||
xmlns:sys="using:System"
|
||||
xmlns:ui="using:FluentAvalonia.UI.Controls"
|
||||
x:CompileBindings="True">
|
||||
<Styles.Resources>
|
||||
<ResourceDictionary>
|
||||
|
||||
+2
-1
@@ -35,6 +35,7 @@ public static class KestrelServerOptionsExtensions
|
||||
|
||||
options.Listen(IReverseProxyService.Constants.Instance.ProxyIp, httpProxyPort, listen =>
|
||||
{
|
||||
listen.Protocols = HttpProtocols.Http1AndHttp2AndHttp3;
|
||||
var proxyMiddleware = options.ApplicationServices.GetRequiredService<HttpProxyMiddleware>();
|
||||
var tunnelMiddleware = options.ApplicationServices.GetRequiredService<TunnelMiddleware>();
|
||||
|
||||
@@ -123,7 +124,7 @@ public static class KestrelServerOptionsExtensions
|
||||
var httpsPort = IReverseProxyConfig.HttpsPort;
|
||||
options.Listen(IReverseProxyService.Constants.Instance.ProxyIp, httpsPort, listen =>
|
||||
{
|
||||
listen.Protocols = HttpProtocols.Http1AndHttp2;
|
||||
listen.Protocols = HttpProtocols.Http1AndHttp2AndHttp3;
|
||||
listen.UseFlowAnalyze();
|
||||
listen.UseTls();
|
||||
});
|
||||
|
||||
+2
-1
@@ -36,7 +36,7 @@ sealed class ReverseProxyHttpClientHandler : DelegatingHandler
|
||||
|
||||
// 设置请求头 host,因为连接中已带端口号故 修改协议为 http
|
||||
request.Headers.Host = uri.Host;
|
||||
request.RequestUri = new UriBuilder(uri) { Scheme = Uri.UriSchemeHttp }.Uri;
|
||||
//request.RequestUri = new UriBuilder(uri) { Scheme = Uri.UriSchemeHttp }.Uri;
|
||||
|
||||
if (domainConfig.Timeout != null)
|
||||
{
|
||||
@@ -61,6 +61,7 @@ sealed class ReverseProxyHttpClientHandler : DelegatingHandler
|
||||
AutomaticDecompression = DecompressionMethods.None,
|
||||
ConnectCallback = ConnectCallback,
|
||||
EnableMultipleHttp2Connections = true,
|
||||
EnableMultipleHttp3Connections = true,
|
||||
RequestHeaderEncodingSelector = (_, _) => Encoding.UTF8,
|
||||
ResponseHeaderEncodingSelector = (_, _) => Encoding.UTF8,
|
||||
};
|
||||
|
||||
+36
-15
@@ -2,6 +2,7 @@
|
||||
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Yarp.ReverseProxy.Forwarder;
|
||||
using HttpVersion = System.Net.HttpVersion;
|
||||
|
||||
// ReSharper disable once CheckNamespace
|
||||
namespace BD.WTTS.Services.Implementation;
|
||||
@@ -30,6 +31,27 @@ sealed partial class HttpReverseProxyMiddleware
|
||||
this.logger = logger;
|
||||
}
|
||||
|
||||
static ArgumentOutOfRangeException GetUnknownHttpVersionException(string? actualValue, [CallerArgumentExpression(nameof(actualValue))] string? paramName = null) => new(
|
||||
$"""
|
||||
Version doesn't map to a known HTTP protocol. (Parameter '{paramName}')
|
||||
Actual value was {actualValue}.
|
||||
""");
|
||||
|
||||
static Version GetHttpVersion(string requestProtocol) =>
|
||||
(requestProtocol != null && requestProtocol.Length >= 6) ? requestProtocol[5] switch
|
||||
{
|
||||
// 参考 Microsoft.AspNetCore.Http.HttpProtocol.GetHttpProtocol
|
||||
'1' => requestProtocol.Length >= 8 ? requestProtocol[7] switch
|
||||
{
|
||||
'0' => HttpVersion.Version10,
|
||||
'1' => HttpVersion.Version11,
|
||||
_ => throw GetUnknownHttpVersionException(requestProtocol),
|
||||
} : throw GetUnknownHttpVersionException(requestProtocol),
|
||||
'2' => HttpVersion.Version20,
|
||||
'3' => HttpVersion.Version30,
|
||||
_ => throw GetUnknownHttpVersionException(requestProtocol),
|
||||
} : throw GetUnknownHttpVersionException(requestProtocol);
|
||||
|
||||
/// <summary>
|
||||
/// 处理请求
|
||||
/// </summary>
|
||||
@@ -60,12 +82,7 @@ sealed partial class HttpReverseProxyMiddleware
|
||||
var destinationPrefix = GetDestinationPrefix(context.Request.Scheme, context.Request.Host, null);
|
||||
var forwarderRequestConfig = new ForwarderRequestConfig()
|
||||
{
|
||||
Version = context.Request.Protocol switch
|
||||
{
|
||||
var protocol when protocol.StartsWith("HTTP/2") => System.Net.HttpVersion.Version20,
|
||||
var protocol when protocol.StartsWith("HTTP/3") => System.Net.HttpVersion.Version30,
|
||||
_ => System.Net.HttpVersion.Version11,
|
||||
},
|
||||
Version = GetHttpVersion(context.Request.Protocol),
|
||||
};
|
||||
var error = await httpForwarder.SendAsync(context, destinationPrefix, httpClient, forwarderRequestConfig, HttpTransformer.Empty);
|
||||
if (error != ForwarderError.None)
|
||||
@@ -119,19 +136,23 @@ sealed partial class HttpReverseProxyMiddleware
|
||||
context.Request.Headers.UserAgent = domainConfig.UserAgent.Replace("${origin}", context.Request.Headers.UserAgent, StringComparison.OrdinalIgnoreCase);
|
||||
}
|
||||
|
||||
var forwarderRequestConfig = new ForwarderRequestConfig()
|
||||
{
|
||||
Version = context.Request.Protocol switch
|
||||
{
|
||||
var protocol when protocol.StartsWith("HTTP/2") => System.Net.HttpVersion.Version20,
|
||||
var protocol when protocol.StartsWith("HTTP/3") => System.Net.HttpVersion.Version30,
|
||||
_ => System.Net.HttpVersion.Version11,
|
||||
},
|
||||
};
|
||||
ForwarderRequestConfig forwarderRequestConfig;
|
||||
|
||||
if (domainConfig.IsServerSideProxy)
|
||||
{
|
||||
SetWattHeaders(context, reverseProxyConfig.Service.ServerSideProxyToken);
|
||||
forwarderRequestConfig = new ForwarderRequestConfig()
|
||||
{
|
||||
Version = HttpVersion.Version30,
|
||||
VersionPolicy = HttpVersionPolicy.RequestVersionOrLower
|
||||
};
|
||||
}
|
||||
else
|
||||
{
|
||||
forwarderRequestConfig = new ForwarderRequestConfig()
|
||||
{
|
||||
Version = GetHttpVersion(context.Request.Protocol),
|
||||
};
|
||||
}
|
||||
|
||||
var error = await httpForwarder.SendAsync(context, destinationPrefix, httpClient, forwarderRequestConfig, HttpTransformer.Empty);
|
||||
|
||||
+83
-21
@@ -48,26 +48,41 @@ sealed partial class YarpReverseProxyServiceImpl : ReverseProxyServiceImpl, IRev
|
||||
platformService,
|
||||
CertificateManager);
|
||||
|
||||
X509Certificate2? cer = CertificateManager.RootCertificatePackable;
|
||||
if (cer is not null && DateTime.Now <= cer.NotAfter && cer.NotAfter <= DateTime.Now.AddMonths(1))
|
||||
try
|
||||
{
|
||||
var interval = cer.NotAfter - DateTime.Now;
|
||||
|
||||
_certificateTimer = new System.Timers.Timer(interval)
|
||||
X509Certificate2? cer = CertificateManager.RootCertificatePackable;
|
||||
if (cer is not null &&
|
||||
DateTime.Now <= cer.NotAfter && cer.NotAfter <= DateTime.Now.AddMilliseconds(int.MaxValue))
|
||||
{
|
||||
AutoReset = false,
|
||||
};
|
||||
var interval = cer.NotAfter - DateTime.Now;
|
||||
|
||||
_certificateTimer.Elapsed += async (_, _) =>
|
||||
{
|
||||
ICertificateManager.Constants.CheckRootCertificate(
|
||||
platformService,
|
||||
CertificateManager);
|
||||
_certificateTimer = new System.Timers.Timer(interval)
|
||||
{
|
||||
AutoReset = false,
|
||||
};
|
||||
|
||||
await StopProxyAsync();
|
||||
await StartProxyImpl();
|
||||
};
|
||||
_certificateTimer.Start();
|
||||
_certificateTimer.Elapsed += async (_, _) =>
|
||||
{
|
||||
try
|
||||
{
|
||||
ICertificateManager.Constants.CheckRootCertificate(
|
||||
platformService,
|
||||
CertificateManager);
|
||||
|
||||
await StopProxyAsync();
|
||||
await StartProxyImpl();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
e.LogAndShowT(TAG, msg: "CheckRootCertificate in Timer.Elapsed Error");
|
||||
}
|
||||
};
|
||||
_certificateTimer.Start();
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
e.LogAndShowT(TAG, msg: "CheckRootCertificate Error");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -83,8 +98,58 @@ sealed partial class YarpReverseProxyServiceImpl : ReverseProxyServiceImpl, IRev
|
||||
|
||||
protected override Task<StartProxyResult> StartProxyImpl() => Task.FromResult(StartProxyCore());
|
||||
|
||||
readonly string[] allowedHosts = ["*",];
|
||||
|
||||
#if WINDOWS
|
||||
/// <summary>
|
||||
/// https://learn.microsoft.com/zh-cn/dotnet/core/extensions/globalization-icu#determine-if-your-app-is-using-icu
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
static bool ICUMode()
|
||||
{
|
||||
SortVersion sortVersion = CultureInfo.InvariantCulture.CompareInfo.Version;
|
||||
byte[] bytes = sortVersion.SortId.ToByteArray();
|
||||
int version = bytes[3] << 24 | bytes[2] << 16 | bytes[1] << 8 | bytes[0];
|
||||
return version != 0 && version == sortVersion.FullVersion;
|
||||
}
|
||||
|
||||
static bool IcuTest(IEnumerable<string> incoming)
|
||||
{
|
||||
if (!OperatingSystem.IsWindowsVersionAtLeast(10, 0, 18362) && ICUMode())
|
||||
{
|
||||
// https://learn.microsoft.com/zh-cn/dotnet/core/extensions/globalization-icu#icu-on-windows
|
||||
// 与 .NET 6 和 .NET 5 相比,.NET 7 及更高版本能够在早期 Windows 版本上加载 ICU
|
||||
// 通常问题出在 1703 ~ 1903 之间的 Windows 版本
|
||||
try
|
||||
{
|
||||
// https://github.com/dotnet/aspnetcore/blob/v9.0.2/src/Middleware/HostFiltering/src/MiddlewareConfigurationManager.cs#L67
|
||||
foreach (var entry in incoming)
|
||||
{
|
||||
// Punycode. Http.Sys requires you to register Unicode hosts, but the headers contain punycode.
|
||||
var host = new HostString(entry).ToUriComponent();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
catch
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
StartProxyResult StartProxyCore()
|
||||
{
|
||||
#if WINDOWS
|
||||
if (!IcuTest(allowedHosts))
|
||||
{
|
||||
return StartProxyResultCode.IcuTestFail;
|
||||
}
|
||||
#endif
|
||||
// https://github.com/dotnetcore/FastGithub/blob/2.1.4/FastGithub/Program.cs#L29
|
||||
try
|
||||
{
|
||||
@@ -98,13 +163,10 @@ sealed partial class YarpReverseProxyServiceImpl : ReverseProxyServiceImpl, IRev
|
||||
|
||||
builder.Logging.AddProvider(new LogConsoleService.Utf8StringLoggerProvider(AssemblyInfo.Accelerator));
|
||||
|
||||
builder.Services.Configure<HostFilteringOptions>(static o =>
|
||||
builder.Services.Configure<HostFilteringOptions>(o =>
|
||||
{
|
||||
o.AllowEmptyHosts = true;
|
||||
o.AllowedHosts = new List<string>
|
||||
{
|
||||
"*",
|
||||
};
|
||||
o.AllowedHosts = allowedHosts;
|
||||
});
|
||||
|
||||
builder.Host.UseNLog();
|
||||
|
||||
+6
@@ -341,6 +341,12 @@ public enum StartProxyResultCode : byte
|
||||
/// 绑定端口错误
|
||||
/// </summary>
|
||||
BindPortError,
|
||||
|
||||
/// <summary>
|
||||
/// 早期 Windows 版本且缺少 Windows 更新补丁,Icu 存在 Bug 导致,要么更新操作系统,要么更改配置使用 NLS 重启程序
|
||||
/// <para>https://learn.microsoft.com/zh-cn/dotnet/core/extensions/globalization-icu#use-nls-instead-of-icu</para>
|
||||
/// </summary>
|
||||
IcuTestFail = 127, // 值与 Mobius 保持一致
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
+8
-11
@@ -9,7 +9,7 @@ internal partial class NetworkTestService : INetworkTestService
|
||||
#region 常量
|
||||
|
||||
// 默认测试地址
|
||||
const string DEFAULT_TESTSERVER_HOSTNAME = "stun.syncthing.net";
|
||||
internal const string DEFAULT_TESTSERVER_HOSTNAME = "stun.miwifi.com";
|
||||
|
||||
const int DEFAULT_PORT = 3478;
|
||||
const int DEFAULT_TLSPORT = 5349;
|
||||
@@ -202,8 +202,6 @@ internal partial class NetworkTestService : INetworkTestService
|
||||
|
||||
#region RFC3489
|
||||
|
||||
StunClient3489? _stunClient;
|
||||
|
||||
/// <summary>
|
||||
/// 测试 STUN 客户端 基于 RFC3489
|
||||
/// </summary>
|
||||
@@ -217,19 +215,17 @@ internal partial class NetworkTestService : INetworkTestService
|
||||
string? testServerHostName = DEFAULT_TESTSERVER_HOSTNAME,
|
||||
int? testServerPort = DEFAULT_TESTSTUN3489_PORT,
|
||||
IPEndPoint? localIPEndPoint = null,
|
||||
bool force = false,
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
{
|
||||
testServerHostName ??= DEFAULT_TESTSERVER_HOSTNAME;
|
||||
testServerPort ??= DEFAULT_TESTSTUN3489_PORT;
|
||||
|
||||
if (_stunClient == null || force)
|
||||
_stunClient = await GetStunClient3489Async(testServerHostName, testServerPort.Value, localIPEndPoint);
|
||||
using var stunClient = await GetStunClient3489Async(testServerHostName, testServerPort.Value, localIPEndPoint);
|
||||
|
||||
try
|
||||
{
|
||||
await _stunClient.QueryAsync(cancellationToken);
|
||||
await stunClient.QueryAsync(cancellationToken);
|
||||
}
|
||||
catch (OperationCanceledException) { throw; }
|
||||
catch (Exception ex)
|
||||
@@ -238,7 +234,7 @@ internal partial class NetworkTestService : INetworkTestService
|
||||
return null;
|
||||
}
|
||||
|
||||
return _stunClient.State;
|
||||
return stunClient.State;
|
||||
}
|
||||
|
||||
private async ValueTask<StunClient3489> GetStunClient3489Async(string serverHostName, int port, IPEndPoint? localIPEndPoint = null)
|
||||
@@ -289,7 +285,7 @@ internal partial class NetworkTestService : INetworkTestService
|
||||
testServerHostName ??= DEFAULT_TESTSERVER_HOSTNAME;
|
||||
testServerPort ??= DEFAULT_TESTSTUN5389_PORT;
|
||||
|
||||
IStunClient5389 client = await GetStunClient5389Async(protocol, testServerHostName, testServerPort.Value, localIPEndPoint);
|
||||
using var client = await GetStunClient5389Async(protocol, testServerHostName, testServerPort.Value, localIPEndPoint);
|
||||
|
||||
if (client == null)
|
||||
return null;
|
||||
@@ -345,7 +341,8 @@ internal partial class NetworkTestService : INetworkTestService
|
||||
)
|
||||
{
|
||||
using UdpClient udpClient = new UdpClient(dnsServerIp, dnsServerPort);
|
||||
|
||||
udpClient.Client.SendTimeout = 3000;
|
||||
udpClient.Client.ReceiveTimeout = 3000;
|
||||
var query = new DnsQueryUdpRequest(testDomain, dnsRecordType);
|
||||
|
||||
Stopwatch watch = Stopwatch.StartNew();
|
||||
@@ -382,7 +379,7 @@ internal partial class NetworkTestService : INetworkTestService
|
||||
Proxy = HttpNoProxy.Instance,
|
||||
};
|
||||
using HttpClient client = new HttpClient(handler);
|
||||
|
||||
client.Timeout = TimeSpan.FromSeconds(3);
|
||||
string queryUrl = $"{dohServer}?name={testDomain}&type={dnsRecordType}";
|
||||
|
||||
Stopwatch watch = Stopwatch.StartNew();
|
||||
|
||||
@@ -91,14 +91,12 @@ internal interface IStunTestService
|
||||
/// <param name="testServerHostName">STUN 服务地址</param>
|
||||
/// <param name="testServerPort">STUN 服务端口</param>
|
||||
/// <param name="localIPEndPoint">本机IP</param>
|
||||
/// <param name="force">刷新测试 Client</param>
|
||||
/// <remarks></remarks>
|
||||
/// <returns></returns>
|
||||
Task<ClassicStunResult?> TestStunClient3489Async(
|
||||
string? testServerHostName = default,
|
||||
int? testServerPort = default,
|
||||
IPEndPoint? localIPEndPoint = default,
|
||||
bool force = false,
|
||||
CancellationToken cancellationToken = default
|
||||
);
|
||||
|
||||
|
||||
@@ -307,6 +307,7 @@ public sealed partial class GameAcceleratorService
|
||||
Games.AddOrUpdate(CurrentAcceleratorGame);
|
||||
|
||||
//加速后
|
||||
TracepointHelper.TrackEvent("AcceleratorGameSuccess");
|
||||
Toast.Show(ToastIcon.Success, "加速成功");
|
||||
if (ProxySettings.AutoShowWattAcceleratorWindow.Value)
|
||||
{
|
||||
@@ -630,42 +631,7 @@ public sealed partial class GameAcceleratorService
|
||||
|
||||
td.Opened += async (s, e) =>
|
||||
{
|
||||
await foreach (var item in install)
|
||||
{
|
||||
if (item.HandleUI(out var content))
|
||||
{
|
||||
switch (content)
|
||||
{
|
||||
case < 100:
|
||||
Dispatcher.UIThread.Post(() => { td.Content = $"正在下载 {item.Content}%"; });
|
||||
td.SetProgressBarState(item.Content, TaskDialogProgressState.Normal);
|
||||
break;
|
||||
case 100:
|
||||
td.SetProgressBarState(item.Content, TaskDialogProgressState.Indeterminate);
|
||||
Dispatcher.UIThread.Post(() => { td.Content = $"下载完成,正在安装..."; });
|
||||
break;
|
||||
case (int)XunYouDownLoadCode.安装成功:
|
||||
//处理成功
|
||||
//Dispatcher.UIThread.Post(() => { td.Content = $"安装完成"; });
|
||||
Dispatcher.UIThread.Post(() => { td.Hide(TaskDialogStandardResult.OK); });
|
||||
td.Hide();
|
||||
break;
|
||||
case int n when n > 101 && n < (int)XunYouDownLoadCode.启动安装程序失败:
|
||||
//处理失败
|
||||
break;
|
||||
// Code 和进度重叠 递进 1000 XunYouInstallOrStartCode.默认 XunYouInstallOrStartCode.已安装
|
||||
case 1000:
|
||||
Dispatcher.UIThread.Post(() => { td.Content = $"默认"; });
|
||||
// XunYouInstallOrStartCode.默认
|
||||
break;
|
||||
case 1001:
|
||||
Dispatcher.UIThread.Post(() => { td.Content = $"已安装"; });
|
||||
// XunYouInstallOrStartCode.已安装
|
||||
Dispatcher.UIThread.Post(() => { td.Hide(TaskDialogStandardResult.OK); });
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
await DownloadCallbackAsync(td, install);
|
||||
};
|
||||
|
||||
//_ = Task.Run(() => { XunYouSDK.InstallAsync(progress, Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles), "WattAccelerator")); });
|
||||
@@ -674,6 +640,47 @@ public sealed partial class GameAcceleratorService
|
||||
}
|
||||
}
|
||||
|
||||
private static async Task DownloadCallbackAsync(TaskDialog td, IAsyncEnumerable<ApiRsp<int>> install)
|
||||
{
|
||||
await foreach (var item in install)
|
||||
{
|
||||
if (item.HandleUI(out var content))
|
||||
{
|
||||
switch (content)
|
||||
{
|
||||
case < 100:
|
||||
Dispatcher.UIThread.Post(() => { td.Content = $"正在下载 {item.Content}%"; });
|
||||
td.SetProgressBarState(item.Content, TaskDialogProgressState.Normal);
|
||||
break;
|
||||
case 100:
|
||||
td.SetProgressBarState(item.Content, TaskDialogProgressState.Indeterminate);
|
||||
Dispatcher.UIThread.Post(() => { td.Content = $"下载完成,正在安装..."; });
|
||||
break;
|
||||
case (int)XunYouDownLoadCode.安装成功:
|
||||
//处理成功
|
||||
//Dispatcher.UIThread.Post(() => { td.Content = $"安装完成"; });
|
||||
TracepointHelper.TrackEvent("DownloadInstallSuccess");
|
||||
Dispatcher.UIThread.Post(() => { td.Hide(TaskDialogStandardResult.OK); });
|
||||
td.Hide();
|
||||
break;
|
||||
case int n when n > 101 && n < (int)XunYouDownLoadCode.启动安装程序失败:
|
||||
//处理失败
|
||||
break;
|
||||
// Code 和进度重叠 递进 1000 XunYouInstallOrStartCode.默认 XunYouInstallOrStartCode.已安装
|
||||
case 1000:
|
||||
Dispatcher.UIThread.Post(() => { td.Content = $"默认"; });
|
||||
// XunYouInstallOrStartCode.默认
|
||||
break;
|
||||
case 1001:
|
||||
Dispatcher.UIThread.Post(() => { td.Content = $"已安装"; });
|
||||
// XunYouInstallOrStartCode.已安装
|
||||
Dispatcher.UIThread.Post(() => { td.Hide(TaskDialogStandardResult.OK); });
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static async void UninstallAccelerator()
|
||||
{
|
||||
var xunYouIsInstall = await Ioc.Get<IAcceleratorService>().XY_IsInstall();
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
// ReSharper disable once CheckNamespace
|
||||
using BD.WTTS.Helpers;
|
||||
using BD.WTTS.Services.Implementation;
|
||||
|
||||
namespace BD.WTTS.Services;
|
||||
|
||||
@@ -73,6 +74,18 @@ partial class ProxyService
|
||||
bool useDoh = ProxySettings.UseDoh.Value;
|
||||
string? customDohAddres = ProxySettings.CustomDohAddres2.Value;
|
||||
|
||||
if (ProxySettings.ProxyBeforeDNSCheck.Value)
|
||||
{
|
||||
if (useDoh)
|
||||
{
|
||||
customDohAddres = await GetFastestDNSAsync(ProxySettingsWindowViewModel.DohAddress);
|
||||
}
|
||||
else
|
||||
{
|
||||
proxyDNS = await GetFastestDNSAsync(ProxySettingsWindowViewModel.ProxyDNSs.Skip(1));
|
||||
}
|
||||
}
|
||||
|
||||
Lazy<IPAddress> proxyIp_ = new(() => ReverseProxySettings.GetProxyIp(proxyIp));
|
||||
void SetProxyIp(IPAddress proxyIPAddress)
|
||||
{
|
||||
@@ -393,8 +406,10 @@ partial class ProxyService
|
||||
if (!string.IsNullOrEmpty(proxyTokenCache))
|
||||
return proxyTokenCache;
|
||||
|
||||
using CancellationTokenSource cts = new();
|
||||
cts.CancelAfter(TimeSpan.FromSeconds(4.99D)); // 5 秒超时
|
||||
var resp = await IMicroServiceClient.Instance.Account
|
||||
.GenerateServerSideProxyToken();
|
||||
.GenerateServerSideProxyToken(cts.Token);
|
||||
|
||||
if (resp != null && !string.IsNullOrEmpty(resp.Content?.AccessToken))
|
||||
{
|
||||
@@ -403,11 +418,14 @@ partial class ProxyService
|
||||
|
||||
return proxyTokenCache;
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
ex.LogAndShowT();
|
||||
return null;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -463,4 +481,69 @@ partial class ProxyService
|
||||
return proxyStatus;
|
||||
}
|
||||
}
|
||||
|
||||
async Task<(long delayMs, string dns)> GetValidDNSAsync(string dns, CancellationToken cancellationToken = default)
|
||||
{
|
||||
var testDomain = "dnscheck-test.steampp.net";
|
||||
try
|
||||
{
|
||||
long delayMs;
|
||||
IPAddress[] address;
|
||||
if (ProxySettings.UseDoh.Value)
|
||||
{
|
||||
(delayMs, address) = await INetworkTestService.Instance.TestDNSOverHttpsAsync(testDomain, dns, cancellationToken: cancellationToken);
|
||||
}
|
||||
else
|
||||
{
|
||||
(delayMs, address) = await INetworkTestService.Instance.TestDNSAsync(testDomain, dns, 53, cancellationToken: cancellationToken);
|
||||
}
|
||||
if (address.Length == 0)
|
||||
throw new Exception("Parsing failed. Return empty ip address.");
|
||||
|
||||
return (delayMs, dns);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.Error(nameof(StartOrStopProxyService), ex.ToString(), "DNS检测出错");
|
||||
return (0, dns);
|
||||
}
|
||||
}
|
||||
|
||||
async Task<string?> GetFastestDNSAsync(IEnumerable<string> dnsAddresses, CancellationToken cancellationToken = default)
|
||||
{
|
||||
var cts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken);
|
||||
var tasks = new List<Task<(long delayMs, string dns)>>();
|
||||
|
||||
foreach (var dns in dnsAddresses)
|
||||
{
|
||||
tasks.Add(GetValidDNSAsync(dns, cts.Token));
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
// 等待任意一个任务完成
|
||||
var completedTask = await Task.WhenAny(tasks);
|
||||
|
||||
// 获取任务结果
|
||||
var (delayMs, dns) = await completedTask;
|
||||
_ = cts.CancelAsync(); // 取消其他任务
|
||||
|
||||
// 如果任务成功完成(假设 delayMs > 0 表示成功)
|
||||
if (delayMs > 0)
|
||||
{
|
||||
return dns; // 返回第一个成功的 DNS 地址
|
||||
}
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
// 任务被取消,忽略
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.Error(nameof(StartOrStopProxyService), ex.ToString(), "DNS检测出错");
|
||||
}
|
||||
|
||||
// 如果没有有效结果,返回默认值
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -163,8 +163,35 @@ public sealed partial class ProxyService
|
||||
return [];
|
||||
var data = ProxyDomains.Items
|
||||
.Where(x => x.Items != null)
|
||||
.SelectMany(s => s.Items!.Where(w => w.ThreeStateEnable != false));
|
||||
//return data.Concat(data.SelectMany(s => GetProxyDomainsItems(s)));
|
||||
.SelectMany(s => s.Items!.Where(w => w.ThreeStateEnable != false))
|
||||
.Select(item =>
|
||||
{
|
||||
//过滤部分选中的子项
|
||||
if (item.Items.Any_Nullable())
|
||||
{
|
||||
return new AccelerateProjectDTO
|
||||
{
|
||||
Name = item.Name,
|
||||
Port = item.Port,
|
||||
MatchDomainNames = item.MatchDomainNames,
|
||||
ForwardDomainNames = item.ForwardDomainNames,
|
||||
IgnoreSSLCertVerification = item.IgnoreSSLCertVerification,
|
||||
FakeServerName = item.FakeServerName,
|
||||
ProxyType = item.ProxyType,
|
||||
ListenDomainNames = item.ListenDomainNames,
|
||||
Checked = item.Checked,
|
||||
Id = item.Id,
|
||||
Order = item.Order,
|
||||
FakeUserAgent = item.FakeUserAgent,
|
||||
Version = item.Version,
|
||||
ThreeStateEnable = item.ThreeStateEnable,
|
||||
// 递归过滤子项
|
||||
Items = item.Items.Where(x => x.ThreeStateEnable != false).ToList()
|
||||
};
|
||||
}
|
||||
return item;
|
||||
});
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
|
||||
@@ -165,6 +165,11 @@ public partial interface IProxySettings
|
||||
/// </summary>
|
||||
bool AutoShowWattAcceleratorWindow { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 加速前进行 DNS 可用性检查
|
||||
/// </summary>
|
||||
bool ProxyBeforeDNSCheck { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 启用脚本自动检查更新的默认值
|
||||
/// </summary>
|
||||
@@ -290,4 +295,9 @@ public partial interface IProxySettings
|
||||
/// </summary>
|
||||
const bool DefaultAutoShowWattAcceleratorWindow = true;
|
||||
|
||||
/// <summary>
|
||||
/// 加速前进行 DNS 可用性检查的默认值
|
||||
/// </summary>
|
||||
const bool DefaultProxyBeforeDNSCheck = true;
|
||||
|
||||
}
|
||||
|
||||
@@ -209,6 +209,12 @@ public sealed partial class ProxySettings_ : IProxySettings, ISettings, ISetting
|
||||
[MPKey(24), MP2Key(24), JsonPropertyOrder(24)]
|
||||
public bool AutoShowWattAcceleratorWindow { get; set; } = IProxySettings.DefaultAutoShowWattAcceleratorWindow;
|
||||
|
||||
/// <summary>
|
||||
/// 加速前进行 DNS 可用性检查
|
||||
/// </summary>
|
||||
[MPKey(25), MP2Key(25), JsonPropertyOrder(25)]
|
||||
public bool ProxyBeforeDNSCheck { get; set; } = IProxySettings.DefaultProxyBeforeDNSCheck;
|
||||
|
||||
}
|
||||
|
||||
public static partial class ProxySettings
|
||||
@@ -383,4 +389,10 @@ public static partial class ProxySettings
|
||||
public static SettingsStructProperty<bool, ProxySettings_> AutoShowWattAcceleratorWindow { get; }
|
||||
= new(DefaultAutoShowWattAcceleratorWindow);
|
||||
|
||||
/// <summary>
|
||||
/// 加速前进行 DNS 可用性检查
|
||||
/// </summary>
|
||||
public static SettingsStructProperty<bool, ProxySettings_> ProxyBeforeDNSCheck { get; }
|
||||
= new(DefaultProxyBeforeDNSCheck);
|
||||
|
||||
}
|
||||
|
||||
@@ -21,16 +21,17 @@ public sealed partial class AcceleratorPageViewModel
|
||||
{
|
||||
// Create new ProxyEnableDomain for 加速服务 page
|
||||
var enableGroupDomain = ProxyService.Current.ProxyDomainsList
|
||||
.Where(list => list.ThreeStateEnable == true || list.ThreeStateEnable == null)
|
||||
.Where(list => list.ThreeStateEnable != false)
|
||||
.Select(list => new ProxyDomainGroupViewModel
|
||||
{
|
||||
Name = list.Name,
|
||||
IconUrl = list.IconUrl ?? string.Empty,
|
||||
EnableProxyDomainVMs = new(
|
||||
list.Items!
|
||||
.Where(i => i.ThreeStateEnable == true)
|
||||
.Where(i => i.ThreeStateEnable != false)
|
||||
.Select(i => new ProxyDomainViewModel(i.Name, i.ProxyType, "https://" + i.ListenDomainNames.Split(";")[0],
|
||||
i.Items?
|
||||
.Where(x => x.ThreeStateEnable != false)
|
||||
.Select(c => new ProxyDomainViewModel(c.Name, c.ProxyType, "https://" + c.ListenDomainNames.Split(';')[0]))
|
||||
.ToList()))
|
||||
.ToList()),
|
||||
|
||||
+1
-1
@@ -4,7 +4,7 @@ namespace BD.WTTS.UI.ViewModels;
|
||||
|
||||
public sealed partial class AcceleratorPageViewModel : TabItemViewModel
|
||||
{
|
||||
public override string Name => Strings.Welcome;
|
||||
public override string Name => Strings.CommunityFix;
|
||||
|
||||
[Reactive]
|
||||
public ReadOnlyCollection<ProxyDomainGroupViewModel>? EnableProxyDomainGroupVMs { get; set; }
|
||||
|
||||
+1
-1
@@ -2,7 +2,7 @@ namespace BD.WTTS.UI.ViewModels;
|
||||
|
||||
public sealed partial class GameAcceleratorPageViewModel : TabItemViewModel
|
||||
{
|
||||
public override string Name => Strings.Welcome;
|
||||
public override string Name => Strings.GameAccelerator;
|
||||
|
||||
private readonly ReadOnlyObservableCollection<XunYouGameViewModel>? _Games;
|
||||
|
||||
|
||||
+69
-54
@@ -31,10 +31,9 @@ public partial class NetworkCheckControlViewModel : ViewModelBase
|
||||
|
||||
public string[] STUNAddress { get; } =
|
||||
[
|
||||
"stun.syncthing.net",
|
||||
NetworkTestService.DEFAULT_TESTSERVER_HOSTNAME,
|
||||
"stun.hot-chilli.net",
|
||||
"stun.fitauto.ru",
|
||||
"stun.miwifi.com",
|
||||
];
|
||||
|
||||
[ObservableAsProperty]
|
||||
@@ -90,28 +89,7 @@ public partial class NetworkCheckControlViewModel : ViewModelBase
|
||||
{
|
||||
SelectedSTUNAddress = STUNAddress[0];
|
||||
|
||||
NATCheckCommand = ReactiveCommand.CreateFromTask(async () =>
|
||||
{
|
||||
var natCheckResult = await _networkTestService.TestStunClient3489Async(testServerHostName: SelectedSTUNAddress) ?? new ClassicStunResult { NatType = NatType.Unknown };
|
||||
var (netSucc, _) = await _networkTestService.TestOpenUrlAsync("https://www.baidu.com");
|
||||
|
||||
var publicEndPoint = natCheckResult.PublicEndPoint?.Address.ToString() ?? "Unknown";
|
||||
var localEndPoint = natCheckResult.LocalEndPoint?.Address.ToString() ?? "Unknown";
|
||||
|
||||
var (natLevel, natTypeTip) = natCheckResult.NatType switch
|
||||
{
|
||||
// Open
|
||||
NatType.OpenInternet or NatType.FullCone => ("开放 NAT", "您可与在其网络上具有任意 NAT 类型的用户玩多人游戏和发起多人游戏。"),
|
||||
// Moderate
|
||||
NatType.RestrictedCone or NatType.PortRestrictedCone or NatType.SymmetricUdpFirewall => ("中等 NAT", "您可与一些用户玩多人游戏;但是,并且通常你将不会被选为比赛的主持人。"),
|
||||
// Strict
|
||||
NatType.Symmetric or NatType.UdpBlocked => ("严格 NAT", "您只能与具有开放 NAT 类型的用户玩多人游戏。您不能被选为比赛的主持人。"),
|
||||
// Unknown
|
||||
NatType.Unknown or NatType.UnsupportedServer or _ => ("不可用 NAT", "如果 NAT 不可用,您将无法使用群聊天或连接到某些 Xbox 游戏的多人游戏。"),
|
||||
};
|
||||
|
||||
return new NATFetchResult(publicEndPoint, localEndPoint, natLevel, natTypeTip, netSucc);
|
||||
});
|
||||
NATCheckCommand = ReactiveCommand.CreateFromTask(NATCheckAsync);
|
||||
NATCheckCommand
|
||||
.IsExecuting
|
||||
.ToPropertyEx(this, x => x.IsNATChecking);
|
||||
@@ -145,36 +123,7 @@ public partial class NetworkCheckControlViewModel : ViewModelBase
|
||||
|
||||
var canDNSCheck = this.WhenAnyValue(x => x.DomainPendingTest)
|
||||
.Select(domain => domain == string.Empty || DomainRegExp().IsMatch(domain));
|
||||
DNSCheckCommand = ReactiveCommand.CreateFromTask(async () =>
|
||||
{
|
||||
var testDomain = DomainPendingTest == string.Empty ? DefaultTestDomain : DomainPendingTest;
|
||||
try
|
||||
{
|
||||
long delayMs;
|
||||
IPAddress[] address;
|
||||
if (ProxySettings.UseDoh)
|
||||
{
|
||||
var configDoh = ProxySettings.CustomDohAddres2.Value ?? ProxySettingsWindowViewModel.DohAddress.FirstOrDefault() ?? string.Empty;
|
||||
(delayMs, address) = await _networkTestService.TestDNSOverHttpsAsync(testDomain, configDoh);
|
||||
}
|
||||
else
|
||||
{
|
||||
var configDns = ProxySettings.ProxyMasterDns.Value ?? string.Empty;
|
||||
(delayMs, address) = await _networkTestService.TestDNSAsync(testDomain, configDns, 53);
|
||||
}
|
||||
if (address.Length == 0)
|
||||
throw new Exception("Parsing failed. Return empty ip address.");
|
||||
|
||||
DNSTestDelay = delayMs + "ms ";
|
||||
DNSTestResult = string.Empty + address.FirstOrDefault();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.Error(nameof(AcceleratorPageViewModel), ex.ToString());
|
||||
DNSTestDelay = string.Empty;
|
||||
DNSTestResult = "error";
|
||||
}
|
||||
}, canDNSCheck);
|
||||
DNSCheckCommand = ReactiveCommand.CreateFromTask(DNSCheckAsync, canDNSCheck);
|
||||
DNSCheckCommand
|
||||
.IsExecuting
|
||||
.ToPropertyEx(this, x => x.IsDNSChecking);
|
||||
@@ -199,4 +148,70 @@ public partial class NetworkCheckControlViewModel : ViewModelBase
|
||||
|
||||
IPv6CheckCommand.Execute().Subscribe();
|
||||
}
|
||||
|
||||
async Task<NATFetchResult> NATCheckAsync()
|
||||
{
|
||||
try
|
||||
{
|
||||
return await NATCheckCoreAsync();
|
||||
}
|
||||
catch
|
||||
{
|
||||
return new("", "", "", "", false);
|
||||
}
|
||||
}
|
||||
|
||||
async Task<NATFetchResult> NATCheckCoreAsync()
|
||||
{
|
||||
var natCheckResult = await _networkTestService.TestStunClient3489Async(testServerHostName: SelectedSTUNAddress) ?? new ClassicStunResult { NatType = NatType.Unknown };
|
||||
var (netSucc, _) = await _networkTestService.TestOpenUrlAsync("https://www.baidu.com");
|
||||
|
||||
var publicEndPoint = natCheckResult.PublicEndPoint?.Address.ToString() ?? "Unknown";
|
||||
var localEndPoint = natCheckResult.LocalEndPoint?.Address.ToString() ?? "Unknown";
|
||||
|
||||
var (natLevel, natTypeTip) = natCheckResult.NatType switch
|
||||
{
|
||||
// Open
|
||||
NatType.OpenInternet or NatType.FullCone => ("开放 NAT", "您可与在其网络上具有任意 NAT 类型的用户玩多人游戏和发起多人游戏。"),
|
||||
// Moderate
|
||||
NatType.RestrictedCone or NatType.PortRestrictedCone or NatType.SymmetricUdpFirewall => ("中等 NAT", "您可与一些用户玩多人游戏;但是,并且通常你将不会被选为比赛的主持人。"),
|
||||
// Strict
|
||||
NatType.Symmetric or NatType.UdpBlocked => ("严格 NAT", "您只能与具有开放 NAT 类型的用户玩多人游戏。您不能被选为比赛的主持人。"),
|
||||
// Unknown
|
||||
NatType.Unknown or NatType.UnsupportedServer or _ => ("不可用 NAT", "如果 NAT 不可用,您将无法使用群聊天或连接到某些 Xbox 游戏的多人游戏。"),
|
||||
};
|
||||
|
||||
return new NATFetchResult(publicEndPoint, localEndPoint, natLevel, natTypeTip, netSucc);
|
||||
}
|
||||
|
||||
async Task DNSCheckAsync()
|
||||
{
|
||||
var testDomain = DomainPendingTest == string.Empty ? DefaultTestDomain : DomainPendingTest;
|
||||
try
|
||||
{
|
||||
long delayMs;
|
||||
IPAddress[] address;
|
||||
if (ProxySettings.UseDoh)
|
||||
{
|
||||
var configDoh = ProxySettings.CustomDohAddres2.Value ?? ProxySettingsWindowViewModel.DohAddress.FirstOrDefault() ?? string.Empty;
|
||||
(delayMs, address) = await _networkTestService.TestDNSOverHttpsAsync(testDomain, configDoh);
|
||||
}
|
||||
else
|
||||
{
|
||||
var configDns = ProxySettings.ProxyMasterDns.Value ?? string.Empty;
|
||||
(delayMs, address) = await _networkTestService.TestDNSAsync(testDomain, configDns, 53);
|
||||
}
|
||||
if (address.Length == 0)
|
||||
throw new Exception("Parsing failed. Return empty ip address.");
|
||||
|
||||
DNSTestDelay = delayMs + "ms ";
|
||||
DNSTestResult = string.Empty + address.FirstOrDefault();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.Error(nameof(AcceleratorPageViewModel), ex.ToString());
|
||||
DNSTestDelay = string.Empty;
|
||||
DNSTestResult = "error";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4,7 +4,7 @@ namespace BD.WTTS.UI.ViewModels;
|
||||
|
||||
public partial class ScriptPageViewModel : TabItemViewModel
|
||||
{
|
||||
public override string Name => Strings.Welcome;
|
||||
public override string Name => Strings.ScriptConfig;
|
||||
|
||||
protected readonly ReadOnlyObservableCollection<ScriptDTO>? _ProxyScripts;
|
||||
|
||||
|
||||
@@ -213,27 +213,31 @@
|
||||
Binding="{Binding PingValue}"
|
||||
ComparisonCondition="GreaterThan"
|
||||
Value="120">
|
||||
<ia:ChangePropertyAction
|
||||
PropertyName="Fill"
|
||||
TargetObject="PingEllipse"
|
||||
Value="#FF4F58" />
|
||||
<ia:ChangePropertyAction
|
||||
PropertyName="Foreground"
|
||||
TargetObject="PingText"
|
||||
Value="#FF4F58" />
|
||||
<ia:ChangePropertyAction PropertyName="Fill" TargetObject="PingEllipse">
|
||||
<ia:ChangePropertyAction.Value>
|
||||
<SolidColorBrush Color="#FF4F58" />
|
||||
</ia:ChangePropertyAction.Value>
|
||||
</ia:ChangePropertyAction>
|
||||
<ia:ChangePropertyAction PropertyName="Foreground" TargetObject="PingText">
|
||||
<ia:ChangePropertyAction.Value>
|
||||
<SolidColorBrush Color="#FF4F58" />
|
||||
</ia:ChangePropertyAction.Value>
|
||||
</ia:ChangePropertyAction>
|
||||
</ia:DataTriggerBehavior>
|
||||
<ia:DataTriggerBehavior
|
||||
Binding="{Binding PingValue}"
|
||||
ComparisonCondition="LessThanOrEqual"
|
||||
Value="120">
|
||||
<ia:ChangePropertyAction
|
||||
PropertyName="Fill"
|
||||
TargetObject="PingEllipse"
|
||||
Value="#47A42B" />
|
||||
<ia:ChangePropertyAction
|
||||
PropertyName="Foreground"
|
||||
TargetObject="PingText"
|
||||
Value="#47A42B" />
|
||||
<ia:ChangePropertyAction PropertyName="Fill" TargetObject="PingEllipse">
|
||||
<ia:ChangePropertyAction.Value>
|
||||
<SolidColorBrush Color="#47A42B" />
|
||||
</ia:ChangePropertyAction.Value>
|
||||
</ia:ChangePropertyAction>
|
||||
<ia:ChangePropertyAction PropertyName="Foreground" TargetObject="PingText">
|
||||
<ia:ChangePropertyAction.Value>
|
||||
<SolidColorBrush Color="#47A42B" />
|
||||
</ia:ChangePropertyAction.Value>
|
||||
</ia:ChangePropertyAction>
|
||||
</ia:DataTriggerBehavior>
|
||||
</i:Interaction.Behaviors>
|
||||
<TextBlock
|
||||
|
||||
@@ -88,6 +88,12 @@
|
||||
</ui:SettingsExpanderItem.Footer>
|
||||
</ui:SettingsExpanderItem>
|
||||
|
||||
<ui:SettingsExpanderItem>
|
||||
<TextBlock Text="启动加速时检查 DNS 可用性" />
|
||||
<ui:SettingsExpanderItem.Footer>
|
||||
<ToggleSwitch Classes="LeftContent" IsChecked="{Binding Source={x:Static ms:ProxySettings.ProxyBeforeDNSCheck}, Path=Value, Mode=TwoWay}" />
|
||||
</ui:SettingsExpanderItem.Footer>
|
||||
</ui:SettingsExpanderItem>
|
||||
<!--<DockPanel>
|
||||
<Label Content="自定义根证书密码"></Label>
|
||||
<TextBox></TextBox>
|
||||
@@ -98,7 +104,7 @@
|
||||
<Button Content="选择证书"/>
|
||||
</DockPanel>-->
|
||||
|
||||
<ui:SettingsExpanderItem Description="*该选项勾选后会导致程序的加速完全不生效,请确认是配合二级代理实现仅需要脚本功能后再启用">
|
||||
<ui:SettingsExpanderItem Description="*该选项勾选后会导致程序的加速失效,请确认是配合二级代理实现仅需要脚本功能后再启用">
|
||||
<TextBlock Text="{Binding Path=Res.CommunityFix_ProxyOnlyOnScript, Mode=OneWay, Source={x:Static s:ResourceService.Current}}" />
|
||||
<ui:SettingsExpanderItem.Footer>
|
||||
<ToggleSwitch Classes="LeftContent" IsChecked="{Binding Source={x:Static ms:ProxySettings.OnlyEnableProxyScript}, Path=Value, Mode=TwoWay}" />
|
||||
@@ -108,7 +114,7 @@
|
||||
|
||||
|
||||
<ui:SettingsExpander
|
||||
Description="*改动后需重启加速才能生效"
|
||||
Description="*请在有正确二级代理的情况下才考虑启用该选项,否则会导致程序的加速失效,改动后需重启加速才能生效"
|
||||
Header="{Binding Path=Res.Settings_Proxy_TwoLevelAgent, Mode=OneWay, Source={x:Static s:ResourceService.Current}}"
|
||||
IsExpanded="True">
|
||||
<ui:SettingsExpander.Footer>
|
||||
|
||||
+1
-1
@@ -2,7 +2,7 @@ using BD.WTTS.UI.Views.Controls;
|
||||
|
||||
namespace BD.WTTS.UI.ViewModels;
|
||||
|
||||
public sealed partial class ArchiSteamFarmPlusPageViewModel : ViewModelBase
|
||||
public sealed partial class ArchiSteamFarmPlusPageViewModel
|
||||
{
|
||||
|
||||
private readonly IArchiSteamFarmService asfService = IArchiSteamFarmService.Instance;
|
||||
|
||||
+3
-1
@@ -2,8 +2,10 @@ using ArchiSteamFarm.Steam;
|
||||
|
||||
namespace BD.WTTS.UI.ViewModels;
|
||||
|
||||
public sealed partial class ArchiSteamFarmPlusPageViewModel
|
||||
public sealed partial class ArchiSteamFarmPlusPageViewModel : TabItemViewModel
|
||||
{
|
||||
public override string Name => "ASF";
|
||||
|
||||
/// <summary>
|
||||
/// 选择 ASF 可执行文件路径
|
||||
/// </summary>
|
||||
|
||||
+1
-1
@@ -12,7 +12,7 @@ using BD.WTTS.UI.Views.Controls;
|
||||
|
||||
namespace BD.WTTS.UI.ViewModels;
|
||||
|
||||
public sealed partial class AuthenticatorHomePageViewModel : ViewModelBase
|
||||
public sealed partial class AuthenticatorHomePageViewModel
|
||||
{
|
||||
const int MAX_SYNC_VALUE = 100;
|
||||
|
||||
|
||||
+3
-1
@@ -2,8 +2,10 @@ using KeyValuePair = BD.Common.Entities.KeyValuePair;
|
||||
|
||||
namespace BD.WTTS.UI.ViewModels;
|
||||
|
||||
public partial class AuthenticatorHomePageViewModel
|
||||
public partial class AuthenticatorHomePageViewModel : TabItemViewModel
|
||||
{
|
||||
public override string Name => Strings.LocalAuth;
|
||||
|
||||
[Reactive]
|
||||
public bool IsLoading { get; set; }
|
||||
|
||||
|
||||
+1
-1
@@ -7,7 +7,7 @@ public sealed partial class GameAccountPageViewModel : TabItemViewModel
|
||||
{
|
||||
static readonly Uri PlatformsPath = new("avares://BD.WTTS.Client.Plugins.GameAccount/UI/Assets/Platforms.json");
|
||||
|
||||
public override string Name => Strings.Welcome;
|
||||
public override string Name => Strings.UserFastChange;
|
||||
|
||||
[Reactive]
|
||||
public ObservableCollection<PlatformAccount>? GamePlatforms { get; set; }
|
||||
|
||||
@@ -3,8 +3,6 @@
|
||||
xmlns="https://github.com/avaloniaui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:i="using:Avalonia.Xaml.Interactivity"
|
||||
xmlns:ia="using:Avalonia.Xaml.Interactions.Core"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:ms="https://steampp.net/settings"
|
||||
xmlns:s="https://steampp.net/services"
|
||||
@@ -190,7 +188,15 @@
|
||||
</spp:AppItem.ActionButton>-->
|
||||
<spp:AppItem.Image>
|
||||
<Panel x:Name="ItemImage">
|
||||
<i:Interaction.Behaviors>
|
||||
<Panel.Styles>
|
||||
<Style Selector="Panel#ItemBox">
|
||||
<Setter Property="Opacity" Value="0" />
|
||||
</Style>
|
||||
<Style Selector="Panel#ItemBox:pointerover">
|
||||
<Setter Property="Opacity" Value="0.8" />
|
||||
</Style>
|
||||
</Panel.Styles>
|
||||
<!--<i:Interaction.Behaviors>
|
||||
<ia:EventTriggerBehavior EventName="PointerEntered" SourceObject="{Binding #ItemImage}">
|
||||
<ia:ChangePropertyAction
|
||||
PropertyName="IsVisible"
|
||||
@@ -203,7 +209,7 @@
|
||||
TargetObject="{Binding #ItemBox}"
|
||||
Value="False" />
|
||||
</ia:EventTriggerBehavior>
|
||||
</i:Interaction.Behaviors>
|
||||
</i:Interaction.Behaviors>-->
|
||||
<Panel MinWidth="{Binding $parent[spp:AppItem].MinWidth}" MaxWidth="{Binding $parent[spp:AppItem].MaxWidth}">
|
||||
<spp:Image2
|
||||
Name="AppImage"
|
||||
@@ -247,11 +253,7 @@
|
||||
</DockPanel>
|
||||
</Border>
|
||||
</Panel>
|
||||
<Panel
|
||||
x:Name="ItemBox"
|
||||
Background="{DynamicResource SolidBackgroundFillColorBaseBrush}"
|
||||
IsVisible="False"
|
||||
Opacity="0.8">
|
||||
<Panel x:Name="ItemBox" Background="{DynamicResource SolidBackgroundFillColorBaseBrush}">
|
||||
<Button
|
||||
Padding="0"
|
||||
HorizontalAlignment="Center"
|
||||
|
||||
@@ -8,7 +8,7 @@ using BD.WTTS.Helpers;
|
||||
|
||||
namespace BD.WTTS.UI.ViewModels;
|
||||
|
||||
public sealed partial class IdleCardPageViewModel : ViewModelBase
|
||||
public sealed partial class IdleCardPageViewModel
|
||||
{
|
||||
readonly ISteamService SteamTool = ISteamService.Instance;
|
||||
readonly ISteamIdleCardService IdleCard = ISteamIdleCardService.Instance;
|
||||
|
||||
+3
-1
@@ -4,8 +4,10 @@ using BD.SteamClient.Services;
|
||||
|
||||
namespace BD.WTTS.UI.ViewModels;
|
||||
|
||||
public sealed partial class IdleCardPageViewModel
|
||||
public sealed partial class IdleCardPageViewModel : TabItemViewModel
|
||||
{
|
||||
public override string Name => Strings.SteamIdleCard;
|
||||
|
||||
/// <summary>
|
||||
/// 有限运行此游戏
|
||||
/// </summary>
|
||||
|
||||
+3
-2
@@ -26,7 +26,7 @@ public sealed partial class IdleSteamLoginPageViewModel : WindowViewModel
|
||||
{
|
||||
IsLoading = true;
|
||||
|
||||
if (SteamLoginState.SteamId == 0)
|
||||
if (!Requires2FA && !RequiresEmailAuth)
|
||||
{
|
||||
SteamLoginState.Username = UserNameText;
|
||||
SteamLoginState.Password = PasswordText;
|
||||
@@ -65,9 +65,10 @@ public sealed partial class IdleSteamLoginPageViewModel : WindowViewModel
|
||||
}
|
||||
else if (SteamLoginState.Message != null)
|
||||
{
|
||||
IsLoading = false;
|
||||
Toast.Show(ToastIcon.Warning, SteamLoginState.Message);
|
||||
}
|
||||
|
||||
IsLoading = false;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
|
||||
@@ -5,6 +5,7 @@ using System.Security.Policy;
|
||||
using static BD.WTTS.Client.Tools.Publish.Helpers.DotNetCLIHelper;
|
||||
using static BD.WTTS.GlobalDllImportResolver;
|
||||
using JsonSerializer = System.Text.Json.JsonSerializer;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace BD.WTTS.Client.Tools.Publish.Commands;
|
||||
|
||||
@@ -843,6 +844,7 @@ $"""
|
||||
arg.ReadyToRun = false;
|
||||
arg.Trimmed = false;
|
||||
arg.SelfContained = false;
|
||||
arg.Architecture = architecture;
|
||||
// https://learn.microsoft.com/zh-cn/dotnet/core/tools/dotnet-run
|
||||
// https://download.visualstudio.microsoft.com/download/pr/c1e2729e-ab96-4929-911d-bf0f24f06f47/1b2f39cbc4eb530e39cfe6f54ce78e45/aspnetcore-runtime-7.0.7-linux-x64.tar.gz
|
||||
// dotnet "Steam++.dll" -clt devtools
|
||||
@@ -889,7 +891,9 @@ $"""
|
||||
bool? EnableMsixTooling = null,
|
||||
bool? GenerateAppxPackageOnBuild = null,
|
||||
bool? StripSymbols = null,
|
||||
bool? CreatePackage = null)
|
||||
bool? CreatePackage = null,
|
||||
Architecture? Architecture = null
|
||||
)
|
||||
{
|
||||
string? _Configuration;
|
||||
|
||||
@@ -1150,11 +1154,13 @@ publish -c {0} -p:OutputType={1} -p:PublishDir=bin\{0}\Publish\win-any -p:Publis
|
||||
yield return AssemblyInfo.Accelerator;
|
||||
yield return AssemblyInfo.GameAccount;
|
||||
yield return AssemblyInfo.GameList;
|
||||
yield return AssemblyInfo.ArchiSteamFarmPlus;
|
||||
yield return AssemblyInfo.Authenticator;
|
||||
if (platform == Platform.Windows)
|
||||
yield return AssemblyInfo.GameTools;
|
||||
yield return AssemblyInfo.SteamIdleCard;
|
||||
if (platform == Platform.Windows)
|
||||
{
|
||||
yield return AssemblyInfo.ArchiSteamFarmPlus;
|
||||
yield return AssemblyInfo.GameTools;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -25,7 +25,7 @@ interface Constants
|
||||
static readonly string[] all_rids = new[] {
|
||||
"win-x64", "win-x86", "win-arm64",
|
||||
"osx-x64", "osx-arm64",
|
||||
"linux-x64", "linux-arm64",
|
||||
"linux-x64", "linux-arm64", "linux-loongarch64",
|
||||
};
|
||||
|
||||
static readonly string[] ignoreDirNames = new[]
|
||||
@@ -122,6 +122,7 @@ interface Constants
|
||||
Architecture.Arm64 => "arm64",
|
||||
Architecture.X64 => "x64",
|
||||
Architecture.X86 => "x86",
|
||||
Architecture.LoongArch64 => "loongarch64",
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(architecture), architecture, null),
|
||||
};
|
||||
|
||||
@@ -160,6 +161,12 @@ interface Constants
|
||||
case "arm64":
|
||||
info.Architecture = Architecture.Arm64;
|
||||
break;
|
||||
case "loongarch64":
|
||||
info.Architecture = Architecture.LoongArch64;
|
||||
break;
|
||||
case "riscv64":
|
||||
info.Architecture = Architecture.RiscV64;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return info;
|
||||
|
||||
@@ -43,6 +43,8 @@ public static partial class GlobalDllImportResolver
|
||||
Architecture.Arm64 => "linux-arm64", // 在 64 位 ARM 上运行的 Linux 发行版本,如 Raspberry Pi Model 3 及更高版本上的 Ubuntu 服务器 64 位
|
||||
Architecture.Arm => "linux-arm", // 在 ARM 上运行的 Linux 发行版本,如 Raspberry Pi Model 2 及更高版本上的 Raspbian
|
||||
Architecture.Armv6 => "linux-armv6",
|
||||
Architecture.LoongArch64 => "linux-loongarch64", // 在龙芯 LoongArch64 上运行的 Linux 发行版本
|
||||
Architecture.RiscV64 => "linux-riscv64", // 在 RISC-V 64 位上运行的 Linux 发行版本
|
||||
_ => throw new PlatformNotSupportedException(),
|
||||
};
|
||||
#else
|
||||
|
||||
+1
-1
@@ -124,7 +124,7 @@ namespace BD.WTTS.Client.Resources {
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 调整当前设备上共享的 Steam 账号优先级顺序,用于解决想玩账号 B 的共享却一直使用的是账号 A 的共享这种问题,拖拽操作从上到下的排序为共享库使用的优先级顺序,也可以选择暂时禁用或启用指定账号的共享。调整后保存重启 Steam 生效! 的本地化字符串。
|
||||
/// 查找类似 (因 Steam 已抛弃旧版本家庭共享 该功能已经失效!) 调整当前设备上共享的 Steam 账号优先级顺序,用于解决想玩账号 B 的共享却一直使用的是账号 A 的共享这种问题,拖拽操作从上到下的排序为共享库使用的优先级顺序,也可以选择暂时禁用或启用指定账号的共享。调整后保存重启 Steam 生效! 的本地化字符串。
|
||||
/// </summary>
|
||||
public static string AccountChange_ShareManageAboutTips {
|
||||
get {
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -2236,7 +2236,7 @@
|
||||
<value>修改的数据生效需要重启 Steam 是否需要重启 Steam。</value>
|
||||
</data>
|
||||
<data name="AccountChange_ShareManageAboutTips" xml:space="preserve">
|
||||
<value>调整当前设备上共享的 Steam 账号优先级顺序,用于解决想玩账号 B 的共享却一直使用的是账号 A 的共享这种问题,拖拽操作从上到下的排序为共享库使用的优先级顺序,也可以选择暂时禁用或启用指定账号的共享。调整后保存重启 Steam 生效!</value>
|
||||
<value>(因 Steam 已抛弃旧版本家庭共享 该功能已经失效!) 调整当前设备上共享的 Steam 账号优先级顺序,用于解决想玩账号 B 的共享却一直使用的是账号 A 的共享这种问题,拖拽操作从上到下的排序为共享库使用的优先级顺序,也可以选择暂时禁用或启用指定账号的共享。调整后保存重启 Steam 生效!</value>
|
||||
</data>
|
||||
<data name="CommunityFix_SubProcessFileNotExist" xml:space="preserve">
|
||||
<value>网络加速子进程文件不存在</value>
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -333,16 +333,18 @@ public sealed class UserService : ReactiveObject
|
||||
if (token != null)
|
||||
{
|
||||
await Browser2.OpenAsync(string.Format(Constants.Urls.OfficialWebsite_Fast_Login_, token.AccessToken, HttpUtility.UrlEncode(token.ExpiresIn.ToString("R")), HttpUtility.UrlEncode(url)));
|
||||
return;
|
||||
}
|
||||
return;
|
||||
break;
|
||||
case FastLoginWebChannel.WattGame:
|
||||
var shopToken = await userManager.GetShopAuthTokenAsync();
|
||||
if (shopToken != null)
|
||||
{
|
||||
var cookieMaxAge = (shopToken.ExpiresIn - DateTimeOffset.Now).TotalSeconds;
|
||||
await Browser2.OpenAsync(string.Format(Constants.Urls.WattGame_Fast_Login_, shopToken.AccessToken, HttpUtility.UrlEncode(cookieMaxAge.ToString()), HttpUtility.UrlEncode(url)));
|
||||
return;
|
||||
}
|
||||
return;
|
||||
break;
|
||||
}
|
||||
await Browser2.OpenAsync(url.ToString());
|
||||
}
|
||||
|
||||
@@ -137,12 +137,15 @@ partial class Startup // 全局异常处理
|
||||
#endif
|
||||
|
||||
#if WINDOWS
|
||||
var mbText =
|
||||
if (isTerminating == true)
|
||||
{
|
||||
var mbText =
|
||||
$"""
|
||||
{string.Format(message, args)}
|
||||
{ex}
|
||||
""";
|
||||
ShowApplicationCrash(mbText);
|
||||
ShowApplicationCrash(mbText);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@ namespace BD.WTTS.UI.ViewModels;
|
||||
|
||||
public sealed class PluginStorePageViewModel : TabItemViewModel
|
||||
{
|
||||
public override string Name => Strings.Welcome;
|
||||
public override string Name => Strings.Plugin_Store;
|
||||
|
||||
public override string IconKey => "avares://BD.WTTS.Client.Avalonia/UI/Assets/Icons/home.ico";
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
<TargetFrameworks Condition="$([MSBuild]::IsOSPlatform('linux'))">net$(DotNet_Version)</TargetFrameworks>
|
||||
<SupportedOSPlatformVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'ios'">15.0</SupportedOSPlatformVersion>
|
||||
<SupportedOSPlatformVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'maccatalyst'">15.0</SupportedOSPlatformVersion>
|
||||
<SupportedOSPlatformVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'macos'">12.0</SupportedOSPlatformVersion>
|
||||
<SupportedOSPlatformVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'android'">21.0</SupportedOSPlatformVersion>
|
||||
<SupportedOSPlatformVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'windows'">10.0.17763.0</SupportedOSPlatformVersion>
|
||||
<TargetPlatformMinVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'windows'">10.0.17763.0</TargetPlatformMinVersion>
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
<TargetFrameworks Condition="$([MSBuild]::IsOSPlatform('linux'))">$(TargetFrameworks)</TargetFrameworks>
|
||||
<SupportedOSPlatformVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'ios'">15.0</SupportedOSPlatformVersion>
|
||||
<SupportedOSPlatformVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'maccatalyst'">15.0</SupportedOSPlatformVersion>
|
||||
<SupportedOSPlatformVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'macos'">12.0</SupportedOSPlatformVersion>
|
||||
<SupportedOSPlatformVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'android'">21.0</SupportedOSPlatformVersion>
|
||||
<SupportedOSPlatformVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'windows'">10.0.17763.0</SupportedOSPlatformVersion>
|
||||
<TargetPlatformMinVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'windows'">10.0.17763.0</TargetPlatformMinVersion>
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
<TargetFrameworks Condition="$([MSBuild]::IsOSPlatform('linux'))">net$(DotNet_Version)</TargetFrameworks>
|
||||
<SupportedOSPlatformVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'ios'">15.0</SupportedOSPlatformVersion>
|
||||
<SupportedOSPlatformVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'maccatalyst'">15.0</SupportedOSPlatformVersion>
|
||||
<SupportedOSPlatformVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'macos'">12.0</SupportedOSPlatformVersion>
|
||||
<SupportedOSPlatformVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'android'">21.0</SupportedOSPlatformVersion>
|
||||
<SupportedOSPlatformVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'windows'">10.0.17763.0</SupportedOSPlatformVersion>
|
||||
<TargetPlatformMinVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'windows'">10.0.17763.0</TargetPlatformMinVersion>
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
<TargetFrameworks Condition="$([MSBuild]::IsOSPlatform('windows'))">$(TargetFrameworks);net$(DotNet_Version)-windows10.0.19041</TargetFrameworks>
|
||||
<SupportedOSPlatformVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'ios'">15.0</SupportedOSPlatformVersion>
|
||||
<SupportedOSPlatformVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'maccatalyst'">15.0</SupportedOSPlatformVersion>
|
||||
<SupportedOSPlatformVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'macos'">12.0</SupportedOSPlatformVersion>
|
||||
<SupportedOSPlatformVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'android'">21.0</SupportedOSPlatformVersion>
|
||||
<SupportedOSPlatformVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'windows'">10.0.17763.0</SupportedOSPlatformVersion>
|
||||
<TargetPlatformMinVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'windows'">10.0.17763.0</TargetPlatformMinVersion>
|
||||
|
||||
Reference in New Issue
Block a user