mirror of
https://github.com/BeyondDimension/SteamTools.git
synced 2026-10-28 23:19:53 +08:00
Merge branch 'v3.x' of https://github.com/BeyondDimension/SteamTools into v3.x
This commit is contained in:
+1
-1
Submodule ref/DirectoryPackages updated: bf939f9309...3d42ed8bcb
@@ -26,9 +26,9 @@
|
||||
<Compile Include="..\ImplicitUsings.Nito.cs">
|
||||
<LinkBase>Properties</LinkBase>
|
||||
</Compile>
|
||||
<!--<Compile Include="..\ImplicitUsings.Enums.cs">
|
||||
<Compile Include="..\ImplicitUsings.Enums.cs">
|
||||
<LinkBase>Properties</LinkBase>
|
||||
</Compile>-->
|
||||
</Compile>
|
||||
<Compile Include="..\BD.WTTS.Client\Services\IPC\IPCSubProcessModuleService.cs">
|
||||
<LinkBase>Services</LinkBase>
|
||||
</Compile>
|
||||
@@ -38,6 +38,9 @@
|
||||
<Compile Include="..\BD.WTTS.Client\Services\UI\Widgets\IPC\*.cs">
|
||||
<LinkBase>Services\UI\Widgets</LinkBase>
|
||||
</Compile>
|
||||
<Compile Include="..\BD.WTTS.Client\Enums\CommandExitCode.cs">
|
||||
<LinkBase>Enums</LinkBase>
|
||||
</Compile>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
@@ -46,6 +49,10 @@
|
||||
<PackageReference Include="dotnetCampus.Ipc" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Folder Include="Properties\" />
|
||||
</ItemGroup>
|
||||
|
||||
<Import Project="..\TFM_NET7_WITH_ALL.props" />
|
||||
|
||||
</Project>
|
||||
|
||||
@@ -24,11 +24,6 @@ public interface IPCSubProcessService : IDisposable
|
||||
/// <returns></returns>
|
||||
T? GetService<T>() 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 程序启动通用函数
|
||||
/// </summary>
|
||||
/// <param name="moduleName"></param>
|
||||
/// <param name="configureServices"></param>
|
||||
/// <param name="configureIpcProvider"></param>
|
||||
/// <param name="configureServices">配置子进程的依赖注入服务</param>
|
||||
/// <param name="configureIpcProvider">配置 IPC 服务</param>
|
||||
/// <param name="args"></param>
|
||||
/// <returns></returns>
|
||||
static async Task<int> 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;
|
||||
|
||||
+6
@@ -31,6 +31,12 @@
|
||||
<Compile Include="..\ImplicitUsings.Nito.cs">
|
||||
<LinkBase>Properties</LinkBase>
|
||||
</Compile>
|
||||
<Compile Include="..\ImplicitUsings.Models.cs">
|
||||
<LinkBase>Properties</LinkBase>
|
||||
</Compile>
|
||||
<Compile Include="..\ImplicitUsings.Enums.cs">
|
||||
<LinkBase>Properties</LinkBase>
|
||||
</Compile>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
+1
-1
@@ -4,7 +4,7 @@
|
||||
using System.Net.NetworkInformation;
|
||||
|
||||
// ReSharper disable once CheckNamespace
|
||||
namespace BD.WTTS.Models;
|
||||
namespace BD.WTTS.Models.Abstractions;
|
||||
|
||||
partial interface IReverseProxyConfig
|
||||
{
|
||||
+1
-1
@@ -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
|
||||
{
|
||||
@@ -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 =>
|
||||
|
||||
@@ -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;
|
||||
+1
-1
@@ -13,7 +13,7 @@ sealed class CertService
|
||||
readonly ILogger<CertService> logger;
|
||||
readonly IReverseProxyConfig reverseProxyConfig;
|
||||
|
||||
IReverseProxyService ReverseProxyService => reverseProxyConfig.Service;
|
||||
ReverseProxyServiceImpl ReverseProxyService => reverseProxyConfig.Service;
|
||||
|
||||
/// <summary>
|
||||
/// 获取 CER 证书文件路径
|
||||
|
||||
+1
-1
@@ -9,7 +9,7 @@ sealed class LazyReverseProxyServiceImpl : IReverseProxyService
|
||||
static IReverseProxyService instance() => Ioc.Get<IReverseProxyService>();
|
||||
#pragma warning restore IDE1006 // 命名样式
|
||||
|
||||
public ICertificateManager CertificateManager => instance().CertificateManager;
|
||||
//public ICertificateManager CertificateManager => instance().CertificateManager;
|
||||
|
||||
public bool ProxyRunning => instance().ProxyRunning;
|
||||
|
||||
|
||||
+1
-1
@@ -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;
|
||||
|
||||
+1
-1
@@ -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;
|
||||
|
||||
+1
-1
@@ -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;
|
||||
|
||||
+1
-1
@@ -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;
|
||||
|
||||
+1
-1
@@ -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;
|
||||
|
||||
+8
-1
@@ -6,7 +6,7 @@ namespace BD.WTTS.Services;
|
||||
/// <summary>
|
||||
/// 反向代理服务
|
||||
/// </summary>
|
||||
[IpcPublic(Timeout = 55000, IgnoresIpcException = false)]
|
||||
[IpcPublic(Timeout = 9000, IgnoresIpcException = false)]
|
||||
public partial interface IReverseProxyService : IDisposable, IReverseProxySettings
|
||||
{
|
||||
/// <summary>
|
||||
@@ -52,6 +52,13 @@ public partial interface IReverseProxyService : IDisposable, IReverseProxySettin
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
ValueTask StopProxyAsync();
|
||||
|
||||
#if DEBUG
|
||||
string GetDebugString()
|
||||
{
|
||||
return $"Pid: {Environment.ProcessId}, Exe: {Environment.ProcessPath}, Asm: {Assembly.GetAssembly(GetType())?.FullName}";
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -3,8 +3,6 @@ namespace BD.WTTS.Services;
|
||||
|
||||
partial interface IReverseProxyService
|
||||
{
|
||||
ICertificateManager CertificateManager { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 将 PEM 证书公钥写入 GOG GALAXY
|
||||
/// </summary>
|
||||
|
||||
@@ -71,6 +71,9 @@
|
||||
<Compile Include="..\BD.WTTS.Client.Plugins.Accelerator.ReverseProxy\Services\IReverseProxyService.Constants.cs">
|
||||
<LinkBase>Services</LinkBase>
|
||||
</Compile>
|
||||
<Compile Include="..\BD.WTTS.Client.Plugins.Accelerator.ReverseProxy\Services\IReverseProxyService.cs">
|
||||
<LinkBase>Services</LinkBase>
|
||||
</Compile>
|
||||
<Compile Include="..\BD.WTTS.Client.Plugins.Accelerator.ReverseProxy\Enums\ExternalProxyType.cs">
|
||||
<LinkBase>Enums</LinkBase>
|
||||
</Compile>
|
||||
|
||||
@@ -70,6 +70,17 @@ sealed class Plugin : PluginBase<Plugin>
|
||||
|
||||
// 从子进程中获取 IPC 远程服务
|
||||
reverseProxyService = await ipc.GetServiceAsync<IReverseProxyService>(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)
|
||||
{
|
||||
|
||||
@@ -34,6 +34,9 @@
|
||||
<Compile Include="..\ImplicitUsings.Models.cs">
|
||||
<LinkBase>Properties</LinkBase>
|
||||
</Compile>
|
||||
<Compile Include="..\ImplicitUsings.Enums.cs">
|
||||
<LinkBase>Properties</LinkBase>
|
||||
</Compile>
|
||||
<Compile Include="..\ImplicitUsings.UI.cs">
|
||||
<LinkBase>Properties</LinkBase>
|
||||
</Compile>
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
namespace BD.WTTS.Enums;
|
||||
|
||||
public enum CommandExitCode
|
||||
{
|
||||
#region 100 ~ 5xx HttpStatusCode
|
||||
|
||||
/// <inheritdoc cref="HttpStatusCode.OK"/>
|
||||
HttpStatusCodeOk = 200,
|
||||
|
||||
/// <inheritdoc cref="HttpStatusCode.BadRequest"/>
|
||||
HttpStatusBadRequest = 400,
|
||||
|
||||
/// <inheritdoc cref="HttpStatusCode.InternalServerError"/>
|
||||
HttpStatusCodeInternalServerError = 500,
|
||||
|
||||
#endregion
|
||||
|
||||
#region xxxx 4 位数通用错误码
|
||||
|
||||
/// <summary>
|
||||
/// 参数不能为空数组
|
||||
/// </summary>
|
||||
EmptyArrayArgs = 4001,
|
||||
|
||||
/// <summary>
|
||||
/// IPC 管道名称不能为空
|
||||
/// </summary>
|
||||
EmptyPipeName = 4002,
|
||||
|
||||
/// <summary>
|
||||
/// 主进程 Id 不能为空
|
||||
/// </summary>
|
||||
EmptyMainProcessId = 4003,
|
||||
|
||||
/// <summary>
|
||||
/// 主进程 Id 找不到
|
||||
/// </summary>
|
||||
NotFoundMainProcessId = 4004,
|
||||
|
||||
/// <summary>
|
||||
/// 获取一组插件失败
|
||||
/// </summary>
|
||||
GetPluginsFail = 4040,
|
||||
|
||||
/// <summary>
|
||||
/// 获取单个插件失败
|
||||
/// </summary>
|
||||
GetPluginFail = 4041,
|
||||
|
||||
/// <summary>
|
||||
/// 获取子进程启动配置失败
|
||||
/// </summary>
|
||||
GetSubProcessBootConfigurationFail = 4042,
|
||||
|
||||
#endregion
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
using dotnetCampus.Ipc.Pipes;
|
||||
|
||||
namespace BD.WTTS.Plugins.Abstractions;
|
||||
|
||||
/// <summary>
|
||||
@@ -69,4 +71,14 @@ public interface IPlugin : IExplicitHasValue
|
||||
void OnUnhandledException(Exception ex, string name, bool? isTerminating = null);
|
||||
|
||||
ValueTask OnExit();
|
||||
|
||||
/// <summary>
|
||||
/// 启动子进程 IPC 程序的 Main 函数
|
||||
/// </summary>
|
||||
/// <param name="moduleName"></param>
|
||||
/// <param name="pipeName"></param>
|
||||
/// <param name="processId"></param>
|
||||
/// <param name="encodedArgs"></param>
|
||||
/// <returns></returns>
|
||||
Task<int> RunSubProcessMainAsync(string moduleName, string pipeName, string processId, string encodedArgs);
|
||||
}
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
using dotnetCampus.Ipc.Pipes;
|
||||
|
||||
namespace BD.WTTS.Plugins.Abstractions;
|
||||
|
||||
[DebuggerDisplay("{DebuggerDisplay,nq}")]
|
||||
@@ -68,4 +70,45 @@ public abstract class PluginBase<TPlugin> : IPlugin where TPlugin : PluginBase<T
|
||||
{
|
||||
return ValueTask.CompletedTask;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 将参数解析为字符串
|
||||
/// </summary>
|
||||
/// <param name="args"></param>
|
||||
/// <returns></returns>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
protected static string DecodeArgs(string args)
|
||||
=> HttpUtility.UrlDecode(args);
|
||||
|
||||
/// <summary>
|
||||
/// 将参数解析为字符串数组
|
||||
/// </summary>
|
||||
/// <param name="args"></param>
|
||||
/// <returns></returns>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
protected static string[] DecodeToArrayArgs(string args)
|
||||
=> HttpUtility.UrlDecode(args).Split(' ', StringSplitOptions.RemoveEmptyEntries);
|
||||
|
||||
public virtual async Task<int> 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;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取子进程 IPC 程序启动配置
|
||||
/// </summary>
|
||||
/// <param name="args"></param>
|
||||
/// <returns></returns>
|
||||
protected virtual (Action<IServiceCollection>? configureServices, Action<IpcProvider>? configureIpcProvider) GetSubProcessBootConfiguration(string args)
|
||||
{
|
||||
return default;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,20 +7,28 @@ public static class PluginsCore
|
||||
|
||||
static readonly HashSet<string> ignoreDirNames = new(StringComparer.OrdinalIgnoreCase)
|
||||
{
|
||||
"Update",
|
||||
Update,
|
||||
};
|
||||
|
||||
internal static HashSet<Assembly>? 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<Assembly>? LoadAssemblies(params string[] loadModules)
|
||||
{
|
||||
HashSet<Assembly>? 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<IPlugin>? InitPlugins()
|
||||
internal static HashSet<IPlugin>? InitPlugins(params string[] loadModules)
|
||||
{
|
||||
HashSet<Assembly>? assemblies = LoadAssemblies();
|
||||
HashSet<Assembly>? assemblies = LoadAssemblies(loadModules);
|
||||
if (!assemblies.Any_Nullable()) return null;
|
||||
|
||||
var assemblies_ = VerifyAssemblies(assemblies).ToArray();
|
||||
|
||||
@@ -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<Process?>(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
|
||||
}
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
+2
-3
@@ -13,14 +13,13 @@ partial class ScheduledTaskServiceImpl
|
||||
/// 使用 PowerShell 实现的开机启动
|
||||
/// <para>https://docs.microsoft.com/en-us/powershell/module/scheduledtasks</para>
|
||||
/// </summary>
|
||||
/// <param name="platformService"></param>
|
||||
/// <param name="isAutoStart"></param>
|
||||
/// <param name="name"></param>
|
||||
/// <param name="userId"></param>
|
||||
/// <param name="userName"></param>
|
||||
/// <param name="tdName"></param>
|
||||
/// <param name="programName"></param>
|
||||
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 = $"<?xml version=\"1.0\" encoding=\"UTF-16\"?><Task version=\"1.2\" xmlns=\"http://schemas.microsoft.com/windows/2004/02/mit/task\"><RegistrationInfo><Description>{description}</Description></RegistrationInfo><Triggers><LogonTrigger><Enabled>true</Enabled><UserId>{userName}</UserId></LogonTrigger></Triggers><Principals><Principal id=\"Author\"><UserId>{userId}</UserId><LogonType>InteractiveToken</LogonType><RunLevel>{(platformService.IsAdministrator ? "HighestAvailable" : "LeastPrivilege")}</RunLevel></Principal></Principals><Settings><MultipleInstancesPolicy>IgnoreNew</MultipleInstancesPolicy><DisallowStartIfOnBatteries>false</DisallowStartIfOnBatteries><StopIfGoingOnBatteries>false</StopIfGoingOnBatteries><AllowHardTerminate>false</AllowHardTerminate><StartWhenAvailable>false</StartWhenAvailable><RunOnlyIfNetworkAvailable>false</RunOnlyIfNetworkAvailable><IdleSettings><Duration>PT10M</Duration><WaitTimeout>PT1H</WaitTimeout><StopOnIdleEnd>true</StopOnIdleEnd><RestartOnIdle>false</RestartOnIdle></IdleSettings><AllowStartOnDemand>true</AllowStartOnDemand><Enabled>true</Enabled><Hidden>false</Hidden><RunOnlyIfIdle>false</RunOnlyIfIdle><WakeToRun>false</WakeToRun><ExecutionTimeLimit>PT0S</ExecutionTimeLimit><Priority>5</Priority></Settings><Actions Context=\"Author\"><Exec><Command>{programName}</Command><Arguments>{arguments}</Arguments><WorkingDirectory>{workingDirectory}</WorkingDirectory></Exec></Actions></Task>";
|
||||
var xml = $"<?xml version=\"1.0\" encoding=\"UTF-16\"?><Task version=\"1.2\" xmlns=\"http://schemas.microsoft.com/windows/2004/02/mit/task\"><RegistrationInfo><Description>{description}</Description></RegistrationInfo><Triggers><LogonTrigger><Enabled>true</Enabled><UserId>{userName}</UserId></LogonTrigger></Triggers><Principals><Principal id=\"Author\"><UserId>{userId}</UserId><LogonType>InteractiveToken</LogonType><RunLevel>{(IPlatformService._IsAdministrator.Value ? "HighestAvailable" : "LeastPrivilege")}</RunLevel></Principal></Principals><Settings><MultipleInstancesPolicy>IgnoreNew</MultipleInstancesPolicy><DisallowStartIfOnBatteries>false</DisallowStartIfOnBatteries><StopIfGoingOnBatteries>false</StopIfGoingOnBatteries><AllowHardTerminate>false</AllowHardTerminate><StartWhenAvailable>false</StartWhenAvailable><RunOnlyIfNetworkAvailable>false</RunOnlyIfNetworkAvailable><IdleSettings><Duration>PT10M</Duration><WaitTimeout>PT1H</WaitTimeout><StopOnIdleEnd>true</StopOnIdleEnd><RestartOnIdle>false</RestartOnIdle></IdleSettings><AllowStartOnDemand>true</AllowStartOnDemand><Enabled>true</Enabled><Hidden>false</Hidden><RunOnlyIfIdle>false</RunOnlyIfIdle><WakeToRun>false</WakeToRun><ExecutionTimeLimit>PT0S</ExecutionTimeLimit><Priority>5</Priority></Settings><Actions Context=\"Author\"><Exec><Command>{programName}</Command><Arguments>{arguments}</Arguments><WorkingDirectory>{workingDirectory}</WorkingDirectory></Exec></Actions></Task>";
|
||||
await RunPowerShellSinglePipeAsync($"Register-ScheduledTask -Force -TaskName '{Escape(tdName)}' -Xml '{Escape(xml)}';exit");
|
||||
}
|
||||
else
|
||||
|
||||
+2
-2
@@ -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)
|
||||
{
|
||||
|
||||
+34
-16
@@ -44,7 +44,7 @@ partial class WindowsPlatformServiceImpl
|
||||
/// <param name="arguments"></param>
|
||||
/// <returns></returns>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static async Task<Process?> StartAsAdministratorByBypassUAC(string fileName, string? arguments = null)
|
||||
internal static async Task<Process?> 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<int>(
|
||||
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
|
||||
/// <param name="fileName"></param>
|
||||
/// <param name="arguments"></param>
|
||||
/// <returns></returns>
|
||||
public async ValueTask<Process?> StartAsAdministrator(string fileName, string? arguments = null)
|
||||
internal static async ValueTask<Process?> 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
|
||||
+1
-1
@@ -51,7 +51,7 @@ partial class WindowsPlatformServiceImpl
|
||||
{
|
||||
var scheduledTaskService = IScheduledTaskService.Instance;
|
||||
scheduledTaskService.ThrowIsNull();
|
||||
scheduledTaskService.SetBootAutoStart(this, isAutoStart, name);
|
||||
scheduledTaskService.SetBootAutoStart(isAutoStart, name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+1
-2
@@ -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);
|
||||
|
||||
@@ -42,7 +42,7 @@ sealed class SteamServiceImpl2 : SteamServiceBaseImpl, ISteamConnectService
|
||||
|
||||
protected override Dictionary<uint, string?>? HideGameList => serviceProvider.GetService<IGameLibrarySettings>()?.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)
|
||||
{
|
||||
|
||||
@@ -6,8 +6,13 @@ namespace BD.WTTS.Services;
|
||||
/// <summary>
|
||||
/// 用于 IPC 的平台实现的服务
|
||||
/// </summary>
|
||||
[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
|
||||
}
|
||||
@@ -3,21 +3,21 @@ namespace BD.WTTS.Services;
|
||||
|
||||
partial interface IPlatformService
|
||||
{
|
||||
internal static readonly Lazy<bool> _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
|
||||
});
|
||||
|
||||
/// <summary>
|
||||
/// 当前程序是否以 Administrator/System(Windows) 或 Root(FreeBSD/Linux/MacOS/Android/iOS) 权限运行
|
||||
/// </summary>
|
||||
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;
|
||||
}
|
||||
@@ -27,6 +27,18 @@ partial interface IPlatformService
|
||||
[Obsolete("use WriteDefaultHostsContent(Stream", true)]
|
||||
string DefaultHostsContent => string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// 写入默认 hosts 文件内容
|
||||
/// </summary>
|
||||
void WriteDefaultHostsContent()
|
||||
{
|
||||
var fileStream = new FileStream(HostsFilePath,
|
||||
FileMode.OpenOrCreate,
|
||||
FileAccess.Write,
|
||||
FileShare.ReadWrite | FileShare.Delete);
|
||||
WriteDefaultHostsContent(fileStream);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 写入默认 hosts 文件内容
|
||||
/// </summary>
|
||||
|
||||
@@ -33,6 +33,17 @@ public partial interface IPlatformService : IPCPlatformService
|
||||
{
|
||||
var iPCPlatformService = await ipc.GetServiceAsync<IPCPlatformService>(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)
|
||||
|
||||
@@ -12,9 +12,8 @@ public interface IScheduledTaskService
|
||||
/// <summary>
|
||||
/// 开机启动使用 taskschd.msc 实现
|
||||
/// </summary>
|
||||
/// <param name="platformService"></param>
|
||||
/// <param name="isAutoStart"></param>
|
||||
/// <param name="name"></param>
|
||||
void SetBootAutoStart(IPlatformService platformService, bool isAutoStart, string name);
|
||||
void SetBootAutoStart(bool isAutoStart, string name);
|
||||
}
|
||||
#endif
|
||||
@@ -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<bool>("-disable_gpu", () => false, "禁用 GPU 硬件加速"));
|
||||
devtools.AddOption(new Option<bool>("-use_wgl", () => false, "使用 Native OpenGL(仅 Windows)"));
|
||||
devtools.Handler = CommandHandler.Create((bool disable_gpu, bool use_wgl) =>
|
||||
devtools.AddOption(new Option<bool>("-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<uint>("-l", "AppServicesLevel"));
|
||||
plugins.AddOption(new Option<string>("-m", "需要加载的模块名称"));
|
||||
plugins.AddOption(new Option<string>("-a", "需要解析的参数,使用 HttpUtility.UrlDecode 解码"));
|
||||
plugins.AddOption(new Option<string>(IPlatformService.IPCRoot.args_PipeName, "IPC 管道名"));
|
||||
plugins.AddOption(new Option<string>(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
|
||||
#endif
|
||||
}
|
||||
@@ -6,7 +6,10 @@ namespace BD.WTTS;
|
||||
partial class Startup // 配置 Host
|
||||
{
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
protected void RunUIApplication(AppServicesLevel? level = null, Func<string>? sendMessage = null)
|
||||
protected void RunUIApplication(
|
||||
AppServicesLevel? level = null,
|
||||
Func<string>? 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");
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user