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);