mirror of
https://github.com/BeyondDimension/SteamTools.git
synced 2026-10-26 20:20:14 +08:00
Compare commits
16
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4573a9b494 | ||
|
|
8f29d7b8ea | ||
|
|
7156d90967 | ||
|
|
ec726e8c48 | ||
|
|
488403a86b | ||
|
|
59474d68cd | ||
|
|
5ab308bb9b | ||
|
|
bf3d6ad778 | ||
|
|
59356f210e | ||
|
|
42df02f718 | ||
|
|
8728126421 | ||
|
|
e0c36a9545 | ||
|
|
9a2bd1a6cc | ||
|
|
499edb402c | ||
|
|
14216ab98f | ||
|
|
95c10dacd4 |
@@ -3,6 +3,12 @@
|
||||
default_base_path="$HOME/WattToolkit"
|
||||
base_path="$default_base_path"
|
||||
|
||||
# 检查是否以root身份执行
|
||||
if [ "$EUID" -eq 0 ]; then
|
||||
echo "此脚本不能以root身份执行。"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# 循环直到用户输入有效路径或直接回车
|
||||
while true; do
|
||||
# 使用 zenity 提示用户选择安装路径或使用默认路径
|
||||
@@ -41,7 +47,45 @@ base_url="https://api.steampp.net"
|
||||
architecture=1
|
||||
app_name="Watt Toolkit"
|
||||
PROCESS_NAMES=("$exec_name" "$app_name")
|
||||
export LC_ALL=en_US.UTF-8
|
||||
Check_LC_Code() {
|
||||
# 检查当前 LANG 环境变量
|
||||
current_lang="${LC_ALL:-$LANG}"
|
||||
echo "当前语言环境: $current_lang"
|
||||
|
||||
# 检查是否为 C 或 C.UTF-8
|
||||
if [ "$current_lang" = "C" ] || [ "$current_lang" = "C.UTF-8" ]; then
|
||||
echo "当前语言环境是 C 或 C.UTF-8,需要修改。"
|
||||
|
||||
# 列出系统支持的语言环境
|
||||
supported_locales=$(locale -a)
|
||||
if [ -z "$supported_locales" ]; then
|
||||
echo "未能获取到支持的语言环境列表。请检查系统配置。"
|
||||
return 1
|
||||
fi
|
||||
|
||||
# 遍历支持的语言环境列表,找到第一个不是 C 或 C.UTF-8 的项
|
||||
first_non_c_locale=""
|
||||
for locale in $supported_locales; do
|
||||
if [ "$locale" != "C" ] && [ "$locale" != "C.UTF-8" ]; then
|
||||
first_non_c_locale="$locale"
|
||||
break
|
||||
fi
|
||||
done
|
||||
|
||||
# 检查是否找到了非 C/C.UTF-8 的语言环境
|
||||
if [ -n "$first_non_c_locale" ]; then
|
||||
echo "修改语言环境为支持列表中的第一个非 C/C.UTF-8 项:$first_non_c_locale"
|
||||
export LC_ALL="$first_non_c_locale"
|
||||
echo "语言环境已修改为 $first_non_c_locale。"
|
||||
else
|
||||
echo "未能找到非 C/C.UTF-8 的语言环境。请检查系统配置。"
|
||||
return 1
|
||||
fi
|
||||
else
|
||||
echo "当前语言环境不是 C 或 C.UTF-8,无需修改。"
|
||||
fi
|
||||
}
|
||||
Check_LC_Code
|
||||
Install_certutil() {
|
||||
# 判断发行版类型
|
||||
if command -v certutil &>/dev/null; then
|
||||
@@ -360,34 +404,44 @@ Kill_Process
|
||||
Decompression
|
||||
# xdg-icon-resource install "$base_path/Icons/Watt-Toolkit.png" --size 128 Watt-Toolkit
|
||||
InitDesktop() {
|
||||
# 检查XDG_DESKTOP_DIR环境变量,如果未设置则使用默认值
|
||||
XDG_DESKTOP_DIR="${XDG_DESKTOP_DIR:-$HOME/Desktop}"
|
||||
|
||||
while true; do
|
||||
# 使用 zenity 提示用户选择安装路径或使用默认路径
|
||||
choice=$(zenity --list --radiolist --title="请选择要添加到的位置" --column="选择" --column="路径" TRUE "$HOME/.local/share/applications/" FALSE "$HOME/Desktop")
|
||||
choice=$(zenity --list --radiolist --title="请选择要添加到的位置" \
|
||||
--column="选择" --column="路径" \
|
||||
TRUE "$XDG_DESKTOP_DIR" \
|
||||
FALSE "$HOME/.local/share/applications/")
|
||||
|
||||
# 检查用户输入
|
||||
if [ "$choice" == "$HOME/.local/share/applications/" ]; then
|
||||
target_dir="$HOME/.local/share/applications/"
|
||||
break
|
||||
elif [ "$choice" == "$HOME/Desktop" ]; then
|
||||
target_dir="$HOME/Desktop/"
|
||||
elif [ "$choice" == "$XDG_DESKTOP_DIR" ]; then
|
||||
target_dir="$XDG_DESKTOP_DIR"
|
||||
break
|
||||
else
|
||||
echo "无效选项,请输入 1 或 2。"
|
||||
# 无效选项时给出提示,并继续循环
|
||||
zenity --info --text="无效选项,请重新选择。"
|
||||
fi
|
||||
done
|
||||
#添加桌面文件
|
||||
|
||||
# 添加桌面文件
|
||||
rm -rf "$target_dir/Watt Toolkit.desktop" 2>/dev/null
|
||||
echo "#!/usr/bin/env xdg-open
|
||||
cat <<EOT > "$target_dir/Watt Toolkit.desktop"
|
||||
[Desktop Entry]
|
||||
Name=Watt Toolkit
|
||||
Exec=$base_path/$exec_name.sh
|
||||
Icon=$base_path/Icons/Watt-Toolkit.png
|
||||
Terminal=false
|
||||
Type=Application
|
||||
StartupNotify=false" >"$target_dir/Watt Toolkit.desktop"
|
||||
StartupNotify=false
|
||||
EOT
|
||||
chmod +x "$target_dir/Watt Toolkit.desktop"
|
||||
|
||||
}
|
||||
|
||||
|
||||
InitDesktop
|
||||
# update-desktop-database ~/.local/share/applications
|
||||
#运行程序
|
||||
|
||||
+1
-1
Submodule ref/SteamClient updated: 3dcd4b4cda...b449d0d434
@@ -21,7 +21,7 @@ public static partial class AssemblyInfo
|
||||
/// <summary>
|
||||
/// RC 版本号,范围 0~9,只增不减
|
||||
/// </summary>
|
||||
const string ver_for_rc = "11";
|
||||
const string ver_for_rc = "12";
|
||||
|
||||
public const string FileVersion = $"{Version2}.{ver_for_rc}1{ver_for_preview}.0";
|
||||
|
||||
|
||||
@@ -111,6 +111,12 @@ public sealed partial class App : Application
|
||||
{
|
||||
Task2.InBackground(() => appWindow.SplashScreen?.RunTasks(CancellationToken.None));
|
||||
}
|
||||
|
||||
IPlatformService.Instance.SetSystemSessionEnding(() =>
|
||||
{
|
||||
Log.Info("System Shutdown", "Application SafeExit...");
|
||||
Shutdown();
|
||||
});
|
||||
}
|
||||
else if (ApplicationLifetime is ISingleViewApplicationLifetime singleView)
|
||||
{
|
||||
|
||||
+2
-2
@@ -7,7 +7,7 @@
|
||||
<RootNamespace>BD.WTTS</RootNamespace>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
<SelfContained>false</SelfContained>
|
||||
<DefineConstants>APP_REVERSE_PROXY;NONE_UI;REMOVE_DNS_INTERCEPT;$(DefineConstants)</DefineConstants>
|
||||
<DefineConstants>APP_REVERSE_PROXY;NONE_UI;$(DefineConstants)</DefineConstants>
|
||||
<ApplicationManifest>Properties\app.manifest</ApplicationManifest>
|
||||
</PropertyGroup>
|
||||
|
||||
@@ -110,7 +110,7 @@
|
||||
<PackageReference Include="Utf8StringInterpolation" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup Condition="!$(DefineConstants.Contains('REMOVE_DNS_INTERCEPT')) AND $([MSBuild]::IsOSPlatform('windows')) AND ($(RuntimeIdentifier.StartsWith('win-')) OR $(RuntimeIdentifier) == '')">
|
||||
<ItemGroup Condition="$([MSBuild]::IsOSPlatform('windows')) AND ($(RuntimeIdentifier.StartsWith('win-')) OR $(RuntimeIdentifier) == '')">
|
||||
<PackageReference Include="Aigio.WinDivertSharp" />
|
||||
</ItemGroup>
|
||||
|
||||
|
||||
-2
@@ -148,7 +148,6 @@ public static partial class ServiceCollectionExtensions
|
||||
|
||||
#if WINDOWS
|
||||
|
||||
#if !REMOVE_DNS_INTERCEPT
|
||||
/// <summary>
|
||||
/// 注册数据包拦截器
|
||||
/// </summary>
|
||||
@@ -171,7 +170,6 @@ public static partial class ServiceCollectionExtensions
|
||||
|
||||
return services;
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
}
|
||||
+1
-1
@@ -84,7 +84,7 @@ sealed partial class HttpReverseProxyMiddleware
|
||||
!reverseProxyConfig.Service.OnlyEnableProxyScript)
|
||||
{
|
||||
// 部分运营商将奇怪的域名解析到 127.0.0.1 再此排除这些不支持的代理域名
|
||||
var ip = await reverseProxyConfig.DnsAnalysis.AnalysisDomainIpAsync(context.Request.Host.Value, IDnsAnalysisService.DNS_Dnspods).FirstOrDefaultAsync();
|
||||
var ip = await reverseProxyConfig.DnsAnalysis.AnalysisDomainIpAsync(context.Request.Host.Value!, IDnsAnalysisService.DNS_Dnspods).FirstOrDefaultAsync();
|
||||
if (ip == null || IPAddress.IsLoopback(ip))
|
||||
{
|
||||
context.Response.StatusCode = StatusCodes.Status500InternalServerError;
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
// https://github.com/dotnetcore/FastGithub/blob/2.1.4/FastGithub.PacketIntercept/DnsInterceptHostedService.cs
|
||||
|
||||
#if WINDOWS && !REMOVE_DNS_INTERCEPT
|
||||
#if WINDOWS
|
||||
|
||||
// ReSharper disable once CheckNamespace
|
||||
namespace BD.WTTS.Services.Implementation;
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
// https://github.com/dotnetcore/FastGithub/blob/2.1.4/FastGithub.PacketIntercept/Dns/DnsInterceptor.cs
|
||||
|
||||
#if WINDOWS && !REMOVE_DNS_INTERCEPT
|
||||
#if WINDOWS
|
||||
|
||||
using WinDivertSharp;
|
||||
using DNS.Protocol;
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
// https://github.com/dotnetcore/FastGithub/blob/2.1.4/FastGithub.PacketIntercept/Tcp/GitInterceptor.cs
|
||||
|
||||
#if WINDOWS && !REMOVE_DNS_INTERCEPT
|
||||
#if WINDOWS
|
||||
|
||||
using static BD.WTTS.Models.Abstractions.IReverseProxyConfig;
|
||||
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
// https://github.com/dotnetcore/FastGithub/blob/2.1.4/FastGithub.PacketIntercept/Tcp/HttpInterceptor.cs
|
||||
|
||||
#if WINDOWS && !REMOVE_DNS_INTERCEPT
|
||||
#if WINDOWS
|
||||
|
||||
using static BD.WTTS.Models.Abstractions.IReverseProxyConfig;
|
||||
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
// https://github.com/dotnetcore/FastGithub/blob/2.1.4/FastGithub.PacketIntercept/Tcp/HttpsInterceptor.cs
|
||||
|
||||
#if WINDOWS && !REMOVE_DNS_INTERCEPT
|
||||
#if WINDOWS
|
||||
|
||||
using static BD.WTTS.Models.Abstractions.IReverseProxyConfig;
|
||||
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
// https://github.com/dotnetcore/FastGithub/blob/2.1.4/FastGithub.PacketIntercept/Tcp/SshInterceptor.cs
|
||||
|
||||
#if WINDOWS && !REMOVE_DNS_INTERCEPT
|
||||
#if WINDOWS
|
||||
|
||||
using static BD.WTTS.Models.Abstractions.IReverseProxyConfig;
|
||||
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
// https://github.com/dotnetcore/FastGithub/blob/2.1.4/FastGithub.PacketIntercept/TcpInterceptHostedService.cs
|
||||
|
||||
#if WINDOWS && !REMOVE_DNS_INTERCEPT
|
||||
#if WINDOWS
|
||||
|
||||
using static BD.WTTS.Models.Abstractions.IReverseProxyConfig;
|
||||
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
// https://github.com/dotnetcore/FastGithub/blob/2.1.4/FastGithub.PacketIntercept/Tcp/TcpInterceptor.cs
|
||||
|
||||
#if WINDOWS && !REMOVE_DNS_INTERCEPT
|
||||
#if WINDOWS
|
||||
|
||||
using WinDivertSharp;
|
||||
|
||||
|
||||
+1
-1
@@ -23,7 +23,7 @@ partial class YarpReverseProxyServiceImpl
|
||||
services.AddReverseProxyServer();
|
||||
services.AddFlowAnalyze();
|
||||
|
||||
#if WINDOWS && !REMOVE_DNS_INTERCEPT
|
||||
#if WINDOWS
|
||||
if (ProxyMode == ProxyMode.DNSIntercept)
|
||||
{
|
||||
services.AddPacketIntercept();
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<PropertyGroup>
|
||||
<RootNamespace>BD.WTTS</RootNamespace>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
<DefineConstants>WTTS_PLUGIN;WTTS_PLUGIN_ACCELERATOR;REMOVE_DNS_INTERCEPT;$(DefineConstants)</DefineConstants>
|
||||
<DefineConstants>WTTS_PLUGIN;WTTS_PLUGIN_ACCELERATOR;$(DefineConstants)</DefineConstants>
|
||||
<!--<EnableDynamicLoading>true</EnableDynamicLoading>-->
|
||||
<AvaloniaUseCompiledBindingsByDefault>true</AvaloniaUseCompiledBindingsByDefault>
|
||||
</PropertyGroup>
|
||||
@@ -124,7 +124,7 @@
|
||||
</EmbeddedResource>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup Condition="!$(DefineConstants.Contains('REMOVE_DNS_INTERCEPT')) AND $([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'windows'">
|
||||
<ItemGroup Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'windows'">
|
||||
<Compile Update="Properties\WinDivertResource.Designer.cs">
|
||||
<DesignTime>True</DesignTime>
|
||||
<AutoGen>True</AutoGen>
|
||||
@@ -136,7 +136,7 @@
|
||||
</EmbeddedResource>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup Condition="$(DefineConstants.Contains('REMOVE_DNS_INTERCEPT')) OR $([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) != 'windows'">
|
||||
<ItemGroup Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) != 'windows'">
|
||||
<Compile Remove="Properties\WinDivertResource.Designer.cs" />
|
||||
<EmbeddedResource Remove="Properties\WinDivertResource.resx" />
|
||||
</ItemGroup>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#if WINDOWS && !REMOVE_DNS_INTERCEPT
|
||||
#if WINDOWS
|
||||
using WinDivertBinRes = BD.WTTS.Properties.WinDivertResource;
|
||||
|
||||
namespace Mobius.Helpers;
|
||||
|
||||
@@ -39,7 +39,7 @@ partial class ProxyService
|
||||
IReadOnlyCollection<ScriptIPCDTO>? scripts = default;
|
||||
bool isEnableScript = ProxySettings.IsEnableScript.Value;
|
||||
bool isOnlyWorkSteamBrowser = ProxySettings.IsOnlyWorkSteamBrowser.Value;
|
||||
ushort proxyPort = ProxySettings.SystemProxyPortId.Value;
|
||||
ushort proxyPort = ProxySettings.SystemProxyPortId.Value == 0 ? ProxySettings.SystemProxyPortId.Default : ProxySettings.SystemProxyPortId.Value;
|
||||
string? proxyIp = ProxySettings.SystemProxyIp.Value;
|
||||
proxyMode = defaultProxyMode;
|
||||
bool isProxyGOG = ProxySettings.IsProxyGOG.Value;
|
||||
@@ -120,9 +120,6 @@ partial class ProxyService
|
||||
|
||||
switch (proxyMode)
|
||||
{
|
||||
#if REMOVE_DNS_INTERCEPT
|
||||
case ProxyMode.DNSIntercept:
|
||||
#endif
|
||||
case ProxyMode.Hosts:
|
||||
var inUsePort = SocketHelper.IsUsePort(proxyIp_.Value, httpsPort);
|
||||
if (inUsePort)
|
||||
@@ -189,7 +186,7 @@ partial class ProxyService
|
||||
return Strings.CommunityFix_SetAsSystemPACProxyFail;
|
||||
}
|
||||
break;
|
||||
#if WINDOWS && !REMOVE_DNS_INTERCEPT
|
||||
#if WINDOWS
|
||||
case ProxyMode.DNSIntercept:
|
||||
{
|
||||
await Mobius.Helpers.WinDivertInitHelper.InitializeAsync();
|
||||
@@ -318,9 +315,6 @@ partial class ProxyService
|
||||
#endif
|
||||
switch (proxyMode) // 先停止接入代理流量
|
||||
{
|
||||
#if REMOVE_DNS_INTERCEPT
|
||||
case ProxyMode.DNSIntercept:
|
||||
#endif
|
||||
case ProxyMode.Hosts:
|
||||
var needClear = hostsFileService.ContainsHostsByTag();
|
||||
if (needClear)
|
||||
@@ -357,7 +351,7 @@ partial class ProxyService
|
||||
await platformService.SetAsSystemPACProxyAsync(false);
|
||||
}
|
||||
break;
|
||||
#if WINDOWS && !REMOVE_DNS_INTERCEPT
|
||||
#if WINDOWS
|
||||
case ProxyMode.DNSIntercept:
|
||||
{
|
||||
// 停止时也调用初始化
|
||||
|
||||
@@ -11,9 +11,7 @@ public static partial class ProxySettings
|
||||
{
|
||||
#if WINDOWS
|
||||
yield return EProxyMode.Hosts;
|
||||
#if !REMOVE_DNS_INTERCEPT
|
||||
yield return EProxyMode.DNSIntercept;
|
||||
#endif
|
||||
yield return EProxyMode.PAC;
|
||||
yield return EProxyMode.System;
|
||||
#elif ANDROID
|
||||
|
||||
@@ -1,19 +1,17 @@
|
||||
using AppResources = BD.WTTS.Client.Resources.Strings;
|
||||
|
||||
using BD.WTTS.UI.Views.Pages;
|
||||
using STUN.StunResult;
|
||||
using STUN.Enums;
|
||||
using AppResources = BD.WTTS.Client.Resources.Strings;
|
||||
|
||||
namespace BD.WTTS.UI.ViewModels;
|
||||
|
||||
public sealed partial class AcceleratorPageViewModel
|
||||
{
|
||||
public NetworkCheckControlViewModel NetworkCheckControlViewModel { get; } = new();
|
||||
|
||||
DateTime _initializeTime;
|
||||
readonly IHostsFileService? hostsFileService;
|
||||
readonly IPlatformService platformService = IPlatformService.Instance;
|
||||
readonly IReverseProxyService reverseProxyService = IReverseProxyService.Constants.Instance;
|
||||
readonly ICertificateManager certificateManager = ICertificateManager.Constants.Instance;
|
||||
readonly INetworkTestService networkTestService = INetworkTestService.Instance;
|
||||
|
||||
public AcceleratorPageViewModel()
|
||||
{
|
||||
@@ -71,82 +69,6 @@ public sealed partial class AcceleratorPageViewModel
|
||||
GameAcceleratorService.Current.LoadGames();
|
||||
});
|
||||
|
||||
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 natStatus = natCheckResult.NatType switch
|
||||
{
|
||||
NatType.OpenInternet or NatType.FullCone => NatTypeSimple.Open,
|
||||
NatType.RestrictedCone or NatType.PortRestrictedCone or NatType.SymmetricUdpFirewall => NatTypeSimple.Moderate,
|
||||
NatType.Symmetric or NatType.UdpBlocked => NatTypeSimple.Strict,
|
||||
NatType.Unknown or NatType.UnsupportedServer or _ => NatTypeSimple.Unknown,
|
||||
};
|
||||
|
||||
PublicEndPoint = natCheckResult.PublicEndPoint?.Address.ToString() ?? "Unknown";
|
||||
LocalEndPoint = natCheckResult.LocalEndPoint?.Address.ToString() ?? "Unknown";
|
||||
|
||||
return (natStatus, netSucc);
|
||||
});
|
||||
NATCheckCommand
|
||||
.IsExecuting
|
||||
.ToPropertyEx(this, x => x.IsNATChecking);
|
||||
|
||||
DNSCheckCommand = ReactiveCommand.CreateFromTask(async () =>
|
||||
{
|
||||
var testDomain = DomainPendingTest == string.Empty ? "store.steampowered.com" : 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";
|
||||
}
|
||||
});
|
||||
DNSCheckCommand
|
||||
.IsExecuting
|
||||
.ToPropertyEx(this, x => x.IsDNSChecking);
|
||||
|
||||
IPv6CheckCommand = ReactiveCommand.CreateFromTask(async () =>
|
||||
{
|
||||
var result = await IMicroServiceClient.Instance.Accelerate.GetMyIP(ipV6: true);
|
||||
if (result.IsSuccess)
|
||||
{
|
||||
IsSupportIPv6 = true;
|
||||
IPv6Address = result.Content ?? string.Empty;
|
||||
}
|
||||
else
|
||||
{
|
||||
IsSupportIPv6 = false;
|
||||
IPv6Address = string.Empty;
|
||||
}
|
||||
});
|
||||
IPv6CheckCommand
|
||||
.IsExecuting
|
||||
.ToPropertyEx(this, x => x.IsIPv6Checking);
|
||||
|
||||
ProxySettingsCommand = ReactiveCommand.Create(() =>
|
||||
{
|
||||
var vm = new ProxySettingsWindowViewModel();
|
||||
|
||||
-55
@@ -4,66 +4,11 @@ namespace BD.WTTS.UI.ViewModels;
|
||||
|
||||
public sealed partial class AcceleratorPageViewModel : TabItemViewModel
|
||||
{
|
||||
public enum NatTypeSimple
|
||||
{
|
||||
Unknown,
|
||||
Open,
|
||||
Moderate,
|
||||
Strict,
|
||||
}
|
||||
|
||||
public override string Name => Strings.Welcome;
|
||||
|
||||
[Reactive]
|
||||
public string SelectedSTUNAddress { get; set; }
|
||||
|
||||
public string[] STUNAddress { get; } =
|
||||
[
|
||||
"stun.syncthing.net",
|
||||
"stun.hot-chilli.net",
|
||||
"stun.fitauto.ru",
|
||||
"stun.miwifi.com",
|
||||
];
|
||||
|
||||
[ObservableAsProperty]
|
||||
public bool IsNATChecking { get; }
|
||||
|
||||
[ObservableAsProperty]
|
||||
public bool IsDNSChecking { get; }
|
||||
|
||||
[ObservableAsProperty]
|
||||
public bool IsIPv6Checking { get; }
|
||||
|
||||
[Reactive]
|
||||
public string DomainPendingTest { get; set; } = string.Empty;
|
||||
|
||||
[Reactive]
|
||||
public ReadOnlyCollection<ProxyDomainGroupViewModel>? EnableProxyDomainGroupVMs { get; set; }
|
||||
|
||||
[Reactive]
|
||||
public string LocalEndPoint { get; set; } = string.Empty;
|
||||
|
||||
[Reactive]
|
||||
public string PublicEndPoint { get; set; } = string.Empty;
|
||||
|
||||
[Reactive]
|
||||
public string DNSTestDelay { get; set; } = string.Empty;
|
||||
|
||||
[Reactive]
|
||||
public string DNSTestResult { get; set; } = string.Empty;
|
||||
|
||||
[Reactive]
|
||||
public string IPv6Address { get; set; } = string.Empty;
|
||||
|
||||
[Reactive]
|
||||
public bool IsSupportIPv6 { get; set; }
|
||||
|
||||
public ReactiveCommand<Unit, (NatTypeSimple Nat, bool PingSuccess)> NATCheckCommand { get; }
|
||||
|
||||
public ReactiveCommand<Unit, Unit> DNSCheckCommand { get; }
|
||||
|
||||
public ReactiveCommand<Unit, Unit> IPv6CheckCommand { get; }
|
||||
|
||||
public ICommand StartProxyCommand { get; }
|
||||
|
||||
public ICommand RefreshCommand { get; }
|
||||
|
||||
@@ -0,0 +1,202 @@
|
||||
using STUN.Enums;
|
||||
using STUN.StunResult;
|
||||
using System.Reactive;
|
||||
|
||||
namespace BD.WTTS.UI.ViewModels;
|
||||
|
||||
public partial class NetworkCheckControlViewModel : ViewModelBase
|
||||
{
|
||||
[GeneratedRegex(DomainValidationAttribute.RegPattern)]
|
||||
private static partial Regex DomainRegExp();
|
||||
|
||||
public class DomainValidationAttribute : RegularExpressionAttribute
|
||||
{
|
||||
public const string RegPattern = @"^[^/]+\.[^/]{2,}$";
|
||||
|
||||
public override string FormatErrorMessage(string name) => "请填入不带分隔符 \"/\" 的域名";
|
||||
|
||||
public DomainValidationAttribute() : base(RegPattern)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
private readonly INetworkTestService _networkTestService = INetworkTestService.Instance;
|
||||
|
||||
public record NATFetchResult(string PublicEndPoint, string LocalEndPoint, string NATLevel, string NATTypeTip, bool PingResult);
|
||||
|
||||
public string DefaultTestDomain { get; } = "store.steampowered.com";
|
||||
|
||||
[Reactive]
|
||||
public string SelectedSTUNAddress { get; set; }
|
||||
|
||||
public string[] STUNAddress { get; } =
|
||||
[
|
||||
"stun.syncthing.net",
|
||||
"stun.hot-chilli.net",
|
||||
"stun.fitauto.ru",
|
||||
"stun.miwifi.com",
|
||||
];
|
||||
|
||||
[ObservableAsProperty]
|
||||
public string NATLevel { get; } = string.Empty;
|
||||
|
||||
[ObservableAsProperty]
|
||||
public string NATTypeTip { get; } = string.Empty;
|
||||
|
||||
[ObservableAsProperty]
|
||||
public string LocalEndPoint { get; } = string.Empty;
|
||||
|
||||
[ObservableAsProperty]
|
||||
public string PublicEndPoint { get; } = string.Empty;
|
||||
|
||||
[ObservableAsProperty]
|
||||
public bool PingOkVisible { get; }
|
||||
|
||||
[ObservableAsProperty]
|
||||
public bool PingErrorVisible { get; }
|
||||
|
||||
[ObservableAsProperty]
|
||||
public bool IsNATChecking { get; }
|
||||
|
||||
[ObservableAsProperty]
|
||||
public bool IsDNSChecking { get; }
|
||||
|
||||
[ObservableAsProperty]
|
||||
public bool IsIPv6Checking { get; }
|
||||
|
||||
[DomainValidation]
|
||||
[Reactive]
|
||||
public string DomainPendingTest { get; set; } = string.Empty;
|
||||
|
||||
[Reactive]
|
||||
public string DNSTestDelay { get; set; } = string.Empty;
|
||||
|
||||
[Reactive]
|
||||
public string DNSTestResult { get; set; } = string.Empty;
|
||||
|
||||
[Reactive]
|
||||
public string IPv6Address { get; set; } = string.Empty;
|
||||
|
||||
[Reactive]
|
||||
public bool IsSupportIPv6 { get; set; }
|
||||
|
||||
public ReactiveCommand<Unit, NATFetchResult> NATCheckCommand { get; }
|
||||
|
||||
public ReactiveCommand<Unit, Unit> DNSCheckCommand { get; }
|
||||
|
||||
public ReactiveCommand<Unit, Unit> IPv6CheckCommand { get; }
|
||||
|
||||
public NetworkCheckControlViewModel()
|
||||
{
|
||||
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
|
||||
.IsExecuting
|
||||
.ToPropertyEx(this, x => x.IsNATChecking);
|
||||
NATCheckCommand
|
||||
.Select(x => x.PublicEndPoint)
|
||||
.ToPropertyEx(this, x => x.PublicEndPoint);
|
||||
NATCheckCommand
|
||||
.Select(x => x.LocalEndPoint)
|
||||
.ToPropertyEx(this, x => x.LocalEndPoint);
|
||||
NATCheckCommand
|
||||
.Select(x => x.NATLevel)
|
||||
.Merge(Observable.Return("未知"))
|
||||
.ToPropertyEx(this, x => x.NATLevel);
|
||||
NATCheckCommand
|
||||
.Select(x => x.NATTypeTip)
|
||||
.Merge(Observable.Return("未知类型"))
|
||||
.ToPropertyEx(this, x => x.NATTypeTip);
|
||||
|
||||
var hidePingResultStream = NATCheckCommand
|
||||
.IsExecuting
|
||||
.Where(x => x == true)
|
||||
.Select(x => false);
|
||||
NATCheckCommand
|
||||
.Select(x => x.PingResult == true)
|
||||
.Merge(hidePingResultStream)
|
||||
.ToPropertyEx(this, x => x.PingOkVisible);
|
||||
NATCheckCommand
|
||||
.Select(x => x.PingResult == false)
|
||||
.Merge(hidePingResultStream)
|
||||
.ToPropertyEx(this, x => x.PingErrorVisible);
|
||||
|
||||
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
|
||||
.IsExecuting
|
||||
.ToPropertyEx(this, x => x.IsDNSChecking);
|
||||
|
||||
IPv6CheckCommand = ReactiveCommand.CreateFromTask(async () =>
|
||||
{
|
||||
var result = await IMicroServiceClient.Instance.Accelerate.GetMyIP(ipV6: true);
|
||||
if (result.IsSuccess)
|
||||
{
|
||||
IsSupportIPv6 = true;
|
||||
IPv6Address = result.Content ?? string.Empty;
|
||||
}
|
||||
else
|
||||
{
|
||||
IsSupportIPv6 = false;
|
||||
IPv6Address = string.Empty;
|
||||
}
|
||||
});
|
||||
IPv6CheckCommand
|
||||
.IsExecuting
|
||||
.ToPropertyEx(this, x => x.IsIPv6Checking);
|
||||
|
||||
IPv6CheckCommand.Execute().Subscribe();
|
||||
}
|
||||
}
|
||||
@@ -11,7 +11,7 @@
|
||||
xmlns:ui="using:FluentAvalonia.UI.Controls"
|
||||
d:DesignHeight="450"
|
||||
d:DesignWidth="800"
|
||||
x:DataType="spp:AcceleratorPageViewModel"
|
||||
x:DataType="spp:NetworkCheckControlViewModel"
|
||||
mc:Ignorable="d">
|
||||
<ScrollViewer
|
||||
Padding="0,0,10,0"
|
||||
@@ -42,7 +42,6 @@
|
||||
x:Name="NATCheckButton"
|
||||
Width="100"
|
||||
Margin="0,0,0,4"
|
||||
x:FieldModifier="public"
|
||||
Command="{Binding NATCheckCommand}"
|
||||
Content="检测"
|
||||
IsEnabled="True" />
|
||||
@@ -63,14 +62,14 @@
|
||||
x:Name="NATTextBlock"
|
||||
VerticalAlignment="Center"
|
||||
Foreground="Gray"
|
||||
Text="未知" />
|
||||
Text="{Binding NATLevel}" />
|
||||
<ui:FontIcon
|
||||
Margin="3,0"
|
||||
FontSize="20"
|
||||
Glyph=""
|
||||
ToolTip.ShowDelay="0">
|
||||
<ToolTip.Tip>
|
||||
<TextBlock x:Name="NATTypeTip" Text="未知类型" />
|
||||
<TextBlock x:Name="NATTypeTip" Text="{Binding NATTypeTip}" />
|
||||
</ToolTip.Tip>
|
||||
</ui:FontIcon>
|
||||
</DockPanel>
|
||||
@@ -126,13 +125,13 @@
|
||||
<ui:FontIcon
|
||||
x:Name="PingOK"
|
||||
HorizontalAlignment="Right"
|
||||
x:FieldModifier="public"
|
||||
FontFamily="{StaticResource SymbolThemeFontFamily}"
|
||||
FontSize="26"
|
||||
Foreground="Green"
|
||||
Glyph="" />
|
||||
Glyph=""
|
||||
IsVisible="{Binding PingOkVisible}" />
|
||||
|
||||
<Grid x:Name="PingError" x:FieldModifier="public">
|
||||
<Grid x:Name="PingError" IsVisible="{Binding PingErrorVisible}">
|
||||
<ui:FontIcon
|
||||
Margin="3"
|
||||
HorizontalAlignment="Right"
|
||||
@@ -213,7 +212,50 @@
|
||||
<TextBox
|
||||
Width="220"
|
||||
Text="{Binding DomainPendingTest, Mode=TwoWay}"
|
||||
Watermark="store.steampowered.com" />
|
||||
Watermark="{Binding DefaultTestDomain}">
|
||||
<TextBox.Styles>
|
||||
<Style Selector="DataValidationErrors">
|
||||
<Setter Property="Template">
|
||||
<ControlTemplate>
|
||||
<DockPanel LastChildFill="True">
|
||||
<ContentControl
|
||||
Content="{Binding (DataValidationErrors.Errors)}"
|
||||
ContentTemplate="{TemplateBinding ErrorTemplate}"
|
||||
DataContext="{TemplateBinding Owner}"
|
||||
DockPanel.Dock="Right"
|
||||
IsVisible="{Binding (DataValidationErrors.HasErrors)}" />
|
||||
<ContentPresenter
|
||||
Name="PART_ContentPresenter"
|
||||
Padding="{TemplateBinding Padding}"
|
||||
Background="{TemplateBinding Background}"
|
||||
BorderBrush="{TemplateBinding BorderBrush}"
|
||||
BorderThickness="{TemplateBinding BorderThickness}"
|
||||
Content="{TemplateBinding Content}"
|
||||
ContentTemplate="{TemplateBinding ContentTemplate}"
|
||||
CornerRadius="{TemplateBinding CornerRadius}" />
|
||||
</DockPanel>
|
||||
</ControlTemplate>
|
||||
</Setter>
|
||||
<Setter Property="ErrorTemplate">
|
||||
<DataTemplate x:DataType="{x:Type x:Object}">
|
||||
<Canvas
|
||||
Width="14"
|
||||
Height="14"
|
||||
Margin="4,0,1,0"
|
||||
Background="Transparent">
|
||||
<ToolTip.Tip>
|
||||
<ItemsControl ItemsSource="{Binding}" />
|
||||
</ToolTip.Tip>
|
||||
<Path
|
||||
Data="M14,7 A7,7 0 0,0 0,7 M0,7 A7,7 0 1,0 14,7 M7,3l0,5 M7,9l0,2"
|
||||
Stroke="Red"
|
||||
StrokeThickness="2" />
|
||||
</Canvas>
|
||||
</DataTemplate>
|
||||
</Setter>
|
||||
</Style>
|
||||
</TextBox.Styles>
|
||||
</TextBox>
|
||||
</ui:SettingsExpanderItem.Footer>
|
||||
</ui:SettingsExpanderItem>
|
||||
|
||||
|
||||
@@ -1,7 +1,4 @@
|
||||
using Avalonia;
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Markup.Xaml;
|
||||
using Org.BouncyCastle.Asn1.Utilities;
|
||||
|
||||
namespace BD.WTTS.UI.Views.Pages;
|
||||
|
||||
|
||||
@@ -648,7 +648,7 @@
|
||||
</Panel>
|
||||
|
||||
<!-- 网络检测 -->
|
||||
<spp:NetworkCheck x:Name="NetworkCheckControl" />
|
||||
<spp:NetworkCheck DataContext="{Binding NetworkCheckControlViewModel}" />
|
||||
|
||||
<TabItem Content="dummy_tab_for_transisit_animation" />
|
||||
</Carousel>
|
||||
|
||||
@@ -73,31 +73,6 @@ public partial class AcceleratorPage2 : PageBase<AcceleratorPageViewModel>
|
||||
GameAccTab.IsVisible = false;
|
||||
AcceleratorTabs.SelectedIndex = 0;
|
||||
}
|
||||
|
||||
NetworkCheckControl.PingOK.IsVisible = false;
|
||||
NetworkCheckControl.PingError.IsVisible = false;
|
||||
NetworkCheckControl.NATCheckButton.Click += (_, _) => NetworkCheckControl.PingError.IsVisible = NetworkCheckControl.PingOK.IsVisible = false;
|
||||
ViewModel!.NATCheckCommand
|
||||
.Subscribe(result =>
|
||||
{
|
||||
(NetworkCheckControl.NATTextBlock.Text, NetworkCheckControl.NATTypeTip.Text) = result.Nat switch
|
||||
{
|
||||
AcceleratorPageViewModel.NatTypeSimple.Open => ("开放 NAT", "您可与在其网络上具有任意 NAT 类型的用户玩多人游戏和发起多人游戏。"),
|
||||
AcceleratorPageViewModel.NatTypeSimple.Moderate => ("中等 NAT", "您可与一些用户玩多人游戏;但是,并且通常你将不会被选为比赛的主持人。"),
|
||||
AcceleratorPageViewModel.NatTypeSimple.Strict => ("严格 NAT", "您只能与具有开放 NAT 类型的用户玩多人游戏。您不能被选为比赛的主持人。"),
|
||||
_ => ("不可用 NAT", "如果 NAT 不可用,您将无法使用群聊天或连接到某些 Xbox 游戏的多人游戏。"),
|
||||
};
|
||||
|
||||
if (result.PingSuccess)
|
||||
{
|
||||
NetworkCheckControl.PingOK.IsVisible = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
NetworkCheckControl.PingError.IsVisible = true;
|
||||
}
|
||||
}).DisposeWith(disposables);
|
||||
ViewModel.IPv6CheckCommand.Execute().Subscribe();
|
||||
});
|
||||
|
||||
SearchGameBox.DropDownClosed += SearchGameBox_DropDownClosed;
|
||||
|
||||
@@ -113,4 +113,22 @@ public sealed class Plugin : PluginBase<Plugin>, IPlugin
|
||||
{
|
||||
yield return GetConfiguration<ASFSettings_>(directoryExists);
|
||||
}
|
||||
|
||||
public override async ValueTask OnExit()
|
||||
{
|
||||
if (ArchiSteamFarmServiceImpl.ASFProcessId.HasValue)
|
||||
{
|
||||
try
|
||||
{
|
||||
var process = Process.GetProcessById(ArchiSteamFarmServiceImpl.ASFProcessId.Value);
|
||||
process.Kill();
|
||||
process.Dispose();
|
||||
}
|
||||
catch (ArgumentException)
|
||||
{
|
||||
// 进程已经退出
|
||||
}
|
||||
}
|
||||
await base.OnExit();
|
||||
}
|
||||
}
|
||||
|
||||
+40
-34
@@ -27,6 +27,8 @@ public partial class ArchiSteamFarmServiceImpl : ReactiveObject, IArchiSteamFarm
|
||||
{
|
||||
}
|
||||
|
||||
public static int? ASFProcessId { get; private set; }
|
||||
|
||||
public Process? ASFProcess { get; set; }
|
||||
|
||||
public event Action<string>? OnConsoleWirteLine;
|
||||
@@ -89,26 +91,48 @@ public partial class ArchiSteamFarmServiceImpl : ReactiveObject, IArchiSteamFarm
|
||||
{
|
||||
var isStartSuccess = false;
|
||||
var ipcUrl = string.Empty;
|
||||
try
|
||||
|
||||
if (ASFProcess != null || string.IsNullOrEmpty(SharedInfo.ASFExecuteFilePath))
|
||||
{
|
||||
if (ASFProcess != null || string.IsNullOrEmpty(SharedInfo.ASFExecuteFilePath))
|
||||
{
|
||||
Toast.Show(ToastIcon.Error, BDStrings.ASF_SelectASFExePath);
|
||||
return (isStartSuccess, ipcUrl);
|
||||
}
|
||||
Toast.Show(ToastIcon.Error, BDStrings.ASF_SelectASFExePath);
|
||||
return (isStartSuccess, ipcUrl);
|
||||
}
|
||||
|
||||
if (ASFSettings.CheckArchiSteamFarmExe && !await CheckFileConsistence()) // 检查文件是否被篡改
|
||||
{
|
||||
Toast.Show(ToastIcon.Error, BDStrings.ASF_ExecuteFileUnsafe);
|
||||
return (isStartSuccess, ipcUrl);
|
||||
}
|
||||
if (ASFSettings.CheckArchiSteamFarmExe && !await CheckFileConsistence()) // 检查文件是否被篡改
|
||||
{
|
||||
Toast.Show(ToastIcon.Error, BDStrings.ASF_ExecuteFileUnsafe);
|
||||
return (isStartSuccess, ipcUrl);
|
||||
}
|
||||
|
||||
ipcUrl = GetIPCUrl();
|
||||
webApiService.SetIPCUrl(ipcUrl); // 设置 IPC 接口地址
|
||||
ipcUrl = GetIPCUrl();
|
||||
webApiService.SetIPCUrl(ipcUrl); // 设置 IPC 接口地址
|
||||
|
||||
KillASFProcess(); // 杀死未关闭的 ASF 进程
|
||||
KillASFProcess(); // 杀死未关闭的 ASF 进程
|
||||
|
||||
var options = new ProcessStartInfo(SharedInfo.ASFExecuteFilePath);
|
||||
ASFProcess = StartAsync(SharedInfo.ASFExecuteFilePath);
|
||||
ASFProcessId = ASFProcess?.Id;
|
||||
|
||||
ASFService.Current.ConsoleLogText = string.Empty;
|
||||
Task2.InBackground(ReadOutPutData, true);
|
||||
AppDomain.CurrentDomain.ProcessExit += ExitHandler;
|
||||
AppDomain.CurrentDomain.UnhandledException += ExitHandler;
|
||||
|
||||
ASFProcess!.ErrorDataReceived += new DataReceivedEventHandler(ExitHandler);
|
||||
ASFProcess.BeginErrorReadLine();
|
||||
|
||||
using var cancellationTokenSource = new CancellationTokenSource(TimeSpan.FromSeconds(60));
|
||||
while (
|
||||
!(isStartSuccess = SocketHelper.IsUsePort(CurrentIPCPortValue)) &&
|
||||
!cancellationTokenSource.IsCancellationRequested)
|
||||
{
|
||||
await Task.Delay(1000);
|
||||
continue;
|
||||
}
|
||||
return (isStartSuccess, ipcUrl);
|
||||
|
||||
Process? StartAsync(string fileName)
|
||||
{
|
||||
var options = new ProcessStartInfo(fileName);
|
||||
options.CreateNoWindow = true;
|
||||
options.UseShellExecute = false;
|
||||
options.RedirectStandardOutput = true;
|
||||
@@ -120,26 +144,8 @@ public partial class ArchiSteamFarmServiceImpl : ReactiveObject, IArchiSteamFarm
|
||||
options.ArgumentList.Add("--CRYPTKEY");
|
||||
options.ArgumentList.Add(EncryptionKey);
|
||||
}
|
||||
ASFProcess = Process.Start(options);
|
||||
|
||||
ASFService.Current.ConsoleLogText = string.Empty;
|
||||
Task2.InBackground(ReadOutPutData, true);
|
||||
AppDomain.CurrentDomain.ProcessExit += ExitHandler;
|
||||
AppDomain.CurrentDomain.UnhandledException += ExitHandler;
|
||||
|
||||
ASFProcess!.ErrorDataReceived += new DataReceivedEventHandler(ExitHandler);
|
||||
ASFProcess.BeginErrorReadLine();
|
||||
while (!SocketHelper.IsUsePort(CurrentIPCPortValue))
|
||||
{
|
||||
Thread.Sleep(1000);
|
||||
continue;
|
||||
}
|
||||
isStartSuccess = true;
|
||||
return Process.Start(options);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
}
|
||||
return (isStartSuccess, ipcUrl);
|
||||
}
|
||||
|
||||
private void KillASFProcess()
|
||||
|
||||
@@ -156,8 +156,20 @@ public sealed class ASFService : ReactiveObject
|
||||
|
||||
public void OpenFolder(string tag)
|
||||
{
|
||||
if (!Enum.TryParse<EPathFolder>(tag, true, out var folderASFPath)) return;
|
||||
var folderASFPathValue = folderASFPath.GetFolderPath();
|
||||
if (string.IsNullOrEmpty(ASFSettings.ArchiSteamFarmExePath.Value))
|
||||
{
|
||||
Toast.Show(ToastIcon.Error, BDStrings.ASF_SetExePathFirst);
|
||||
return;
|
||||
}
|
||||
|
||||
string folderASFPathValue = string.Empty;
|
||||
if (!Enum.TryParse<EPathFolder>(tag, true, out var folderASFPath) ||
|
||||
!Path.Exists(folderASFPathValue = folderASFPath.GetFolderPath()))
|
||||
{
|
||||
Toast.Show(ToastIcon.Error, BDStrings.ASF_SelectASFExePath);
|
||||
return;
|
||||
}
|
||||
|
||||
IPlatformService.Instance.OpenFolder(folderASFPathValue);
|
||||
}
|
||||
|
||||
|
||||
+10
-3
@@ -11,9 +11,16 @@ public partial class ArchiSteamFarmExePathSettingsPageViewModel : ViewModelBase
|
||||
SelectProgramPath = ReactiveCommand.Create(ASFService.Current.SelectASFProgramLocationAsync);
|
||||
DownloadASF = ReactiveCommand.Create(() =>
|
||||
{
|
||||
var progress = INotificationService.Instance.NotifyDownload(() => "开始下载 ASF ", NotificationType.NewVersion);
|
||||
ASFService.Current.DownloadASFAsync(progress: progress);
|
||||
Toast.Show(ToastIcon.Info, "等待后台下载文件", ToastLength.Short);
|
||||
if (INotificationService.Instance.IsSupportNotifyDownload)
|
||||
{
|
||||
var progress = INotificationService.Instance.NotifyDownload(() => "开始下载 ASF ", NotificationType.NewVersion);
|
||||
ASFService.Current.DownloadASFAsync(progress: progress);
|
||||
Toast.Show(ToastIcon.Info, "等待后台下载文件", ToastLength.Short);
|
||||
}
|
||||
else
|
||||
{
|
||||
Toast.Show(ToastIcon.Error, "当前平台无法调用下载通知,请自行下载", ToastLength.Short);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,7 +32,9 @@ static class SharedInfo
|
||||
{
|
||||
get
|
||||
{
|
||||
return Path.GetDirectoryName(ASFSettingsExecuteFilePath) ?? string.Empty;
|
||||
return !string.IsNullOrWhiteSpace(ASFSettingsExecuteFilePath)
|
||||
? Path.GetDirectoryName(ASFSettingsExecuteFilePath) ?? string.Empty
|
||||
: string.Empty;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -135,7 +135,7 @@
|
||||
<TextBlock
|
||||
VerticalAlignment="Center"
|
||||
IsVisible="{Binding IsProtection}"
|
||||
Text="{Binding Path=Res.Achievement_IsProtection, Mode=OneWay, Source={x:Static s:ResourceService.Current}}" />
|
||||
Text="{Binding Path=Res.Achievement_IsProtection, Mode=OneWay, StringFormat={}({0}), Source={x:Static s:ResourceService.Current}}" />
|
||||
<StackPanel
|
||||
VerticalAlignment="Center"
|
||||
Orientation="Vertical"
|
||||
|
||||
@@ -1141,7 +1141,7 @@ 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.ArchiSteamFarmPlus;
|
||||
yield return AssemblyInfo.Authenticator;
|
||||
if (platform == Platform.Windows)
|
||||
yield return AssemblyInfo.GameTools;
|
||||
|
||||
@@ -339,6 +339,9 @@ $"""
|
||||
string? pfxFilePath = null,
|
||||
string? workingDirectory = null)
|
||||
{
|
||||
if (pfxFilePath != pfxFilePath_MSStore_CodeSigning)
|
||||
return;
|
||||
|
||||
ProcessStartInfo psi;
|
||||
switch (pfxFilePath)
|
||||
{
|
||||
|
||||
+4
-1
@@ -11,7 +11,10 @@ partial class WindowsPlatformServiceImpl
|
||||
{
|
||||
SystemEvents.SessionEnding += (sender, e) =>
|
||||
{
|
||||
action.Invoke();
|
||||
if (e.Reason == SessionEndReasons.SystemShutdown)
|
||||
{
|
||||
action.Invoke();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user