diff --git a/ref/DirectoryPackages b/ref/DirectoryPackages
index bf939f930..3d42ed8bc 160000
--- a/ref/DirectoryPackages
+++ b/ref/DirectoryPackages
@@ -1 +1 @@
-Subproject commit bf939f9309c2bea71eaa5327857a2f5855a57f1d
+Subproject commit 3d42ed8bcb6a5fc10748b872627b8be5b7ebf38f
diff --git a/src/BD.WTTS.Client.IPC/BD.WTTS.Client.IPC.csproj b/src/BD.WTTS.Client.IPC/BD.WTTS.Client.IPC.csproj
index c28768829..77a0b213e 100644
--- a/src/BD.WTTS.Client.IPC/BD.WTTS.Client.IPC.csproj
+++ b/src/BD.WTTS.Client.IPC/BD.WTTS.Client.IPC.csproj
@@ -26,9 +26,9 @@
Properties
-
+
Services
@@ -38,6 +38,9 @@
Services\UI\Widgets
+
+ Enums
+
@@ -46,6 +49,10 @@
+
+
+
+
diff --git a/src/BD.WTTS.Client.IPC/Services/IPCSubProcessService.cs b/src/BD.WTTS.Client.IPC/Services/IPCSubProcessService.cs
index ba9f0f60b..1956ea196 100644
--- a/src/BD.WTTS.Client.IPC/Services/IPCSubProcessService.cs
+++ b/src/BD.WTTS.Client.IPC/Services/IPCSubProcessService.cs
@@ -24,11 +24,6 @@ public interface IPCSubProcessService : IDisposable
///
T? GetService() where T : class;
- const int ExitCode_EmptyArrayArgs = 4001;
- const int ExitCode_EmptyPipeName = 4002;
- const int ExitCode_EmptyMainProcessId = 4003;
- const int ExitCode_NotFoundMainProcessId = 4004;
-
private static IPCSubProcessServiceImpl? iPCSubProcessServiceImpl;
static IPCSubProcessService Instance => iPCSubProcessServiceImpl.ThrowIsNull();
@@ -37,8 +32,8 @@ public interface IPCSubProcessService : IDisposable
/// 子进程 IPC 程序启动通用函数
///
///
- ///
- ///
+ /// 配置子进程的依赖注入服务
+ /// 配置 IPC 服务
///
///
static async Task MainAsync(
@@ -48,15 +43,15 @@ public interface IPCSubProcessService : IDisposable
params string[] args)
{
if (args.Length < 2)
- return ExitCode_EmptyArrayArgs;
+ return (int)CommandExitCode.EmptyArrayArgs;
var pipeName = args[0];
if (string.IsNullOrWhiteSpace(pipeName))
- return ExitCode_EmptyPipeName;
+ return (int)CommandExitCode.EmptyPipeName;
if (!int.TryParse(args[1], out var pid))
- return ExitCode_EmptyMainProcessId;
+ return (int)CommandExitCode.EmptyMainProcessId;
var mainProcess = Process.GetProcessById(pid);
if (mainProcess == null)
- return ExitCode_NotFoundMainProcessId;
+ return (int)CommandExitCode.NotFoundMainProcessId;
TaskCompletionSource tcs = new();
mainProcess.EnableRaisingEvents = true;
diff --git a/src/BD.WTTS.Client.Plugins.Accelerator.ReverseProxy/BD.WTTS.Client.Plugins.Accelerator.ReverseProxy.csproj b/src/BD.WTTS.Client.Plugins.Accelerator.ReverseProxy/BD.WTTS.Client.Plugins.Accelerator.ReverseProxy.csproj
index fbda3d7c0..57e8f3c8b 100644
--- a/src/BD.WTTS.Client.Plugins.Accelerator.ReverseProxy/BD.WTTS.Client.Plugins.Accelerator.ReverseProxy.csproj
+++ b/src/BD.WTTS.Client.Plugins.Accelerator.ReverseProxy/BD.WTTS.Client.Plugins.Accelerator.ReverseProxy.csproj
@@ -31,6 +31,12 @@
Properties
+
+ Properties
+
+
+ Properties
+
diff --git a/src/BD.WTTS.Client.Plugins.Accelerator.ReverseProxy/Models/IReverseProxyConfig.GlobalListener.cs b/src/BD.WTTS.Client.Plugins.Accelerator.ReverseProxy/Models/Abstractions/IReverseProxyConfig.GlobalListener.cs
similarity index 98%
rename from src/BD.WTTS.Client.Plugins.Accelerator.ReverseProxy/Models/IReverseProxyConfig.GlobalListener.cs
rename to src/BD.WTTS.Client.Plugins.Accelerator.ReverseProxy/Models/Abstractions/IReverseProxyConfig.GlobalListener.cs
index 3158752ff..3e33d70c1 100644
--- a/src/BD.WTTS.Client.Plugins.Accelerator.ReverseProxy/Models/IReverseProxyConfig.GlobalListener.cs
+++ b/src/BD.WTTS.Client.Plugins.Accelerator.ReverseProxy/Models/Abstractions/IReverseProxyConfig.GlobalListener.cs
@@ -4,7 +4,7 @@
using System.Net.NetworkInformation;
// ReSharper disable once CheckNamespace
-namespace BD.WTTS.Models;
+namespace BD.WTTS.Models.Abstractions;
partial interface IReverseProxyConfig
{
diff --git a/src/BD.WTTS.Client.Plugins.Accelerator.ReverseProxy/Models/IReverseProxyConfig.cs b/src/BD.WTTS.Client.Plugins.Accelerator.ReverseProxy/Models/Abstractions/IReverseProxyConfig.cs
similarity index 97%
rename from src/BD.WTTS.Client.Plugins.Accelerator.ReverseProxy/Models/IReverseProxyConfig.cs
rename to src/BD.WTTS.Client.Plugins.Accelerator.ReverseProxy/Models/Abstractions/IReverseProxyConfig.cs
index fbdc7008e..84c6d5ea9 100644
--- a/src/BD.WTTS.Client.Plugins.Accelerator.ReverseProxy/Models/IReverseProxyConfig.cs
+++ b/src/BD.WTTS.Client.Plugins.Accelerator.ReverseProxy/Models/Abstractions/IReverseProxyConfig.cs
@@ -2,7 +2,7 @@
// https://github.com/dotnetcore/FastGithub/blob/2.1.4/FastGithub.Configuration/FastGithubConfig.cs
// ReSharper disable once CheckNamespace
-namespace BD.WTTS.Models;
+namespace BD.WTTS.Models.Abstractions;
public partial interface IReverseProxyConfig
{
diff --git a/src/BD.WTTS.Client.Plugins.Accelerator.ReverseProxy/Program.cs b/src/BD.WTTS.Client.Plugins.Accelerator.ReverseProxy/Program.cs
index 306b994b0..11914259e 100644
--- a/src/BD.WTTS.Client.Plugins.Accelerator.ReverseProxy/Program.cs
+++ b/src/BD.WTTS.Client.Plugins.Accelerator.ReverseProxy/Program.cs
@@ -3,6 +3,9 @@ using IHttpClientFactory_Common = System.Net.Http.Client.IHttpClientFactory;
using IHttpClientFactory_Extensions_Http = System.Net.Http.IHttpClientFactory;
const string moduleName = "Accelerator";
+#if DEBUG
+Console.WriteLine($"This: {moduleName} / Program.Start");
+#endif
try
{
var exitCode = await IPCSubProcessService.MainAsync(moduleName, ConfigureServices, static ipcProvider =>
diff --git a/src/BD.WTTS.Client.Plugins.Accelerator.ReverseProxy/Properties/ImplicitUsings.cs b/src/BD.WTTS.Client.Plugins.Accelerator.ReverseProxy/Properties/ImplicitUsings.cs
deleted file mode 100644
index 2604111bd..000000000
--- a/src/BD.WTTS.Client.Plugins.Accelerator.ReverseProxy/Properties/ImplicitUsings.cs
+++ /dev/null
@@ -1,10 +0,0 @@
-// C# 10 定义全局 using
-
-#pragma warning disable IDE0079 // 请删除不必要的忽略
-#pragma warning disable IDE0005
-#pragma warning disable SA1209 // Using alias directives should be placed after other using directives
-#pragma warning disable SA1211 // Using alias directives should be ordered alphabetically by alias name
-
-global using BD.WTTS.Enums;
-
-global using BD.WTTS.Models;
\ No newline at end of file
diff --git a/src/BD.WTTS.Client.Plugins.Accelerator.ReverseProxy/Services.Implementation/HttpServer/Certificates/CertService.cs b/src/BD.WTTS.Client.Plugins.Accelerator.ReverseProxy/Services.Implementation/HttpServer/Certificates/CertService.cs
index 17899253c..a63fd8f3b 100644
--- a/src/BD.WTTS.Client.Plugins.Accelerator.ReverseProxy/Services.Implementation/HttpServer/Certificates/CertService.cs
+++ b/src/BD.WTTS.Client.Plugins.Accelerator.ReverseProxy/Services.Implementation/HttpServer/Certificates/CertService.cs
@@ -13,7 +13,7 @@ sealed class CertService
readonly ILogger logger;
readonly IReverseProxyConfig reverseProxyConfig;
- IReverseProxyService ReverseProxyService => reverseProxyConfig.Service;
+ ReverseProxyServiceImpl ReverseProxyService => reverseProxyConfig.Service;
///
/// 获取 CER 证书文件路径
diff --git a/src/BD.WTTS.Client.Plugins.Accelerator.ReverseProxy/Services.Implementation/LazyReverseProxyServiceImpl.cs b/src/BD.WTTS.Client.Plugins.Accelerator.ReverseProxy/Services.Implementation/LazyReverseProxyServiceImpl.cs
index 172159f0f..60df75a22 100644
--- a/src/BD.WTTS.Client.Plugins.Accelerator.ReverseProxy/Services.Implementation/LazyReverseProxyServiceImpl.cs
+++ b/src/BD.WTTS.Client.Plugins.Accelerator.ReverseProxy/Services.Implementation/LazyReverseProxyServiceImpl.cs
@@ -9,7 +9,7 @@ sealed class LazyReverseProxyServiceImpl : IReverseProxyService
static IReverseProxyService instance() => Ioc.Get();
#pragma warning restore IDE1006 // 命名样式
- public ICertificateManager CertificateManager => instance().CertificateManager;
+ //public ICertificateManager CertificateManager => instance().CertificateManager;
public bool ProxyRunning => instance().ProxyRunning;
diff --git a/src/BD.WTTS.Client.Plugins.Accelerator.ReverseProxy/Services.Implementation/PacketIntercept/GitInterceptor.cs b/src/BD.WTTS.Client.Plugins.Accelerator.ReverseProxy/Services.Implementation/PacketIntercept/GitInterceptor.cs
index 9103fd5ed..517ef9a06 100644
--- a/src/BD.WTTS.Client.Plugins.Accelerator.ReverseProxy/Services.Implementation/PacketIntercept/GitInterceptor.cs
+++ b/src/BD.WTTS.Client.Plugins.Accelerator.ReverseProxy/Services.Implementation/PacketIntercept/GitInterceptor.cs
@@ -2,7 +2,7 @@
#if WINDOWS
-using static BD.WTTS.Models.IReverseProxyConfig;
+using static BD.WTTS.Models.Abstractions.IReverseProxyConfig;
// ReSharper disable once CheckNamespace
namespace BD.WTTS.Services.Implementation;
diff --git a/src/BD.WTTS.Client.Plugins.Accelerator.ReverseProxy/Services.Implementation/PacketIntercept/HttpInterceptor.cs b/src/BD.WTTS.Client.Plugins.Accelerator.ReverseProxy/Services.Implementation/PacketIntercept/HttpInterceptor.cs
index e34e2eb95..3d3871a91 100644
--- a/src/BD.WTTS.Client.Plugins.Accelerator.ReverseProxy/Services.Implementation/PacketIntercept/HttpInterceptor.cs
+++ b/src/BD.WTTS.Client.Plugins.Accelerator.ReverseProxy/Services.Implementation/PacketIntercept/HttpInterceptor.cs
@@ -2,7 +2,7 @@
#if WINDOWS
-using static BD.WTTS.Models.IReverseProxyConfig;
+using static BD.WTTS.Models.Abstractions.IReverseProxyConfig;
// ReSharper disable once CheckNamespace
namespace BD.WTTS.Services.Implementation;
diff --git a/src/BD.WTTS.Client.Plugins.Accelerator.ReverseProxy/Services.Implementation/PacketIntercept/HttpsInterceptor.cs b/src/BD.WTTS.Client.Plugins.Accelerator.ReverseProxy/Services.Implementation/PacketIntercept/HttpsInterceptor.cs
index 9725eb8eb..717dbb8bf 100644
--- a/src/BD.WTTS.Client.Plugins.Accelerator.ReverseProxy/Services.Implementation/PacketIntercept/HttpsInterceptor.cs
+++ b/src/BD.WTTS.Client.Plugins.Accelerator.ReverseProxy/Services.Implementation/PacketIntercept/HttpsInterceptor.cs
@@ -2,7 +2,7 @@
#if WINDOWS
-using static BD.WTTS.Models.IReverseProxyConfig;
+using static BD.WTTS.Models.Abstractions.IReverseProxyConfig;
// ReSharper disable once CheckNamespace
namespace BD.WTTS.Services.Implementation;
diff --git a/src/BD.WTTS.Client.Plugins.Accelerator.ReverseProxy/Services.Implementation/PacketIntercept/SshInterceptor.cs b/src/BD.WTTS.Client.Plugins.Accelerator.ReverseProxy/Services.Implementation/PacketIntercept/SshInterceptor.cs
index 2c6df84d2..253a85bd4 100644
--- a/src/BD.WTTS.Client.Plugins.Accelerator.ReverseProxy/Services.Implementation/PacketIntercept/SshInterceptor.cs
+++ b/src/BD.WTTS.Client.Plugins.Accelerator.ReverseProxy/Services.Implementation/PacketIntercept/SshInterceptor.cs
@@ -2,7 +2,7 @@
#if WINDOWS
-using static BD.WTTS.Models.IReverseProxyConfig;
+using static BD.WTTS.Models.Abstractions.IReverseProxyConfig;
// ReSharper disable once CheckNamespace
namespace BD.WTTS.Services.Implementation;
diff --git a/src/BD.WTTS.Client.Plugins.Accelerator.ReverseProxy/Services.Implementation/PacketIntercept/TcpInterceptHostedService.cs b/src/BD.WTTS.Client.Plugins.Accelerator.ReverseProxy/Services.Implementation/PacketIntercept/TcpInterceptHostedService.cs
index 9fa7e8cb9..13844a5f1 100644
--- a/src/BD.WTTS.Client.Plugins.Accelerator.ReverseProxy/Services.Implementation/PacketIntercept/TcpInterceptHostedService.cs
+++ b/src/BD.WTTS.Client.Plugins.Accelerator.ReverseProxy/Services.Implementation/PacketIntercept/TcpInterceptHostedService.cs
@@ -2,7 +2,7 @@
#if WINDOWS
-using static BD.WTTS.Models.IReverseProxyConfig;
+using static BD.WTTS.Models.Abstractions.IReverseProxyConfig;
// ReSharper disable once CheckNamespace
namespace BD.WTTS.Services.Implementation;
diff --git a/src/BD.WTTS.Client.Plugins.Accelerator.ReverseProxy/Services/IReverseProxyService.Constants.cs b/src/BD.WTTS.Client.Plugins.Accelerator.ReverseProxy/Services/IReverseProxyService.Constants.cs
index 21a84ef14..10dced25c 100644
--- a/src/BD.WTTS.Client.Plugins.Accelerator.ReverseProxy/Services/IReverseProxyService.Constants.cs
+++ b/src/BD.WTTS.Client.Plugins.Accelerator.ReverseProxy/Services/IReverseProxyService.Constants.cs
@@ -6,7 +6,7 @@ namespace BD.WTTS.Services;
///
/// 反向代理服务
///
-[IpcPublic(Timeout = 55000, IgnoresIpcException = false)]
+[IpcPublic(Timeout = 9000, IgnoresIpcException = false)]
public partial interface IReverseProxyService : IDisposable, IReverseProxySettings
{
///
@@ -52,6 +52,13 @@ public partial interface IReverseProxyService : IDisposable, IReverseProxySettin
///
///
ValueTask StopProxyAsync();
+
+#if DEBUG
+ string GetDebugString()
+ {
+ return $"Pid: {Environment.ProcessId}, Exe: {Environment.ProcessPath}, Asm: {Assembly.GetAssembly(GetType())?.FullName}";
+ }
+#endif
}
///
diff --git a/src/BD.WTTS.Client.Plugins.Accelerator.ReverseProxy/Services/IReverseProxyService.cs b/src/BD.WTTS.Client.Plugins.Accelerator.ReverseProxy/Services/IReverseProxyService.cs
index 9d96a64ab..6c136638f 100644
--- a/src/BD.WTTS.Client.Plugins.Accelerator.ReverseProxy/Services/IReverseProxyService.cs
+++ b/src/BD.WTTS.Client.Plugins.Accelerator.ReverseProxy/Services/IReverseProxyService.cs
@@ -3,8 +3,6 @@ namespace BD.WTTS.Services;
partial interface IReverseProxyService
{
- ICertificateManager CertificateManager { get; }
-
///
/// 将 PEM 证书公钥写入 GOG GALAXY
///
diff --git a/src/BD.WTTS.Client.Plugins.Accelerator/BD.WTTS.Client.Plugins.Accelerator.csproj b/src/BD.WTTS.Client.Plugins.Accelerator/BD.WTTS.Client.Plugins.Accelerator.csproj
index 83a0b87fc..3f6cb089f 100644
--- a/src/BD.WTTS.Client.Plugins.Accelerator/BD.WTTS.Client.Plugins.Accelerator.csproj
+++ b/src/BD.WTTS.Client.Plugins.Accelerator/BD.WTTS.Client.Plugins.Accelerator.csproj
@@ -71,6 +71,9 @@
Services
+
+ Services
+
Enums
diff --git a/src/BD.WTTS.Client.Plugins.Accelerator/Plugins/Plugin.cs b/src/BD.WTTS.Client.Plugins.Accelerator/Plugins/Plugin.cs
index 26f6e82d8..8e1891959 100644
--- a/src/BD.WTTS.Client.Plugins.Accelerator/Plugins/Plugin.cs
+++ b/src/BD.WTTS.Client.Plugins.Accelerator/Plugins/Plugin.cs
@@ -70,6 +70,17 @@ sealed class Plugin : PluginBase
// 从子进程中获取 IPC 远程服务
reverseProxyService = await ipc.GetServiceAsync(moduleName);
+#if DEBUG
+ try
+ {
+ var debugStringIPC = $"Pid: {Environment.ProcessId}, Exe: {Environment.ProcessPath}, Asm: {Assembly.GetAssembly(GetType())?.FullName}{Environment.NewLine}{reverseProxyService?.GetDebugString()}";
+ Console.WriteLine($"DebugString/IReverseProxyService: {debugStringIPC}");
+ }
+ catch (Exception ex)
+ {
+ Console.WriteLine(ex);
+ }
+#endif
if (ResourceService.IsChineseSimplified)
{
diff --git a/src/BD.WTTS.Client/BD.WTTS.Client.csproj b/src/BD.WTTS.Client/BD.WTTS.Client.csproj
index e5112e8c5..1de8d76f5 100644
--- a/src/BD.WTTS.Client/BD.WTTS.Client.csproj
+++ b/src/BD.WTTS.Client/BD.WTTS.Client.csproj
@@ -34,6 +34,9 @@
Properties
+
+ Properties
+
Properties
diff --git a/src/BD.WTTS.Client/Enums/CommandExitCode.cs b/src/BD.WTTS.Client/Enums/CommandExitCode.cs
new file mode 100644
index 000000000..4711785b9
--- /dev/null
+++ b/src/BD.WTTS.Client/Enums/CommandExitCode.cs
@@ -0,0 +1,56 @@
+namespace BD.WTTS.Enums;
+
+public enum CommandExitCode
+{
+ #region 100 ~ 5xx HttpStatusCode
+
+ ///
+ HttpStatusCodeOk = 200,
+
+ ///
+ HttpStatusBadRequest = 400,
+
+ ///
+ HttpStatusCodeInternalServerError = 500,
+
+ #endregion
+
+ #region xxxx 4 位数通用错误码
+
+ ///
+ /// 参数不能为空数组
+ ///
+ EmptyArrayArgs = 4001,
+
+ ///
+ /// IPC 管道名称不能为空
+ ///
+ EmptyPipeName = 4002,
+
+ ///
+ /// 主进程 Id 不能为空
+ ///
+ EmptyMainProcessId = 4003,
+
+ ///
+ /// 主进程 Id 找不到
+ ///
+ NotFoundMainProcessId = 4004,
+
+ ///
+ /// 获取一组插件失败
+ ///
+ GetPluginsFail = 4040,
+
+ ///
+ /// 获取单个插件失败
+ ///
+ GetPluginFail = 4041,
+
+ ///
+ /// 获取子进程启动配置失败
+ ///
+ GetSubProcessBootConfigurationFail = 4042,
+
+ #endregion
+}
\ No newline at end of file
diff --git a/src/BD.WTTS.Client/Models/AppSettings.cs b/src/BD.WTTS.Client/Models/AppSettings.cs
index d572badf2..42c230808 100644
--- a/src/BD.WTTS.Client/Models/AppSettings.cs
+++ b/src/BD.WTTS.Client/Models/AppSettings.cs
@@ -123,6 +123,10 @@ public sealed partial class AppSettings : IMicroServiceClient.ISettings
public static AppSettings Instance { get; } = GetAppSettings();
+#if DEBUG
+ internal static bool UseLocalhostApiBaseUrl { get; set; }
+#endif
+
static AppSettings GetAppSettings()
{
var s = new AppSettings()
@@ -136,8 +140,9 @@ public sealed partial class AppSettings : IMicroServiceClient.ISettings
#endif
};
#if DEBUG
- s.ApiBaseUrl = Constants.Urls.BaseUrl_API_Debug;
- //s.ApiBaseUrl = Constants.Urls.BaseUrl_API_Development;
+ s.ApiBaseUrl = UseLocalhostApiBaseUrl ?
+ Constants.Urls.BaseUrl_API_Debug :
+ Constants.Urls.BaseUrl_API_Development;
#else
s.ApiBaseUrl = Constants.Urls.BaseUrl_API_Production;
#endif
diff --git a/src/BD.WTTS.Client/Plugins/Abstractions/IPlugin.cs b/src/BD.WTTS.Client/Plugins/Abstractions/IPlugin.cs
index 00fb9bd08..e169313f3 100644
--- a/src/BD.WTTS.Client/Plugins/Abstractions/IPlugin.cs
+++ b/src/BD.WTTS.Client/Plugins/Abstractions/IPlugin.cs
@@ -1,3 +1,5 @@
+using dotnetCampus.Ipc.Pipes;
+
namespace BD.WTTS.Plugins.Abstractions;
///
@@ -69,4 +71,14 @@ public interface IPlugin : IExplicitHasValue
void OnUnhandledException(Exception ex, string name, bool? isTerminating = null);
ValueTask OnExit();
+
+ ///
+ /// 启动子进程 IPC 程序的 Main 函数
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ Task RunSubProcessMainAsync(string moduleName, string pipeName, string processId, string encodedArgs);
}
diff --git a/src/BD.WTTS.Client/Plugins/Abstractions/PluginBase.cs b/src/BD.WTTS.Client/Plugins/Abstractions/PluginBase.cs
index 94fa7151b..1f4c8ac0d 100644
--- a/src/BD.WTTS.Client/Plugins/Abstractions/PluginBase.cs
+++ b/src/BD.WTTS.Client/Plugins/Abstractions/PluginBase.cs
@@ -1,3 +1,5 @@
+using dotnetCampus.Ipc.Pipes;
+
namespace BD.WTTS.Plugins.Abstractions;
[DebuggerDisplay("{DebuggerDisplay,nq}")]
@@ -68,4 +70,45 @@ public abstract class PluginBase : IPlugin where TPlugin : PluginBase
+ /// 将参数解析为字符串
+ ///
+ ///
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ protected static string DecodeArgs(string args)
+ => HttpUtility.UrlDecode(args);
+
+ ///
+ /// 将参数解析为字符串数组
+ ///
+ ///
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ protected static string[] DecodeToArrayArgs(string args)
+ => HttpUtility.UrlDecode(args).Split(' ', StringSplitOptions.RemoveEmptyEntries);
+
+ public virtual async Task RunSubProcessMainAsync(string moduleName, string pipeName, string processId, string encodedArgs)
+ {
+ var subProcessBootConfiguration = GetSubProcessBootConfiguration(encodedArgs ?? string.Empty);
+ if (subProcessBootConfiguration == default)
+ return (int)CommandExitCode.GetSubProcessBootConfigurationFail;
+
+ var exitCode = await IPCSubProcessService.MainAsync(moduleName,
+ subProcessBootConfiguration.configureServices,
+ subProcessBootConfiguration.configureIpcProvider,
+ new[] { pipeName, processId });
+ return exitCode;
+ }
+
+ ///
+ /// 获取子进程 IPC 程序启动配置
+ ///
+ ///
+ ///
+ protected virtual (Action? configureServices, Action? configureIpcProvider) GetSubProcessBootConfiguration(string args)
+ {
+ return default;
+ }
}
diff --git a/src/BD.WTTS.Client/Plugins/PluginsCore.cs b/src/BD.WTTS.Client/Plugins/PluginsCore.cs
index fc04311fd..d4b05d400 100644
--- a/src/BD.WTTS.Client/Plugins/PluginsCore.cs
+++ b/src/BD.WTTS.Client/Plugins/PluginsCore.cs
@@ -7,20 +7,28 @@ public static class PluginsCore
static readonly HashSet ignoreDirNames = new(StringComparer.OrdinalIgnoreCase)
{
- "Update",
+ Update,
};
- internal static HashSet? LoadAssemblies()
+ public const string Accelerator = "Accelerator";
+ public const string GameAccount = "GameAccount";
+ public const string GameList = "GameList";
+ public const string ArchiSteamFarmPlus = "ArchiSteamFarmPlus";
+ public const string Authenticator = "Authenticator";
+ public const string GameTools = "GameTools";
+ public const string Update = "Update";
+
+ internal static HashSet? LoadAssemblies(params string[] loadModules)
{
HashSet? assemblies = null;
#if DEBUG // DEBUG 模式遍历项目查找模块
- var modules = new[] {
- "Accelerator",
- "GameAccount",
- "GameList",
- "ArchiSteamFarmPlus",
- "Authenticator",
- "GameTools",
+ var modules = loadModules.Any_Nullable() ? loadModules : new[] {
+ Accelerator,
+ GameAccount,
+ GameList,
+ ArchiSteamFarmPlus,
+ Authenticator,
+ GameTools,
};
foreach (var item in modules)
{
@@ -70,12 +78,12 @@ public static class PluginsCore
var pluginsPath = Path.Combine(AppContext.BaseDirectory, "modules");
if (Directory.Exists(pluginsPath))
{
- var directories = Directory.EnumerateDirectories(pluginsPath);
- foreach (var directory in directories)
+ bool EachDirectories(string directory, string? dirName = null)
{
- var dirName = Path.GetDirectoryName(directory);
- if (dirName == null) continue;
- if (ignoreDirNames.Contains(dirName)) continue;
+ dirName ??= Path.GetDirectoryName(directory);
+ if (dirName == null) return true;
+ if (ignoreDirNames.Contains(dirName))
+ return true;
var dllPath = Path.Combine(directory,
$"Steam++.Plugins.{dirName}.dll");
if (File.Exists(dllPath))
@@ -90,13 +98,35 @@ public static class PluginsCore
catch (Exception e)
{
Log.Error(TAG, e, $"AssemblyLoadFrom fail, assemblyPath: {assemblyPath}");
- continue;
+ return true;
}
assemblies ??= new();
assemblies.Add(assembly);
}
}
+ return false;
+ }
+
+ if (loadModules.Any_Nullable())
+ {
+ foreach (var loadModule in loadModules)
+ {
+ var directory = Path.Combine(pluginsPath, loadModule);
+ if (!Directory.Exists(directory))
+ continue;
+ if (EachDirectories(directory, loadModule))
+ continue;
+ }
+ }
+ else
+ {
+ var directories = Directory.EnumerateDirectories(pluginsPath);
+ foreach (var directory in directories)
+ {
+ if (EachDirectories(directory))
+ continue;
+ }
}
}
#endif
@@ -122,9 +152,9 @@ public static class PluginsCore
}
}
- internal static HashSet? InitPlugins()
+ internal static HashSet? InitPlugins(params string[] loadModules)
{
- HashSet? assemblies = LoadAssemblies();
+ HashSet? assemblies = LoadAssemblies(loadModules);
if (!assemblies.Any_Nullable()) return null;
var assemblies_ = VerifyAssemblies(assemblies).ToArray();
diff --git a/src/BD.WTTS.Client/Services.Implementation/IPC/IPCMainProcessServiceImpl.cs b/src/BD.WTTS.Client/Services.Implementation/IPC/IPCMainProcessServiceImpl.cs
index e1986bc41..b63a9fe9b 100644
--- a/src/BD.WTTS.Client/Services.Implementation/IPC/IPCMainProcessServiceImpl.cs
+++ b/src/BD.WTTS.Client/Services.Implementation/IPC/IPCMainProcessServiceImpl.cs
@@ -2,6 +2,7 @@ using dotnetCampus.Ipc.CompilerServices.GeneratedProxies;
using dotnetCampus.Ipc.Context;
using dotnetCampus.Ipc.Pipes;
using dotnetCampus.Ipc.Utils.Logging;
+using Polly;
using IPCLogLevel = dotnetCampus.Ipc.Utils.Logging.LogLevel;
using MSEXLogLevel = Microsoft.Extensions.Logging.LogLevel;
@@ -178,24 +179,26 @@ public sealed partial class IPCMainProcessServiceImpl : IPCMainProcessService
#if WINDOWS
// 启动管理员权限服务进程
- if (IPlatformService.Instance is WindowsPlatformServiceImpl windowsPlatformService)
+ Task2.InBackground(async () =>
{
- Task2.InBackground(async () =>
+ var processPath = Environment.ProcessPath;
+ processPath.ThrowIsNull();
+ var pipeName = ipcProvider.ThrowIsNull().IpcContext.PipeName;
+ const string arguments_ =
+ $"-clt {IPlatformService.IPCRoot.CommandName} {IPlatformService.IPCRoot.args_PipeName} {{0}} {IPlatformService.IPCRoot.args_ProcessId} {{1}}";
+ var arguments = string.Format(arguments_, pipeName, pid);
+ await AddDaemonWithStartSubProcessAsync(IPlatformService.IPCRoot.moduleName, async _ =>
{
- var processPath = Environment.ProcessPath;
- processPath.ThrowIsNull();
- var pipeName = ipcProvider.ThrowIsNull().IpcContext.PipeName;
- const string arguments_ =
- $"-clt {IPlatformService.IPCRoot.CommandName} {IPlatformService.IPCRoot.args_PipeName} {{0}} {IPlatformService.IPCRoot.args_ProcessId} {{1}}";
- var arguments = string.Format(arguments_, pipeName, pid);
- await AddDaemonWithStartSubProcessAsync(IPlatformService.IPCRoot.moduleName, async _ =>
+ return await Policy.HandleResult(x => x == null)
+ .RetryAsync(3)
+ .ExecuteAsync(async () =>
{
- var process = await windowsPlatformService.StartAsAdministrator(processPath, arguments);
+ var process = await WindowsPlatformServiceImpl.StartAsAdministrator(processPath, arguments);
return process;
});
- await IPlatformService.IPCRoot.SetIPC(this);
});
- }
+ await IPlatformService.IPCRoot.SetIPC(this);
+ });
#endif
}
diff --git a/src/BD.WTTS.Client/Services.Implementation/Net/HostsFileServiceImpl.cs b/src/BD.WTTS.Client/Services.Implementation/Net/HostsFileServiceImpl.cs
index 893829e62..89d4bd709 100644
--- a/src/BD.WTTS.Client/Services.Implementation/Net/HostsFileServiceImpl.cs
+++ b/src/BD.WTTS.Client/Services.Implementation/Net/HostsFileServiceImpl.cs
@@ -497,7 +497,7 @@ internal sealed class HostsFileServiceImpl
{
try
{
- s.WriteDefaultHostsContent(new FileStream(s.HostsFilePath, FileMode.OpenOrCreate));
+ s.WriteDefaultHostsContent();
Toast.Show(AppResources.CommunityFix_ResetHostsFileOk);
}
catch (Exception e)
diff --git a/src/BD.WTTS.Client/Services.Implementation/Platform/Windows/ScheduledTaskServiceImpl.PowerShell.cs b/src/BD.WTTS.Client/Services.Implementation/Platform/Windows/ScheduledTaskServiceImpl.PowerShell.cs
index 69136eb94..68734910a 100644
--- a/src/BD.WTTS.Client/Services.Implementation/Platform/Windows/ScheduledTaskServiceImpl.PowerShell.cs
+++ b/src/BD.WTTS.Client/Services.Implementation/Platform/Windows/ScheduledTaskServiceImpl.PowerShell.cs
@@ -13,14 +13,13 @@ partial class ScheduledTaskServiceImpl
/// 使用 PowerShell 实现的开机启动
/// https://docs.microsoft.com/en-us/powershell/module/scheduledtasks
///
- ///
///
///
///
///
///
///
- static async void SetBootAutoStartByPowerShell(IPlatformService platformService, bool isAutoStart, string name, string userId, string userName, string tdName, string programName)
+ static async void SetBootAutoStartByPowerShell(bool isAutoStart, string name, string userId, string userName, string tdName, string programName)
{
if (isAutoStart)
{
@@ -32,7 +31,7 @@ partial class ScheduledTaskServiceImpl
if (string.IsNullOrWhiteSpace(userName)) userName = userId;
else userName = SecurityElement.Escape(userName);
var description = SecurityElement.Escape(GetDescription(name));
- var xml = $"{description}true{userName}{userId}InteractiveToken{(platformService.IsAdministrator ? "HighestAvailable" : "LeastPrivilege")}IgnoreNewfalsefalsefalsefalsefalsePT10MPT1HtruefalsetruetruefalsefalsefalsePT0S5{programName}{arguments}{workingDirectory}";
+ var xml = $"{description}true{userName}{userId}InteractiveToken{(IPlatformService._IsAdministrator.Value ? "HighestAvailable" : "LeastPrivilege")}IgnoreNewfalsefalsefalsefalsefalsePT10MPT1HtruefalsetruetruefalsefalsefalsePT0S5{programName}{arguments}{workingDirectory}";
await RunPowerShellSinglePipeAsync($"Register-ScheduledTask -Force -TaskName '{Escape(tdName)}' -Xml '{Escape(xml)}';exit");
}
else
diff --git a/src/BD.WTTS.Client/Services.Implementation/Platform/Windows/ScheduledTaskServiceImpl.cs b/src/BD.WTTS.Client/Services.Implementation/Platform/Windows/ScheduledTaskServiceImpl.cs
index ceb9bbefa..569b6517e 100644
--- a/src/BD.WTTS.Client/Services.Implementation/Platform/Windows/ScheduledTaskServiceImpl.cs
+++ b/src/BD.WTTS.Client/Services.Implementation/Platform/Windows/ScheduledTaskServiceImpl.cs
@@ -6,7 +6,7 @@ namespace BD.WTTS.Services.Implementation;
sealed partial class ScheduledTaskServiceImpl : IScheduledTaskService
{
- void IScheduledTaskService.SetBootAutoStart(IPlatformService platformService, bool isAutoStart, string name)
+ void IScheduledTaskService.SetBootAutoStart(bool isAutoStart, string name)
{
try
{
@@ -16,7 +16,7 @@ sealed partial class ScheduledTaskServiceImpl : IScheduledTaskService
var userId = hasSid ? identity.User!.ToString() : userName;
var tdName = hasSid ? userId : userId.Replace(Path.DirectorySeparatorChar, '_');
tdName = $"{name}_{{{tdName}}}";
- SetBootAutoStartByPowerShell(platformService, isAutoStart, name, userId, userName, tdName, IApplication.ProgramName);
+ SetBootAutoStartByPowerShell(isAutoStart, name, userId, userName, tdName, IApplication.ProgramName);
}
catch (Exception e)
{
diff --git a/src/BD.WTTS.Client/Services.Implementation/Platform/Windows/WindowsPlatformServiceImpl.BypassUAC.cs b/src/BD.WTTS.Client/Services.Implementation/Platform/Windows/WindowsPlatformServiceImpl.BypassUAC.cs
index 13cc53fd6..403712cdf 100644
--- a/src/BD.WTTS.Client/Services.Implementation/Platform/Windows/WindowsPlatformServiceImpl.BypassUAC.cs
+++ b/src/BD.WTTS.Client/Services.Implementation/Platform/Windows/WindowsPlatformServiceImpl.BypassUAC.cs
@@ -44,7 +44,7 @@ partial class WindowsPlatformServiceImpl
///
///
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static async Task StartAsAdministratorByBypassUAC(string fileName, string? arguments = null)
+ internal static async Task StartAsAdministratorByBypassUAC(string fileName, string? arguments = null)
{
/** 33. Author: winscripting.blog
* https://github.com/hfiref0x/UACME
@@ -68,6 +68,15 @@ partial class WindowsPlatformServiceImpl
if (!File.Exists(targetName))
return null;
+ var processPath = Environment.ProcessPath;
+ processPath.ThrowIsNull();
+ if (fileName != processPath) // 仅允许启动自己
+ throw new ArgumentOutOfRangeException(nameof(fileName));
+
+ var processName = Path.GetFileNameWithoutExtension(fileName);
+ if (string.IsNullOrWhiteSpace(processName))
+ throw new ArgumentNullException(nameof(processName));
+
classes = Registry.CurrentUser.OpenSubKey(@"Software\Classes", true);
using var command = classes!.CreateSubKey(@"ms-settings\Shell\Open\command", true);
command.SetValue("DelegateExecute", "");
@@ -80,19 +89,21 @@ partial class WindowsPlatformServiceImpl
WindowStyle = ProcessWindowStyle.Hidden,
FileName = targetName,
};
+ var processs_start_before = new HashSet(
+ Process.GetProcessesByName(processName).Select(x => x.Id));
var process = Process.Start(psi);
process!.WaitForExit(6000);
- var processName = Path.GetFileNameWithoutExtension(fileName);
for (int i = 0; i < 7; i++)
{
- var processs = Process.GetProcessesByName(processName);
- foreach (var item in processs)
+ var processs_start_after = Process.GetProcessesByName(processName);
+ foreach (var item in processs_start_after)
{
+ if (processs_start_before.Contains(item.Id))
+ continue;
+
if (IsProcessElevated(item))
- {
return item;
- }
}
await Task.Delay(800);
@@ -128,24 +139,31 @@ partial class WindowsPlatformServiceImpl
///
///
///
- public async ValueTask StartAsAdministrator(string fileName, string? arguments = null)
+ internal static async ValueTask StartAsAdministrator(string fileName, string? arguments = null)
{
- IPlatformService thiz = this;
- if (thiz.IsAdministrator)
+ if (IPlatformService._IsAdministrator.Value)
return Process2.Start(fileName, arguments);
var process = await StartAsAdministratorByBypassUAC(fileName, arguments);
if (process != null)
return process;
- ProcessStartInfo psi = new()
+ try
{
- FileName = fileName,
- Arguments = arguments,
- UseShellExecute = true,
- Verb = "runas",
- };
- return Process.Start(psi);
+ ProcessStartInfo psi = new()
+ {
+ FileName = fileName,
+ Arguments = arguments,
+ UseShellExecute = true,
+ Verb = "runas",
+ };
+ var process_runas = Process.Start(psi);
+ return process_runas;
+ }
+ catch
+ {
+ return null;
+ }
}
}
#endif
\ No newline at end of file
diff --git a/src/BD.WTTS.Client/Services.Implementation/Platform/Windows/WindowsPlatformServiceImpl.SystemOnOff.cs b/src/BD.WTTS.Client/Services.Implementation/Platform/Windows/WindowsPlatformServiceImpl.SystemOnOff.cs
index 25bbef5c1..c02002d6e 100644
--- a/src/BD.WTTS.Client/Services.Implementation/Platform/Windows/WindowsPlatformServiceImpl.SystemOnOff.cs
+++ b/src/BD.WTTS.Client/Services.Implementation/Platform/Windows/WindowsPlatformServiceImpl.SystemOnOff.cs
@@ -51,7 +51,7 @@ partial class WindowsPlatformServiceImpl
{
var scheduledTaskService = IScheduledTaskService.Instance;
scheduledTaskService.ThrowIsNull();
- scheduledTaskService.SetBootAutoStart(this, isAutoStart, name);
+ scheduledTaskService.SetBootAutoStart(isAutoStart, name);
}
}
}
diff --git a/src/BD.WTTS.Client/Services.Implementation/Platform/Windows/WindowsPlatformServiceImpl.cs b/src/BD.WTTS.Client/Services.Implementation/Platform/Windows/WindowsPlatformServiceImpl.cs
index eb614a608..35f75da9c 100644
--- a/src/BD.WTTS.Client/Services.Implementation/Platform/Windows/WindowsPlatformServiceImpl.cs
+++ b/src/BD.WTTS.Client/Services.Implementation/Platform/Windows/WindowsPlatformServiceImpl.cs
@@ -122,8 +122,7 @@ sealed partial class WindowsPlatformServiceImpl : IPlatformService
public Process? StartAsInvoker(string fileName, string? arguments = null)
{
- IPlatformService thiz = this;
- if (thiz.IsAdministrator)
+ if (IPlatformService._IsAdministrator.Value)
{
// runas /trustlevel:0x20000 没有真正的降权,只是作为具有限制特权,使用 explorer 最好,但不接受参数,可以创建一个临时cmd脚本启动
//return StartAsInvokerByRunas(fileName, arguments);
diff --git a/src/BD.WTTS.Client/Services.Implementation/Steam/SteamServiceImpl2.cs b/src/BD.WTTS.Client/Services.Implementation/Steam/SteamServiceImpl2.cs
index 255a73985..7d4bb1491 100644
--- a/src/BD.WTTS.Client/Services.Implementation/Steam/SteamServiceImpl2.cs
+++ b/src/BD.WTTS.Client/Services.Implementation/Steam/SteamServiceImpl2.cs
@@ -42,7 +42,7 @@ sealed class SteamServiceImpl2 : SteamServiceBaseImpl, ISteamConnectService
protected override Dictionary? HideGameList => serviceProvider.GetService()?.HideGameList;
- //protected override string? GetString(string name) => AppResources.ResourceManager.GetString(name);
+ protected override string? GetString(string name) => AppResources.ResourceManager.GetString(name);
protected override Process? StartAsInvoker(string fileName, string? arguments = null)
{
diff --git a/src/BD.WTTS.Client/Services/Platform/IPC/IPCPlatformService.cs b/src/BD.WTTS.Client/Services/Platform/IPC/IPCPlatformService.cs
index 61afde338..59da0f251 100644
--- a/src/BD.WTTS.Client/Services/Platform/IPC/IPCPlatformService.cs
+++ b/src/BD.WTTS.Client/Services/Platform/IPC/IPCPlatformService.cs
@@ -6,8 +6,13 @@ namespace BD.WTTS.Services;
///
/// 用于 IPC 的平台实现的服务
///
-[IpcPublic(Timeout = 55000, IgnoresIpcException = false)]
+[IpcPublic(Timeout = 9000, IgnoresIpcException = false)]
public partial interface IPCPlatformService
{
-
+#if DEBUG
+ string GetDebugString()
+ {
+ return $"Pid: {Environment.ProcessId}, Exe: {Environment.ProcessPath}, Asm: {Assembly.GetAssembly(GetType())?.FullName}";
+ }
+#endif
}
\ No newline at end of file
diff --git a/src/BD.WTTS.Client/Services/Platform/IPlatformService.IsAdministrator.cs b/src/BD.WTTS.Client/Services/Platform/IPlatformService.IsAdministrator.cs
index 01d247668..19234cfc2 100644
--- a/src/BD.WTTS.Client/Services/Platform/IPlatformService.IsAdministrator.cs
+++ b/src/BD.WTTS.Client/Services/Platform/IPlatformService.IsAdministrator.cs
@@ -3,21 +3,21 @@ namespace BD.WTTS.Services;
partial interface IPlatformService
{
+ internal static readonly Lazy _IsAdministrator = new(() =>
+ {
+#if WINDOWS
+ using WindowsIdentity identity = WindowsIdentity.GetCurrent();
+ return identity.IsSystem || new WindowsPrincipal(identity)
+ .IsInRole(WindowsBuiltInRole.Administrator);
+#elif MACCATALYST || MACOS || LINUX || IOS || ANDROID
+ return Interop.Libc.GetEUID() == 0;
+#else
+ throw new PlatformNotSupportedException();
+#endif
+ });
+
///
/// 当前程序是否以 Administrator/System(Windows) 或 Root(FreeBSD/Linux/MacOS/Android/iOS) 权限运行
///
- bool IsAdministrator
- {
- get
- {
-#if WINDOWS
- using WindowsIdentity identity = WindowsIdentity.GetCurrent();
- return identity.IsSystem || new WindowsPrincipal(identity)
- .IsInRole(WindowsBuiltInRole.Administrator);
-#elif MACCATALYST || MACOS || LINUX || IOS || ANDROID
- return Interop.Libc.GetEUID() == 0;
- throw new PlatformNotSupportedException();
-#endif
- }
- }
+ bool IsAdministrator => _IsAdministrator.Value;
}
\ No newline at end of file
diff --git a/src/BD.WTTS.Client/Services/Platform/IPlatformService.Net.Hosts.cs b/src/BD.WTTS.Client/Services/Platform/IPlatformService.Net.Hosts.cs
index 731af0cbc..bcc39cc16 100644
--- a/src/BD.WTTS.Client/Services/Platform/IPlatformService.Net.Hosts.cs
+++ b/src/BD.WTTS.Client/Services/Platform/IPlatformService.Net.Hosts.cs
@@ -27,6 +27,18 @@ partial interface IPlatformService
[Obsolete("use WriteDefaultHostsContent(Stream", true)]
string DefaultHostsContent => string.Empty;
+ ///
+ /// 写入默认 hosts 文件内容
+ ///
+ void WriteDefaultHostsContent()
+ {
+ var fileStream = new FileStream(HostsFilePath,
+ FileMode.OpenOrCreate,
+ FileAccess.Write,
+ FileShare.ReadWrite | FileShare.Delete);
+ WriteDefaultHostsContent(fileStream);
+ }
+
///
/// 写入默认 hosts 文件内容
///
diff --git a/src/BD.WTTS.Client/Services/Platform/IPlatformService.cs b/src/BD.WTTS.Client/Services/Platform/IPlatformService.cs
index 472e9fcdc..637198cfd 100644
--- a/src/BD.WTTS.Client/Services/Platform/IPlatformService.cs
+++ b/src/BD.WTTS.Client/Services/Platform/IPlatformService.cs
@@ -33,6 +33,17 @@ public partial interface IPlatformService : IPCPlatformService
{
var iPCPlatformService = await ipc.GetServiceAsync(moduleName);
iPCPlatformService.ThrowIsNull();
+#if DEBUG
+ try
+ {
+ var debugStringIPC = $"Pid: {Environment.ProcessId}, Exe: {Environment.ProcessPath}, Asm: {Assembly.GetAssembly(typeof(IPlatformService))?.FullName}{Environment.NewLine}{iPCPlatformService.GetDebugString()}";
+ Console.WriteLine($"DebugString/IPCPlatformService: {debugStringIPC}");
+ }
+ catch (Exception ex)
+ {
+ Console.WriteLine(ex);
+ }
+#endif
tcs.TrySetResult(iPCPlatformService);
}
catch (Exception ex)
diff --git a/src/BD.WTTS.Client/Services/Platform/Windows/IScheduledTaskService.cs b/src/BD.WTTS.Client/Services/Platform/Windows/IScheduledTaskService.cs
index 6bbf24fb8..f0df6d0d7 100644
--- a/src/BD.WTTS.Client/Services/Platform/Windows/IScheduledTaskService.cs
+++ b/src/BD.WTTS.Client/Services/Platform/Windows/IScheduledTaskService.cs
@@ -12,9 +12,8 @@ public interface IScheduledTaskService
///
/// 开机启动使用 taskschd.msc 实现
///
- ///
///
///
- void SetBootAutoStart(IPlatformService platformService, bool isAutoStart, string name);
+ void SetBootAutoStart(bool isAutoStart, string name);
}
#endif
\ No newline at end of file
diff --git a/src/BD.WTTS.Client/Startup/Startup.Commands.cs b/src/BD.WTTS.Client/Startup/Startup.Commands.cs
index a4eb6aa77..a059cc0ed 100644
--- a/src/BD.WTTS.Client/Startup/Startup.Commands.cs
+++ b/src/BD.WTTS.Client/Startup/Startup.Commands.cs
@@ -2,12 +2,14 @@
using dotnetCampus.Ipc.CompilerServices.GeneratedProxies;
using System.CommandLine;
using System.CommandLine.NamingConventionBinder;
+#endif
// ReSharper disable once CheckNamespace
namespace BD.WTTS;
partial class Startup // 自定义控制台命令参数
{
+#if (WINDOWS || MACCATALYST || MACOS || LINUX) && !(IOS || ANDROID)
[MethodImpl(MethodImplOptions.AggressiveInlining)]
void ConfigureCommands(RootCommand rootCommand)
{
@@ -44,8 +46,12 @@ partial class Startup // 自定义控制台命令参数
var devtools = new Command("devtools");
devtools.AddOption(new Option("-disable_gpu", () => false, "禁用 GPU 硬件加速"));
devtools.AddOption(new Option("-use_wgl", () => false, "使用 Native OpenGL(仅 Windows)"));
- devtools.Handler = CommandHandler.Create((bool disable_gpu, bool use_wgl) =>
+ devtools.AddOption(new Option("-use_localhost", () => false, "使用本机服务端"));
+ devtools.Handler = CommandHandler.Create((bool disable_gpu, bool use_wgl, bool use_localhost) =>
{
+#if DEBUG
+ AppSettings.UseLocalhostApiBaseUrl = use_localhost;
+#endif
IsMainProcess = true;
IsConsoleLineToolProcess = false;
@@ -303,6 +309,13 @@ partial class Startup // 自定义控制台命令参数
{
Handler = CommandHandler.Create(async (string n, string p) =>
{
+ if (string.IsNullOrWhiteSpace(n) ||
+ string.IsNullOrWhiteSpace(p))
+ return 400;
+
+ if (!IPlatformService._IsAdministrator.Value)
+ return 401;
+
RunUIApplication(AppServicesLevel.IPCRoot | AppServicesLevel.Hosts);
await WaitConfiguredServices;
@@ -329,14 +342,35 @@ partial class Startup // 自定义控制台命令参数
rootCommand.AddCommand(sudo);
#endif
- // -clt plugins {插件名} {插件需要解析的参数}
+ // -clt plugins -l {AppServicesLevel} -m {插件名} -n {PipeName} -p {ProcessId} -a {插件需要解析的参数}
var plugins = new Command("plugins", "插件使用的 IPC 服务进程")
{
- Handler = CommandHandler.Create(() =>
+ Handler = CommandHandler.Create(async (uint l, string m, string n, string p, string a) =>
{
- // TODO
+ if (string.IsNullOrWhiteSpace(n) ||
+ string.IsNullOrWhiteSpace(p))
+ return (int)CommandExitCode.HttpStatusBadRequest;
+
+ var level = (AppServicesLevel)l;
+ RunUIApplication(level, loadModules: m);
+ await WaitConfiguredServices;
+
+ if (!TryGetPlugins(out var plugins))
+ return (int)CommandExitCode.GetPluginsFail;
+
+ var plugin = plugins.FirstOrDefault(x => x.Name == m);
+ if (plugin == null)
+ return (int)CommandExitCode.GetPluginFail;
+
+ var exitCode = await plugin.RunSubProcessMainAsync(m, n, p, a);
+ return exitCode;
}),
};
+ plugins.AddOption(new Option("-l", "AppServicesLevel"));
+ plugins.AddOption(new Option("-m", "需要加载的模块名称"));
+ plugins.AddOption(new Option("-a", "需要解析的参数,使用 HttpUtility.UrlDecode 解码"));
+ plugins.AddOption(new Option(IPlatformService.IPCRoot.args_PipeName, "IPC 管道名"));
+ plugins.AddOption(new Option(IPlatformService.IPCRoot.args_ProcessId, "主进程 Id"));
rootCommand.AddCommand(plugins);
// -clt types
@@ -345,8 +379,16 @@ partial class Startup // 自定义控制台命令参数
Handler = CommandHandler.Create(() =>
{
int exitCode = default;
- using var assemblies_stream = new FileStream(Path.Combine(IOPath.CacheDirectory, "assemblies.txt"), FileMode.OpenOrCreate, FileAccess.Write, FileShare.ReadWrite | FileShare.Delete);
- using var types_stream = new FileStream(Path.Combine(IOPath.CacheDirectory, "types.txt"), FileMode.OpenOrCreate, FileAccess.Write, FileShare.ReadWrite | FileShare.Delete);
+ using var assemblies_stream = new FileStream(Path.Combine(
+ IOPath.CacheDirectory, "assemblies.txt"),
+ FileMode.OpenOrCreate,
+ FileAccess.Write,
+ FileShare.ReadWrite | FileShare.Delete);
+ using var types_stream = new FileStream(Path.Combine(
+ IOPath.CacheDirectory, "types.txt"),
+ FileMode.OpenOrCreate,
+ FileAccess.Write,
+ FileShare.ReadWrite | FileShare.Delete);
try
{
var assemblies_ = AppDomain.CurrentDomain.GetAssemblies();
@@ -386,12 +428,12 @@ partial class Startup // 自定义控制台命令参数
}
}
}
- return exitCode = 200;
+ return exitCode = (int)CommandExitCode.HttpStatusCodeOk;
}
catch (Exception ex)
{
Console.WriteLine(ex);
- return exitCode = 500;
+ return exitCode = (int)CommandExitCode.HttpStatusCodeInternalServerError;
}
finally
{
@@ -410,5 +452,5 @@ partial class Startup // 自定义控制台命令参数
};
rootCommand.AddCommand(types);
}
-}
-#endif
\ No newline at end of file
+#endif
+}
\ No newline at end of file
diff --git a/src/BD.WTTS.Client/Startup/Startup.Host.cs b/src/BD.WTTS.Client/Startup/Startup.Host.cs
index 093c670ab..cc2afad79 100644
--- a/src/BD.WTTS.Client/Startup/Startup.Host.cs
+++ b/src/BD.WTTS.Client/Startup/Startup.Host.cs
@@ -6,7 +6,10 @@ namespace BD.WTTS;
partial class Startup // 配置 Host
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- protected void RunUIApplication(AppServicesLevel? level = null, Func? sendMessage = null)
+ protected void RunUIApplication(
+ AppServicesLevel? level = null,
+ Func? sendMessage = null,
+ params string[] loadModules)
{
#if STARTUP_WATCH_TRACE || DEBUG
WatchTrace.Start();
@@ -28,7 +31,7 @@ partial class Startup // 配置 Host
#if (WINDOWS || MACCATALYST || MACOS || LINUX) && !(IOS || ANDROID)
if (IsMainProcess)
{
- plugins = PluginsCore.InitPlugins();
+ plugins = PluginsCore.InitPlugins(loadModules);
HasPlugins = plugins.Any_Nullable();
#if STARTUP_WATCH_TRACE || DEBUG
WatchTrace.Record("InitPlugins");
diff --git a/src/BD.WTTS.Client/Startup/Startup.OnStartup.cs b/src/BD.WTTS.Client/Startup/Startup.OnStartup.cs
index 5d6ec2b6e..98b88cc40 100644
--- a/src/BD.WTTS.Client/Startup/Startup.OnStartup.cs
+++ b/src/BD.WTTS.Client/Startup/Startup.OnStartup.cs
@@ -31,13 +31,13 @@ partial class Startup // OnStartup
if (IsMainProcess)
{
- Task.Run(async () =>
+ Task2.InBackground(async () =>
{
await ActiveUserRecordAsync(ActiveUserAnonymousStatisticType.OnStartup);
});
if (GeneralSettings.AutoCheckAppUpdate.Value)
{
- Task.Run(async () =>
+ Task2.InBackground(async () =>
{
await IApplicationUpdateService.Instance
.CheckUpdateAsync(showIsExistUpdateFalse: false);