diff --git a/src/BD.WTTS.Client.IPC/Services/IPCSubProcessService.cs b/src/BD.WTTS.Client.IPC/Services/IPCSubProcessService.cs
index ba9f0f60b..8f08309f6 100644
--- a/src/BD.WTTS.Client.IPC/Services/IPCSubProcessService.cs
+++ b/src/BD.WTTS.Client.IPC/Services/IPCSubProcessService.cs
@@ -1,4 +1,5 @@
using dotnetCampus.Ipc.Pipes;
+using ExitCode = BD.WTTS.Startup.CommandExitCode;
namespace BD.WTTS.Services;
@@ -24,11 +25,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 +33,8 @@ public interface IPCSubProcessService : IDisposable
/// 子进程 IPC 程序启动通用函数
///
///
- ///
- ///
+ /// 配置子进程的依赖注入服务
+ /// 配置 IPC 服务
///
///
static async Task MainAsync(
@@ -48,15 +44,15 @@ public interface IPCSubProcessService : IDisposable
params string[] args)
{
if (args.Length < 2)
- return ExitCode_EmptyArrayArgs;
+ return (int)ExitCode.EmptyArrayArgs;
var pipeName = args[0];
if (string.IsNullOrWhiteSpace(pipeName))
- return ExitCode_EmptyPipeName;
+ return (int)ExitCode.EmptyPipeName;
if (!int.TryParse(args[1], out var pid))
- return ExitCode_EmptyMainProcessId;
+ return (int)ExitCode.EmptyMainProcessId;
var mainProcess = Process.GetProcessById(pid);
if (mainProcess == null)
- return ExitCode_NotFoundMainProcessId;
+ return (int)ExitCode.NotFoundMainProcessId;
TaskCompletionSource tcs = new();
mainProcess.EnableRaisingEvents = true;
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..36d293256 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)Startup.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..226eb0c17 100644
--- a/src/BD.WTTS.Client/Services.Implementation/IPC/IPCMainProcessServiceImpl.cs
+++ b/src/BD.WTTS.Client/Services.Implementation/IPC/IPCMainProcessServiceImpl.cs
@@ -178,24 +178,21 @@ 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 _ =>
- {
- var process = await windowsPlatformService.StartAsAdministrator(processPath, arguments);
- return process;
- });
- await IPlatformService.IPCRoot.SetIPC(this);
+ var process = await WindowsPlatformServiceImpl.StartAsAdministrator(processPath, arguments);
+ return process;
});
- }
+ await IPlatformService.IPCRoot.SetIPC(this);
+ });
#endif
}
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..e2175f46e 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,10 +139,9 @@ 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);
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/Platform/IPlatformService.IsAdministrator.cs b/src/BD.WTTS.Client/Services/Platform/IPlatformService.IsAdministrator.cs
index 01d247668..2cdc3ca22 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/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..bf79bd445 100644
--- a/src/BD.WTTS.Client/Startup/Startup.Commands.cs
+++ b/src/BD.WTTS.Client/Startup/Startup.Commands.cs
@@ -303,6 +303,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 +336,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 +373,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 +422,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 +446,60 @@ partial class Startup // 自定义控制台命令参数
};
rootCommand.AddCommand(types);
}
+
+ 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
+ }
}
#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");