csharp_style_namespace_declarations = file_scoped

This commit is contained in:
2dust
2025-04-02 11:44:23 +08:00
parent d92540121f
commit 4d3db56065
186 changed files with 23361 additions and 23546 deletions
+220 -221
View File
@@ -1,244 +1,243 @@
namespace ServiceLib.Handler
namespace ServiceLib.Handler;
public sealed class AppHandler
{
public sealed class AppHandler
#region Property
private static readonly Lazy<AppHandler> _instance = new(() => new());
private Config _config;
private int? _statePort;
private int? _statePort2;
private Job? _processJob;
private bool? _isAdministrator;
public static AppHandler Instance => _instance.Value;
public Config Config => _config;
public int StatePort
{
#region Property
private static readonly Lazy<AppHandler> _instance = new(() => new());
private Config _config;
private int? _statePort;
private int? _statePort2;
private Job? _processJob;
private bool? _isAdministrator;
public static AppHandler Instance => _instance.Value;
public Config Config => _config;
public int StatePort
get
{
get
_statePort ??= Utils.GetFreePort(GetLocalPort(EInboundProtocol.api));
return _statePort.Value;
}
}
public int StatePort2
{
get
{
_statePort2 ??= Utils.GetFreePort(GetLocalPort(EInboundProtocol.api2));
return _statePort2.Value + (_config.TunModeItem.EnableTun ? 1 : 0);
}
}
public bool IsAdministrator
{
get
{
_isAdministrator ??= Utils.IsAdministrator();
return _isAdministrator.Value;
}
}
#endregion Property
#region Init
public bool InitApp()
{
if (Utils.HasWritePermission() == false)
{
Environment.SetEnvironmentVariable(Global.LocalAppData, "1", EnvironmentVariableTarget.Process);
}
Logging.Setup();
var config = ConfigHandler.LoadConfig();
if (config == null)
{
return false;
}
_config = config;
Thread.CurrentThread.CurrentUICulture = new(_config.UiItem.CurrentLanguage);
//Under Win10
if (Utils.IsWindows() && Environment.OSVersion.Version.Major < 10)
{
Environment.SetEnvironmentVariable("DOTNET_EnableWriteXorExecute", "0", EnvironmentVariableTarget.User);
}
SQLiteHelper.Instance.CreateTable<SubItem>();
SQLiteHelper.Instance.CreateTable<ProfileItem>();
SQLiteHelper.Instance.CreateTable<ServerStatItem>();
SQLiteHelper.Instance.CreateTable<RoutingItem>();
SQLiteHelper.Instance.CreateTable<ProfileExItem>();
SQLiteHelper.Instance.CreateTable<DNSItem>();
return true;
}
public bool InitComponents()
{
Logging.SaveLog($"v2rayN start up | {Utils.GetRuntimeInfo()}");
Logging.LoggingEnabled(_config.GuiItem.EnableLog);
return true;
}
public bool Reset()
{
_statePort = null;
_statePort2 = null;
return true;
}
#endregion Init
#region Config
public int GetLocalPort(EInboundProtocol protocol)
{
var localPort = _config.Inbound.FirstOrDefault(t => t.Protocol == nameof(EInboundProtocol.socks))?.LocalPort ?? 10808;
return localPort + (int)protocol;
}
public void AddProcess(IntPtr processHandle)
{
if (Utils.IsWindows())
{
_processJob ??= new();
try
{
_processJob?.AddProcess(processHandle);
}
catch
{
_statePort ??= Utils.GetFreePort(GetLocalPort(EInboundProtocol.api));
return _statePort.Value;
}
}
}
public int StatePort2
#endregion Config
#region SqliteHelper
public async Task<List<SubItem>?> SubItems()
{
return await SQLiteHelper.Instance.TableAsync<SubItem>().OrderBy(t => t.Sort).ToListAsync();
}
public async Task<SubItem?> GetSubItem(string? subid)
{
return await SQLiteHelper.Instance.TableAsync<SubItem>().FirstOrDefaultAsync(t => t.Id == subid);
}
public async Task<List<ProfileItem>?> ProfileItems(string subid)
{
if (subid.IsNullOrEmpty())
{
get
{
_statePort2 ??= Utils.GetFreePort(GetLocalPort(EInboundProtocol.api2));
return _statePort2.Value + (_config.TunModeItem.EnableTun ? 1 : 0);
}
return await SQLiteHelper.Instance.TableAsync<ProfileItem>().ToListAsync();
}
public bool IsAdministrator
else
{
get
{
_isAdministrator ??= Utils.IsAdministrator();
return _isAdministrator.Value;
}
return await SQLiteHelper.Instance.TableAsync<ProfileItem>().Where(t => t.Subid == subid).ToListAsync();
}
}
#endregion Property
public async Task<List<string>?> ProfileItemIndexes(string subid)
{
return (await ProfileItems(subid))?.Select(t => t.IndexId)?.ToList();
}
#region Init
public bool InitApp()
{
if (Utils.HasWritePermission() == false)
{
Environment.SetEnvironmentVariable(Global.LocalAppData, "1", EnvironmentVariableTarget.Process);
}
Logging.Setup();
var config = ConfigHandler.LoadConfig();
if (config == null)
{
return false;
}
_config = config;
Thread.CurrentThread.CurrentUICulture = new(_config.UiItem.CurrentLanguage);
//Under Win10
if (Utils.IsWindows() && Environment.OSVersion.Version.Major < 10)
{
Environment.SetEnvironmentVariable("DOTNET_EnableWriteXorExecute", "0", EnvironmentVariableTarget.User);
}
SQLiteHelper.Instance.CreateTable<SubItem>();
SQLiteHelper.Instance.CreateTable<ProfileItem>();
SQLiteHelper.Instance.CreateTable<ServerStatItem>();
SQLiteHelper.Instance.CreateTable<RoutingItem>();
SQLiteHelper.Instance.CreateTable<ProfileExItem>();
SQLiteHelper.Instance.CreateTable<DNSItem>();
return true;
}
public bool InitComponents()
{
Logging.SaveLog($"v2rayN start up | {Utils.GetRuntimeInfo()}");
Logging.LoggingEnabled(_config.GuiItem.EnableLog);
return true;
}
public bool Reset()
{
_statePort = null;
_statePort2 = null;
return true;
}
#endregion Init
#region Config
public int GetLocalPort(EInboundProtocol protocol)
{
var localPort = _config.Inbound.FirstOrDefault(t => t.Protocol == nameof(EInboundProtocol.socks))?.LocalPort ?? 10808;
return localPort + (int)protocol;
}
public void AddProcess(IntPtr processHandle)
{
if (Utils.IsWindows())
{
_processJob ??= new();
try
{
_processJob?.AddProcess(processHandle);
}
catch
{
}
}
}
#endregion Config
#region SqliteHelper
public async Task<List<SubItem>?> SubItems()
{
return await SQLiteHelper.Instance.TableAsync<SubItem>().OrderBy(t => t.Sort).ToListAsync();
}
public async Task<SubItem?> GetSubItem(string? subid)
{
return await SQLiteHelper.Instance.TableAsync<SubItem>().FirstOrDefaultAsync(t => t.Id == subid);
}
public async Task<List<ProfileItem>?> ProfileItems(string subid)
{
if (subid.IsNullOrEmpty())
{
return await SQLiteHelper.Instance.TableAsync<ProfileItem>().ToListAsync();
}
else
{
return await SQLiteHelper.Instance.TableAsync<ProfileItem>().Where(t => t.Subid == subid).ToListAsync();
}
}
public async Task<List<string>?> ProfileItemIndexes(string subid)
{
return (await ProfileItems(subid))?.Select(t => t.IndexId)?.ToList();
}
public async Task<List<ProfileItemModel>?> ProfileItems(string subid, string filter)
{
var sql = @$"select a.*
public async Task<List<ProfileItemModel>?> ProfileItems(string subid, string filter)
{
var sql = @$"select a.*
,b.remarks subRemarks
from ProfileItem a
left join SubItem b on a.subid = b.id
where 1=1 ";
if (subid.IsNotEmpty())
if (subid.IsNotEmpty())
{
sql += $" and a.subid = '{subid}'";
}
if (filter.IsNotEmpty())
{
if (filter.Contains('\''))
{
sql += $" and a.subid = '{subid}'";
filter = filter.Replace("'", "");
}
if (filter.IsNotEmpty())
{
if (filter.Contains('\''))
{
filter = filter.Replace("'", "");
}
sql += string.Format(" and (a.remarks like '%{0}%' or a.address like '%{0}%') ", filter);
}
return await SQLiteHelper.Instance.QueryAsync<ProfileItemModel>(sql);
sql += string.Format(" and (a.remarks like '%{0}%' or a.address like '%{0}%') ", filter);
}
public async Task<ProfileItem?> GetProfileItem(string indexId)
{
if (indexId.IsNullOrEmpty())
{
return null;
}
return await SQLiteHelper.Instance.TableAsync<ProfileItem>().FirstOrDefaultAsync(it => it.IndexId == indexId);
}
public async Task<ProfileItem?> GetProfileItemViaRemarks(string? remarks)
{
if (remarks.IsNullOrEmpty())
{
return null;
}
return await SQLiteHelper.Instance.TableAsync<ProfileItem>().FirstOrDefaultAsync(it => it.Remarks == remarks);
}
public async Task<List<RoutingItem>?> RoutingItems()
{
return await SQLiteHelper.Instance.TableAsync<RoutingItem>().OrderBy(t => t.Sort).ToListAsync();
}
public async Task<RoutingItem?> GetRoutingItem(string id)
{
return await SQLiteHelper.Instance.TableAsync<RoutingItem>().FirstOrDefaultAsync(it => it.Id == id);
}
public async Task<List<DNSItem>?> DNSItems()
{
return await SQLiteHelper.Instance.TableAsync<DNSItem>().ToListAsync();
}
public async Task<DNSItem?> GetDNSItem(ECoreType eCoreType)
{
return await SQLiteHelper.Instance.TableAsync<DNSItem>().FirstOrDefaultAsync(it => it.CoreType == eCoreType);
}
#endregion SqliteHelper
#region Core Type
public List<string> GetShadowsocksSecurities(ProfileItem profileItem)
{
var coreType = GetCoreType(profileItem, EConfigType.Shadowsocks);
switch (coreType)
{
case ECoreType.v2fly:
return Global.SsSecurities;
case ECoreType.Xray:
return Global.SsSecuritiesInXray;
case ECoreType.sing_box:
return Global.SsSecuritiesInSingbox;
}
return Global.SsSecuritiesInSingbox;
}
public ECoreType GetCoreType(ProfileItem profileItem, EConfigType eConfigType)
{
if (profileItem?.CoreType != null)
{
return (ECoreType)profileItem.CoreType;
}
var item = _config.CoreTypeItem?.FirstOrDefault(it => it.ConfigType == eConfigType);
return item?.CoreType ?? ECoreType.Xray;
}
#endregion Core Type
return await SQLiteHelper.Instance.QueryAsync<ProfileItemModel>(sql);
}
public async Task<ProfileItem?> GetProfileItem(string indexId)
{
if (indexId.IsNullOrEmpty())
{
return null;
}
return await SQLiteHelper.Instance.TableAsync<ProfileItem>().FirstOrDefaultAsync(it => it.IndexId == indexId);
}
public async Task<ProfileItem?> GetProfileItemViaRemarks(string? remarks)
{
if (remarks.IsNullOrEmpty())
{
return null;
}
return await SQLiteHelper.Instance.TableAsync<ProfileItem>().FirstOrDefaultAsync(it => it.Remarks == remarks);
}
public async Task<List<RoutingItem>?> RoutingItems()
{
return await SQLiteHelper.Instance.TableAsync<RoutingItem>().OrderBy(t => t.Sort).ToListAsync();
}
public async Task<RoutingItem?> GetRoutingItem(string id)
{
return await SQLiteHelper.Instance.TableAsync<RoutingItem>().FirstOrDefaultAsync(it => it.Id == id);
}
public async Task<List<DNSItem>?> DNSItems()
{
return await SQLiteHelper.Instance.TableAsync<DNSItem>().ToListAsync();
}
public async Task<DNSItem?> GetDNSItem(ECoreType eCoreType)
{
return await SQLiteHelper.Instance.TableAsync<DNSItem>().FirstOrDefaultAsync(it => it.CoreType == eCoreType);
}
#endregion SqliteHelper
#region Core Type
public List<string> GetShadowsocksSecurities(ProfileItem profileItem)
{
var coreType = GetCoreType(profileItem, EConfigType.Shadowsocks);
switch (coreType)
{
case ECoreType.v2fly:
return Global.SsSecurities;
case ECoreType.Xray:
return Global.SsSecuritiesInXray;
case ECoreType.sing_box:
return Global.SsSecuritiesInSingbox;
}
return Global.SsSecuritiesInSingbox;
}
public ECoreType GetCoreType(ProfileItem profileItem, EConfigType eConfigType)
{
if (profileItem?.CoreType != null)
{
return (ECoreType)profileItem.CoreType;
}
var item = _config.CoreTypeItem?.FirstOrDefault(it => it.ConfigType == eConfigType);
return item?.CoreType ?? ECoreType.Xray;
}
#endregion Core Type
}
+183 -184
View File
@@ -1,223 +1,223 @@
using System.Security.Principal;
using System.Text.RegularExpressions;
namespace ServiceLib.Handler
namespace ServiceLib.Handler;
public static class AutoStartupHandler
{
public static class AutoStartupHandler
private static readonly string _tag = "AutoStartupHandler";
public static async Task<bool> UpdateTask(Config config)
{
private static readonly string _tag = "AutoStartupHandler";
public static async Task<bool> UpdateTask(Config config)
if (Utils.IsWindows())
{
if (Utils.IsWindows())
await ClearTaskWindows();
if (config.GuiItem.AutoRun)
{
await ClearTaskWindows();
if (config.GuiItem.AutoRun)
{
await SetTaskWindows();
}
await SetTaskWindows();
}
else if (Utils.IsLinux())
}
else if (Utils.IsLinux())
{
await ClearTaskLinux();
if (config.GuiItem.AutoRun)
{
await ClearTaskLinux();
if (config.GuiItem.AutoRun)
{
await SetTaskLinux();
}
await SetTaskLinux();
}
else if (Utils.IsOSX())
}
else if (Utils.IsOSX())
{
await ClearTaskOSX();
if (config.GuiItem.AutoRun)
{
await ClearTaskOSX();
if (config.GuiItem.AutoRun)
{
await SetTaskOSX();
}
await SetTaskOSX();
}
return true;
}
#region Windows
return true;
}
private static async Task ClearTaskWindows()
#region Windows
private static async Task ClearTaskWindows()
{
var autoRunName = GetAutoRunNameWindows();
WindowsUtils.RegWriteValue(Global.AutoRunRegPath, autoRunName, "");
if (Utils.IsAdministrator())
{
AutoStartTaskService(autoRunName, "", "");
}
await Task.CompletedTask;
}
private static async Task SetTaskWindows()
{
try
{
var autoRunName = GetAutoRunNameWindows();
WindowsUtils.RegWriteValue(Global.AutoRunRegPath, autoRunName, "");
var exePath = Utils.GetExePath();
if (Utils.IsAdministrator())
{
AutoStartTaskService(autoRunName, "", "");
AutoStartTaskService(autoRunName, exePath, "");
}
await Task.CompletedTask;
}
private static async Task SetTaskWindows()
{
try
else
{
var autoRunName = GetAutoRunNameWindows();
var exePath = Utils.GetExePath();
if (Utils.IsAdministrator())
{
AutoStartTaskService(autoRunName, exePath, "");
}
else
{
WindowsUtils.RegWriteValue(Global.AutoRunRegPath, autoRunName, exePath.AppendQuotes());
}
}
catch (Exception ex)
{
Logging.SaveLog(_tag, ex);
}
await Task.CompletedTask;
}
/// <summary>
/// Auto Start via TaskService
/// </summary>
/// <param name="taskName"></param>
/// <param name="fileName"></param>
/// <param name="description"></param>
/// <exception cref="ArgumentNullException"></exception>
public static void AutoStartTaskService(string taskName, string fileName, string description)
{
if (taskName.IsNullOrEmpty())
{
return;
}
var logonUser = WindowsIdentity.GetCurrent().Name;
using var taskService = new Microsoft.Win32.TaskScheduler.TaskService();
var tasks = taskService.RootFolder.GetTasks(new Regex(taskName));
if (fileName.IsNullOrEmpty())
{
foreach (var t in tasks)
{
taskService.RootFolder.DeleteTask(t.Name);
}
return;
}
var task = taskService.NewTask();
task.RegistrationInfo.Description = description;
task.Settings.DisallowStartIfOnBatteries = false;
task.Settings.StopIfGoingOnBatteries = false;
task.Settings.RunOnlyIfIdle = false;
task.Settings.IdleSettings.StopOnIdleEnd = false;
task.Settings.ExecutionTimeLimit = TimeSpan.Zero;
task.Triggers.Add(new Microsoft.Win32.TaskScheduler.LogonTrigger { UserId = logonUser, Delay = TimeSpan.FromSeconds(30) });
task.Principal.RunLevel = Microsoft.Win32.TaskScheduler.TaskRunLevel.Highest;
task.Actions.Add(new Microsoft.Win32.TaskScheduler.ExecAction(fileName.AppendQuotes(), null, Path.GetDirectoryName(fileName)));
taskService.RootFolder.RegisterTaskDefinition(taskName, task);
}
private static string GetAutoRunNameWindows()
{
return $"{Global.AutoRunName}_{Utils.GetMd5(Utils.StartupPath())}";
}
#endregion Windows
#region Linux
private static async Task ClearTaskLinux()
{
try
{
File.Delete(GetHomePathLinux());
}
catch (Exception ex)
{
Logging.SaveLog(_tag, ex);
}
await Task.CompletedTask;
}
private static async Task SetTaskLinux()
{
try
{
var linuxConfig = EmbedUtils.GetEmbedText(Global.LinuxAutostartConfig);
if (linuxConfig.IsNotEmpty())
{
linuxConfig = linuxConfig.Replace("$ExecPath$", Utils.GetExePath());
Logging.SaveLog(linuxConfig);
var homePath = GetHomePathLinux();
await File.WriteAllTextAsync(homePath, linuxConfig);
}
}
catch (Exception ex)
{
Logging.SaveLog(_tag, ex);
WindowsUtils.RegWriteValue(Global.AutoRunRegPath, autoRunName, exePath.AppendQuotes());
}
}
private static string GetHomePathLinux()
catch (Exception ex)
{
var homePath = Path.Combine(Utils.GetHomePath(), ".config", "autostart", $"{Global.AppName}.desktop");
Directory.CreateDirectory(Path.GetDirectoryName(homePath));
return homePath;
Logging.SaveLog(_tag, ex);
}
await Task.CompletedTask;
}
/// <summary>
/// Auto Start via TaskService
/// </summary>
/// <param name="taskName"></param>
/// <param name="fileName"></param>
/// <param name="description"></param>
/// <exception cref="ArgumentNullException"></exception>
public static void AutoStartTaskService(string taskName, string fileName, string description)
{
if (taskName.IsNullOrEmpty())
{
return;
}
#endregion Linux
#region macOS
private static async Task ClearTaskOSX()
var logonUser = WindowsIdentity.GetCurrent().Name;
using var taskService = new Microsoft.Win32.TaskScheduler.TaskService();
var tasks = taskService.RootFolder.GetTasks(new Regex(taskName));
if (fileName.IsNullOrEmpty())
{
try
foreach (var t in tasks)
{
var launchAgentPath = GetLaunchAgentPathMacOS();
if (File.Exists(launchAgentPath))
{
var args = new[] { "-c", $"launchctl unload -w \"{launchAgentPath}\"" };
await Utils.GetCliWrapOutput(Global.LinuxBash, args);
File.Delete(launchAgentPath);
}
}
catch (Exception ex)
{
Logging.SaveLog(_tag, ex);
taskService.RootFolder.DeleteTask(t.Name);
}
return;
}
private static async Task SetTaskOSX()
{
try
{
var plistContent = GenerateLaunchAgentPlist();
var launchAgentPath = GetLaunchAgentPathMacOS();
await File.WriteAllTextAsync(launchAgentPath, plistContent);
var task = taskService.NewTask();
task.RegistrationInfo.Description = description;
task.Settings.DisallowStartIfOnBatteries = false;
task.Settings.StopIfGoingOnBatteries = false;
task.Settings.RunOnlyIfIdle = false;
task.Settings.IdleSettings.StopOnIdleEnd = false;
task.Settings.ExecutionTimeLimit = TimeSpan.Zero;
task.Triggers.Add(new Microsoft.Win32.TaskScheduler.LogonTrigger { UserId = logonUser, Delay = TimeSpan.FromSeconds(30) });
task.Principal.RunLevel = Microsoft.Win32.TaskScheduler.TaskRunLevel.Highest;
task.Actions.Add(new Microsoft.Win32.TaskScheduler.ExecAction(fileName.AppendQuotes(), null, Path.GetDirectoryName(fileName)));
var args = new[] { "-c", $"launchctl load -w \"{launchAgentPath}\"" };
taskService.RootFolder.RegisterTaskDefinition(taskName, task);
}
private static string GetAutoRunNameWindows()
{
return $"{Global.AutoRunName}_{Utils.GetMd5(Utils.StartupPath())}";
}
#endregion Windows
#region Linux
private static async Task ClearTaskLinux()
{
try
{
File.Delete(GetHomePathLinux());
}
catch (Exception ex)
{
Logging.SaveLog(_tag, ex);
}
await Task.CompletedTask;
}
private static async Task SetTaskLinux()
{
try
{
var linuxConfig = EmbedUtils.GetEmbedText(Global.LinuxAutostartConfig);
if (linuxConfig.IsNotEmpty())
{
linuxConfig = linuxConfig.Replace("$ExecPath$", Utils.GetExePath());
Logging.SaveLog(linuxConfig);
var homePath = GetHomePathLinux();
await File.WriteAllTextAsync(homePath, linuxConfig);
}
}
catch (Exception ex)
{
Logging.SaveLog(_tag, ex);
}
}
private static string GetHomePathLinux()
{
var homePath = Path.Combine(Utils.GetHomePath(), ".config", "autostart", $"{Global.AppName}.desktop");
Directory.CreateDirectory(Path.GetDirectoryName(homePath));
return homePath;
}
#endregion Linux
#region macOS
private static async Task ClearTaskOSX()
{
try
{
var launchAgentPath = GetLaunchAgentPathMacOS();
if (File.Exists(launchAgentPath))
{
var args = new[] { "-c", $"launchctl unload -w \"{launchAgentPath}\"" };
await Utils.GetCliWrapOutput(Global.LinuxBash, args);
}
catch (Exception ex)
{
Logging.SaveLog(_tag, ex);
File.Delete(launchAgentPath);
}
}
private static string GetLaunchAgentPathMacOS()
catch (Exception ex)
{
var homePath = Environment.GetFolderPath(Environment.SpecialFolder.UserProfile);
var launchAgentPath = Path.Combine(homePath, "Library", "LaunchAgents", $"{Global.AppName}-LaunchAgent.plist");
Directory.CreateDirectory(Path.GetDirectoryName(launchAgentPath));
return launchAgentPath;
Logging.SaveLog(_tag, ex);
}
}
private static string GenerateLaunchAgentPlist()
private static async Task SetTaskOSX()
{
try
{
var exePath = Utils.GetExePath();
var appName = Path.GetFileNameWithoutExtension(exePath);
return $@"<?xml version=""1.0"" encoding=""UTF-8""?>
var plistContent = GenerateLaunchAgentPlist();
var launchAgentPath = GetLaunchAgentPathMacOS();
await File.WriteAllTextAsync(launchAgentPath, plistContent);
var args = new[] { "-c", $"launchctl load -w \"{launchAgentPath}\"" };
await Utils.GetCliWrapOutput(Global.LinuxBash, args);
}
catch (Exception ex)
{
Logging.SaveLog(_tag, ex);
}
}
private static string GetLaunchAgentPathMacOS()
{
var homePath = Environment.GetFolderPath(Environment.SpecialFolder.UserProfile);
var launchAgentPath = Path.Combine(homePath, "Library", "LaunchAgents", $"{Global.AppName}-LaunchAgent.plist");
Directory.CreateDirectory(Path.GetDirectoryName(launchAgentPath));
return launchAgentPath;
}
private static string GenerateLaunchAgentPlist()
{
var exePath = Utils.GetExePath();
var appName = Path.GetFileNameWithoutExtension(exePath);
return $@"<?xml version=""1.0"" encoding=""UTF-8""?>
<!DOCTYPE plist PUBLIC ""-//Apple//DTD PLIST 1.0//EN"" ""http://www.apple.com/DTDs/PropertyList-1.0.dtd"">
<plist version=""1.0"">
<dict>
@@ -235,8 +235,7 @@ namespace ServiceLib.Handler
<false/>
</dict>
</plist>";
}
#endregion macOS
}
#endregion macOS
}
+147 -148
View File
@@ -1,188 +1,187 @@
using static ServiceLib.Models.ClashProxies;
namespace ServiceLib.Handler
namespace ServiceLib.Handler;
public sealed class ClashApiHandler
{
public sealed class ClashApiHandler
private static readonly Lazy<ClashApiHandler> instance = new(() => new());
public static ClashApiHandler Instance => instance.Value;
private static readonly string _tag = "ClashApiHandler";
private Dictionary<string, ProxiesItem>? _proxies;
public Dictionary<string, object> ProfileContent { get; set; }
public async Task<Tuple<ClashProxies, ClashProviders>?> GetClashProxiesAsync()
{
private static readonly Lazy<ClashApiHandler> instance = new(() => new());
public static ClashApiHandler Instance => instance.Value;
private static readonly string _tag = "ClashApiHandler";
private Dictionary<string, ProxiesItem>? _proxies;
public Dictionary<string, object> ProfileContent { get; set; }
public async Task<Tuple<ClashProxies, ClashProviders>?> GetClashProxiesAsync()
for (var i = 0; i < 3; i++)
{
for (var i = 0; i < 3; i++)
var url = $"{GetApiUrl()}/proxies";
var result = await HttpClientHelper.Instance.TryGetAsync(url);
var clashProxies = JsonUtils.Deserialize<ClashProxies>(result);
var url2 = $"{GetApiUrl()}/providers/proxies";
var result2 = await HttpClientHelper.Instance.TryGetAsync(url2);
var clashProviders = JsonUtils.Deserialize<ClashProviders>(result2);
if (clashProxies != null || clashProviders != null)
{
var url = $"{GetApiUrl()}/proxies";
var result = await HttpClientHelper.Instance.TryGetAsync(url);
var clashProxies = JsonUtils.Deserialize<ClashProxies>(result);
var url2 = $"{GetApiUrl()}/providers/proxies";
var result2 = await HttpClientHelper.Instance.TryGetAsync(url2);
var clashProviders = JsonUtils.Deserialize<ClashProviders>(result2);
if (clashProxies != null || clashProviders != null)
{
_proxies = clashProxies?.proxies;
return new Tuple<ClashProxies, ClashProviders>(clashProxies, clashProviders);
}
await Task.Delay(2000);
_proxies = clashProxies?.proxies;
return new Tuple<ClashProxies, ClashProviders>(clashProxies, clashProviders);
}
return null;
await Task.Delay(2000);
}
public void ClashProxiesDelayTest(bool blAll, List<ClashProxyModel> lstProxy, Action<ClashProxyModel?, string> updateFunc)
return null;
}
public void ClashProxiesDelayTest(bool blAll, List<ClashProxyModel> lstProxy, Action<ClashProxyModel?, string> updateFunc)
{
Task.Run(async () =>
{
Task.Run(async () =>
if (blAll)
{
if (blAll)
if (_proxies == null)
{
if (_proxies == null)
{
await GetClashProxiesAsync();
}
lstProxy = new List<ClashProxyModel>();
foreach (var kv in _proxies ?? [])
{
if (Global.notAllowTestType.Contains(kv.Value.type?.ToLower()))
{
continue;
}
lstProxy.Add(new ClashProxyModel()
{
Name = kv.Value.name,
Type = kv.Value.type?.ToLower(),
});
}
await GetClashProxiesAsync();
}
if (lstProxy is not { Count: > 0 })
lstProxy = new List<ClashProxyModel>();
foreach (var kv in _proxies ?? [])
{
return;
}
var urlBase = $"{GetApiUrl()}/proxies";
urlBase += @"/{0}/delay?timeout=10000&url=" + AppHandler.Instance.Config.SpeedTestItem.SpeedPingTestUrl;
var tasks = new List<Task>();
foreach (var it in lstProxy)
{
if (Global.notAllowTestType.Contains(it.Type.ToLower()))
if (Global.notAllowTestType.Contains(kv.Value.type?.ToLower()))
{
continue;
}
var name = it.Name;
var url = string.Format(urlBase, name);
tasks.Add(Task.Run(async () =>
lstProxy.Add(new ClashProxyModel()
{
var result = await HttpClientHelper.Instance.TryGetAsync(url);
updateFunc?.Invoke(it, result);
}));
Name = kv.Value.name,
Type = kv.Value.type?.ToLower(),
});
}
await Task.WhenAll(tasks);
await Task.Delay(1000);
updateFunc?.Invoke(null, "");
});
}
}
public List<ProxiesItem>? GetClashProxyGroups()
{
try
{
var fileContent = ProfileContent;
if (fileContent is null || fileContent?.ContainsKey("proxy-groups") == false)
{
return null;
}
return JsonUtils.Deserialize<List<ProxiesItem>>(JsonUtils.Serialize(fileContent["proxy-groups"]));
}
catch (Exception ex)
{
Logging.SaveLog(_tag, ex);
return null;
}
}
public async Task ClashSetActiveProxy(string name, string nameNode)
{
try
{
var url = $"{GetApiUrl()}/proxies/{name}";
var headers = new Dictionary<string, string>();
headers.Add("name", nameNode);
await HttpClientHelper.Instance.PutAsync(url, headers);
}
catch (Exception ex)
{
Logging.SaveLog(_tag, ex);
}
}
public async Task ClashConfigUpdate(Dictionary<string, string> headers)
{
if (_proxies == null)
if (lstProxy is not { Count: > 0 })
{
return;
}
var urlBase = $"{GetApiUrl()}/proxies";
urlBase += @"/{0}/delay?timeout=10000&url=" + AppHandler.Instance.Config.SpeedTestItem.SpeedPingTestUrl;
var urlBase = $"{GetApiUrl()}/configs";
var tasks = new List<Task>();
foreach (var it in lstProxy)
{
if (Global.notAllowTestType.Contains(it.Type.ToLower()))
{
continue;
}
var name = it.Name;
var url = string.Format(urlBase, name);
tasks.Add(Task.Run(async () =>
{
var result = await HttpClientHelper.Instance.TryGetAsync(url);
updateFunc?.Invoke(it, result);
}));
}
await Task.WhenAll(tasks);
await Task.Delay(1000);
updateFunc?.Invoke(null, "");
});
}
await HttpClientHelper.Instance.PatchAsync(urlBase, headers);
}
public async Task ClashConfigReload(string filePath)
public List<ProxiesItem>? GetClashProxyGroups()
{
try
{
await ClashConnectionClose("");
try
var fileContent = ProfileContent;
if (fileContent is null || fileContent?.ContainsKey("proxy-groups") == false)
{
var url = $"{GetApiUrl()}/configs?force=true";
var headers = new Dictionary<string, string>();
headers.Add("path", filePath);
await HttpClientHelper.Instance.PutAsync(url, headers);
}
catch (Exception ex)
{
Logging.SaveLog(_tag, ex);
return null;
}
return JsonUtils.Deserialize<List<ProxiesItem>>(JsonUtils.Serialize(fileContent["proxy-groups"]));
}
public async Task<ClashConnections?> GetClashConnectionsAsync()
catch (Exception ex)
{
try
{
var url = $"{GetApiUrl()}/connections";
var result = await HttpClientHelper.Instance.TryGetAsync(url);
var clashConnections = JsonUtils.Deserialize<ClashConnections>(result);
return clashConnections;
}
catch (Exception ex)
{
Logging.SaveLog(_tag, ex);
}
Logging.SaveLog(_tag, ex);
return null;
}
}
public async Task ClashConnectionClose(string id)
public async Task ClashSetActiveProxy(string name, string nameNode)
{
try
{
try
{
var url = $"{GetApiUrl()}/connections/{id}";
await HttpClientHelper.Instance.DeleteAsync(url);
}
catch (Exception ex)
{
Logging.SaveLog(_tag, ex);
}
var url = $"{GetApiUrl()}/proxies/{name}";
var headers = new Dictionary<string, string>();
headers.Add("name", nameNode);
await HttpClientHelper.Instance.PutAsync(url, headers);
}
private string GetApiUrl()
catch (Exception ex)
{
return $"{Global.HttpProtocol}{Global.Loopback}:{AppHandler.Instance.StatePort2}";
Logging.SaveLog(_tag, ex);
}
}
public async Task ClashConfigUpdate(Dictionary<string, string> headers)
{
if (_proxies == null)
{
return;
}
var urlBase = $"{GetApiUrl()}/configs";
await HttpClientHelper.Instance.PatchAsync(urlBase, headers);
}
public async Task ClashConfigReload(string filePath)
{
await ClashConnectionClose("");
try
{
var url = $"{GetApiUrl()}/configs?force=true";
var headers = new Dictionary<string, string>();
headers.Add("path", filePath);
await HttpClientHelper.Instance.PutAsync(url, headers);
}
catch (Exception ex)
{
Logging.SaveLog(_tag, ex);
}
}
public async Task<ClashConnections?> GetClashConnectionsAsync()
{
try
{
var url = $"{GetApiUrl()}/connections";
var result = await HttpClientHelper.Instance.TryGetAsync(url);
var clashConnections = JsonUtils.Deserialize<ClashConnections>(result);
return clashConnections;
}
catch (Exception ex)
{
Logging.SaveLog(_tag, ex);
}
return null;
}
public async Task ClashConnectionClose(string id)
{
try
{
var url = $"{GetApiUrl()}/connections/{id}";
await HttpClientHelper.Instance.DeleteAsync(url);
}
catch (Exception ex)
{
Logging.SaveLog(_tag, ex);
}
}
private string GetApiUrl()
{
return $"{Global.HttpProtocol}{Global.Loopback}:{AppHandler.Instance.StatePort2}";
}
}
File diff suppressed because it is too large Load Diff
+135 -140
View File
@@ -1,160 +1,155 @@
using DynamicData;
using ServiceLib.Enums;
using ServiceLib.Models;
namespace ServiceLib.Handler;
namespace ServiceLib.Handler
/// <summary>
/// Core configuration file processing class
/// </summary>
public class CoreConfigHandler
{
/// <summary>
/// Core configuration file processing class
/// </summary>
public class CoreConfigHandler
private static readonly string _tag = "CoreConfigHandler";
public static async Task<RetResult> GenerateClientConfig(ProfileItem node, string? fileName)
{
private static readonly string _tag = "CoreConfigHandler";
var config = AppHandler.Instance.Config;
var result = new RetResult();
public static async Task<RetResult> GenerateClientConfig(ProfileItem node, string? fileName)
if (node.ConfigType == EConfigType.Custom)
{
var config = AppHandler.Instance.Config;
var result = new RetResult();
if (node.ConfigType == EConfigType.Custom)
result = node.CoreType switch
{
result = node.CoreType switch
{
ECoreType.mihomo => await new CoreConfigClashService(config).GenerateClientCustomConfig(node, fileName),
ECoreType.sing_box => await new CoreConfigSingboxService(config).GenerateClientCustomConfig(node, fileName),
_ => await GenerateClientCustomConfig(node, fileName)
};
}
else if (AppHandler.Instance.GetCoreType(node, node.ConfigType) == ECoreType.sing_box)
{
result = await new CoreConfigSingboxService(config).GenerateClientConfigContent(node);
}
else
{
result = await new CoreConfigV2rayService(config).GenerateClientConfigContent(node);
}
if (result.Success != true)
{
return result;
}
if (fileName.IsNotEmpty() && result.Data != null)
{
await File.WriteAllTextAsync(fileName, result.Data.ToString());
}
ECoreType.mihomo => await new CoreConfigClashService(config).GenerateClientCustomConfig(node, fileName),
ECoreType.sing_box => await new CoreConfigSingboxService(config).GenerateClientCustomConfig(node, fileName),
_ => await GenerateClientCustomConfig(node, fileName)
};
}
else if (AppHandler.Instance.GetCoreType(node, node.ConfigType) == ECoreType.sing_box)
{
result = await new CoreConfigSingboxService(config).GenerateClientConfigContent(node);
}
else
{
result = await new CoreConfigV2rayService(config).GenerateClientConfigContent(node);
}
if (result.Success != true)
{
return result;
}
private static async Task<RetResult> GenerateClientCustomConfig(ProfileItem node, string? fileName)
if (fileName.IsNotEmpty() && result.Data != null)
{
var ret = new RetResult();
try
await File.WriteAllTextAsync(fileName, result.Data.ToString());
}
return result;
}
private static async Task<RetResult> GenerateClientCustomConfig(ProfileItem node, string? fileName)
{
var ret = new RetResult();
try
{
if (node == null || fileName is null)
{
if (node == null || fileName is null)
{
ret.Msg = ResUI.CheckServerSettings;
return ret;
}
if (File.Exists(fileName))
{
File.SetAttributes(fileName, FileAttributes.Normal); //If the file has a read-only attribute, direct deletion will fail
File.Delete(fileName);
}
string addressFileName = node.Address;
if (!File.Exists(addressFileName))
{
addressFileName = Utils.GetConfigPath(addressFileName);
}
if (!File.Exists(addressFileName))
{
ret.Msg = ResUI.FailedGenDefaultConfiguration;
return ret;
}
File.Copy(addressFileName, fileName);
File.SetAttributes(fileName, FileAttributes.Normal); //Copy will keep the attributes of addressFileName, so we need to add write permissions to fileName just in case of addressFileName is a read-only file.
//check again
if (!File.Exists(fileName))
{
ret.Msg = ResUI.FailedGenDefaultConfiguration;
return ret;
}
ret.Msg = string.Format(ResUI.SuccessfulConfiguration, "");
ret.Success = true;
return await Task.FromResult(ret);
ret.Msg = ResUI.CheckServerSettings;
return ret;
}
catch (Exception ex)
if (File.Exists(fileName))
{
File.SetAttributes(fileName, FileAttributes.Normal); //If the file has a read-only attribute, direct deletion will fail
File.Delete(fileName);
}
string addressFileName = node.Address;
if (!File.Exists(addressFileName))
{
addressFileName = Utils.GetConfigPath(addressFileName);
}
if (!File.Exists(addressFileName))
{
Logging.SaveLog(_tag, ex);
ret.Msg = ResUI.FailedGenDefaultConfiguration;
return ret;
}
File.Copy(addressFileName, fileName);
File.SetAttributes(fileName, FileAttributes.Normal); //Copy will keep the attributes of addressFileName, so we need to add write permissions to fileName just in case of addressFileName is a read-only file.
//check again
if (!File.Exists(fileName))
{
ret.Msg = ResUI.FailedGenDefaultConfiguration;
return ret;
}
ret.Msg = string.Format(ResUI.SuccessfulConfiguration, "");
ret.Success = true;
return await Task.FromResult(ret);
}
public static async Task<RetResult> GenerateClientSpeedtestConfig(Config config, string fileName, List<ServerTestItem> selecteds, ECoreType coreType)
catch (Exception ex)
{
var result = new RetResult();
if (coreType == ECoreType.sing_box)
{
result = await new CoreConfigSingboxService(config).GenerateClientSpeedtestConfig(selecteds);
}
else if (coreType == ECoreType.Xray)
{
result = await new CoreConfigV2rayService(config).GenerateClientSpeedtestConfig(selecteds);
}
if (result.Success != true)
{
return result;
}
await File.WriteAllTextAsync(fileName, result.Data.ToString());
return result;
}
public static async Task<RetResult> GenerateClientSpeedtestConfig(Config config, ProfileItem node, ServerTestItem testItem, string fileName)
{
var result = new RetResult();
var initPort = AppHandler.Instance.GetLocalPort(EInboundProtocol.speedtest);
var port = Utils.GetFreePort(initPort + testItem.QueueNum);
testItem.Port = port;
if (AppHandler.Instance.GetCoreType(node, node.ConfigType) == ECoreType.sing_box)
{
result = await new CoreConfigSingboxService(config).GenerateClientSpeedtestConfig(node, port);
}
else
{
result = await new CoreConfigV2rayService(config).GenerateClientSpeedtestConfig(node, port);
}
if (result.Success != true)
{
return result;
}
await File.WriteAllTextAsync(fileName, result.Data.ToString());
return result;
}
public static async Task<RetResult> GenerateClientMultipleLoadConfig(Config config, string fileName, List<ProfileItem> selecteds, ECoreType coreType, EMultipleLoad multipleLoad)
{
var result = new RetResult();
if (coreType == ECoreType.sing_box)
{
result = await new CoreConfigSingboxService(config).GenerateClientMultipleLoadConfig(selecteds);
}
else
{
result = await new CoreConfigV2rayService(config).GenerateClientMultipleLoadConfig(selecteds, multipleLoad);
}
if (result.Success != true)
{
return result;
}
await File.WriteAllTextAsync(fileName, result.Data.ToString());
return result;
Logging.SaveLog(_tag, ex);
ret.Msg = ResUI.FailedGenDefaultConfiguration;
return ret;
}
}
public static async Task<RetResult> GenerateClientSpeedtestConfig(Config config, string fileName, List<ServerTestItem> selecteds, ECoreType coreType)
{
var result = new RetResult();
if (coreType == ECoreType.sing_box)
{
result = await new CoreConfigSingboxService(config).GenerateClientSpeedtestConfig(selecteds);
}
else if (coreType == ECoreType.Xray)
{
result = await new CoreConfigV2rayService(config).GenerateClientSpeedtestConfig(selecteds);
}
if (result.Success != true)
{
return result;
}
await File.WriteAllTextAsync(fileName, result.Data.ToString());
return result;
}
public static async Task<RetResult> GenerateClientSpeedtestConfig(Config config, ProfileItem node, ServerTestItem testItem, string fileName)
{
var result = new RetResult();
var initPort = AppHandler.Instance.GetLocalPort(EInboundProtocol.speedtest);
var port = Utils.GetFreePort(initPort + testItem.QueueNum);
testItem.Port = port;
if (AppHandler.Instance.GetCoreType(node, node.ConfigType) == ECoreType.sing_box)
{
result = await new CoreConfigSingboxService(config).GenerateClientSpeedtestConfig(node, port);
}
else
{
result = await new CoreConfigV2rayService(config).GenerateClientSpeedtestConfig(node, port);
}
if (result.Success != true)
{
return result;
}
await File.WriteAllTextAsync(fileName, result.Data.ToString());
return result;
}
public static async Task<RetResult> GenerateClientMultipleLoadConfig(Config config, string fileName, List<ProfileItem> selecteds, ECoreType coreType, EMultipleLoad multipleLoad)
{
var result = new RetResult();
if (coreType == ECoreType.sing_box)
{
result = await new CoreConfigSingboxService(config).GenerateClientMultipleLoadConfig(selecteds);
}
else
{
result = await new CoreConfigV2rayService(config).GenerateClientMultipleLoadConfig(selecteds, multipleLoad);
}
if (result.Success != true)
{
return result;
}
await File.WriteAllTextAsync(fileName, result.Data.ToString());
return result;
}
}
+339 -340
View File
@@ -1,410 +1,409 @@
using System.Diagnostics;
using System.Text;
namespace ServiceLib.Handler
namespace ServiceLib.Handler;
/// <summary>
/// Core process processing class
/// </summary>
public class CoreHandler
{
/// <summary>
/// Core process processing class
/// </summary>
public class CoreHandler
private static readonly Lazy<CoreHandler> _instance = new(() => new());
public static CoreHandler Instance => _instance.Value;
private Config _config;
private Process? _process;
private Process? _processPre;
private int _linuxSudoPid = -1;
private Action<bool, string>? _updateFunc;
private const string _tag = "CoreHandler";
public async Task Init(Config config, Action<bool, string> updateFunc)
{
private static readonly Lazy<CoreHandler> _instance = new(() => new());
public static CoreHandler Instance => _instance.Value;
private Config _config;
private Process? _process;
private Process? _processPre;
private int _linuxSudoPid = -1;
private Action<bool, string>? _updateFunc;
private const string _tag = "CoreHandler";
_config = config;
_updateFunc = updateFunc;
public async Task Init(Config config, Action<bool, string> updateFunc)
Environment.SetEnvironmentVariable(Global.V2RayLocalAsset, Utils.GetBinPath(""), EnvironmentVariableTarget.Process);
Environment.SetEnvironmentVariable(Global.XrayLocalAsset, Utils.GetBinPath(""), EnvironmentVariableTarget.Process);
Environment.SetEnvironmentVariable(Global.XrayLocalCert, Utils.GetBinPath(""), EnvironmentVariableTarget.Process);
//Copy the bin folder to the storage location (for init)
if (Environment.GetEnvironmentVariable(Global.LocalAppData) == "1")
{
_config = config;
_updateFunc = updateFunc;
Environment.SetEnvironmentVariable(Global.V2RayLocalAsset, Utils.GetBinPath(""), EnvironmentVariableTarget.Process);
Environment.SetEnvironmentVariable(Global.XrayLocalAsset, Utils.GetBinPath(""), EnvironmentVariableTarget.Process);
Environment.SetEnvironmentVariable(Global.XrayLocalCert, Utils.GetBinPath(""), EnvironmentVariableTarget.Process);
//Copy the bin folder to the storage location (for init)
if (Environment.GetEnvironmentVariable(Global.LocalAppData) == "1")
var fromPath = Utils.GetBaseDirectory("bin");
var toPath = Utils.GetBinPath("");
if (fromPath != toPath)
{
var fromPath = Utils.GetBaseDirectory("bin");
var toPath = Utils.GetBinPath("");
if (fromPath != toPath)
{
FileManager.CopyDirectory(fromPath, toPath, true, false);
}
FileManager.CopyDirectory(fromPath, toPath, true, false);
}
}
if (Utils.IsNonWindows())
if (Utils.IsNonWindows())
{
var coreInfo = CoreInfoHandler.Instance.GetCoreInfo();
foreach (var it in coreInfo)
{
var coreInfo = CoreInfoHandler.Instance.GetCoreInfo();
foreach (var it in coreInfo)
if (it.CoreType == ECoreType.v2rayN)
{
if (it.CoreType == ECoreType.v2rayN)
if (Utils.UpgradeAppExists(out var upgradeFileName))
{
if (Utils.UpgradeAppExists(out var upgradeFileName))
{
await Utils.SetLinuxChmod(upgradeFileName);
}
continue;
await Utils.SetLinuxChmod(upgradeFileName);
}
continue;
}
foreach (var name in it.CoreExes)
foreach (var name in it.CoreExes)
{
var exe = Utils.GetBinPath(Utils.GetExeName(name), it.CoreType.ToString());
if (File.Exists(exe))
{
var exe = Utils.GetBinPath(Utils.GetExeName(name), it.CoreType.ToString());
if (File.Exists(exe))
{
await Utils.SetLinuxChmod(exe);
}
await Utils.SetLinuxChmod(exe);
}
}
}
}
}
public async Task LoadCore(ProfileItem? node)
public async Task LoadCore(ProfileItem? node)
{
if (node == null)
{
if (node == null)
{
UpdateFunc(false, ResUI.CheckServerSettings);
return;
}
UpdateFunc(false, ResUI.CheckServerSettings);
return;
}
var fileName = Utils.GetBinConfigPath(Global.CoreConfigFileName);
var result = await CoreConfigHandler.GenerateClientConfig(node, fileName);
if (result.Success != true)
{
UpdateFunc(true, result.Msg);
return;
}
var fileName = Utils.GetBinConfigPath(Global.CoreConfigFileName);
var result = await CoreConfigHandler.GenerateClientConfig(node, fileName);
if (result.Success != true)
{
UpdateFunc(true, result.Msg);
return;
}
UpdateFunc(false, $"{node.GetSummary()}");
UpdateFunc(false, $"{Utils.GetRuntimeInfo()}");
UpdateFunc(false, string.Format(ResUI.StartService, DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss")));
await CoreStop();
UpdateFunc(false, $"{node.GetSummary()}");
UpdateFunc(false, $"{Utils.GetRuntimeInfo()}");
UpdateFunc(false, string.Format(ResUI.StartService, DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss")));
await CoreStop();
await Task.Delay(100);
if (Utils.IsWindows() && _config.TunModeItem.EnableTun)
{
await Task.Delay(100);
await WindowsUtils.RemoveTunDevice();
}
if (Utils.IsWindows() && _config.TunModeItem.EnableTun)
{
await Task.Delay(100);
await WindowsUtils.RemoveTunDevice();
}
await CoreStart(node);
await CoreStartPreService(node);
if (_process != null)
{
UpdateFunc(true, $"{node.GetSummary()}");
}
}
await CoreStart(node);
await CoreStartPreService(node);
public async Task<int> LoadCoreConfigSpeedtest(List<ServerTestItem> selecteds)
{
var coreType = selecteds.Exists(t => t.ConfigType is EConfigType.Hysteria2 or EConfigType.TUIC or EConfigType.WireGuard) ? ECoreType.sing_box : ECoreType.Xray;
var fileName = string.Format(Global.CoreSpeedtestConfigFileName, Utils.GetGuid(false));
var configPath = Utils.GetBinConfigPath(fileName);
var result = await CoreConfigHandler.GenerateClientSpeedtestConfig(_config, configPath, selecteds, coreType);
UpdateFunc(false, result.Msg);
if (result.Success != true)
{
return -1;
}
UpdateFunc(false, string.Format(ResUI.StartService, DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss")));
UpdateFunc(false, configPath);
var coreInfo = CoreInfoHandler.Instance.GetCoreInfo(coreType);
var proc = await RunProcess(coreInfo, fileName, true, false);
if (proc is null)
{
return -1;
}
return proc.Id;
}
public async Task<int> LoadCoreConfigSpeedtest(ServerTestItem testItem)
{
var node = await AppHandler.Instance.GetProfileItem(testItem.IndexId);
if (node is null)
{
return -1;
}
var fileName = string.Format(Global.CoreSpeedtestConfigFileName, Utils.GetGuid(false));
var configPath = Utils.GetBinConfigPath(fileName);
var result = await CoreConfigHandler.GenerateClientSpeedtestConfig(_config, node, testItem, configPath);
if (result.Success != true)
{
return -1;
}
var coreType = AppHandler.Instance.GetCoreType(node, node.ConfigType);
var coreInfo = CoreInfoHandler.Instance.GetCoreInfo(coreType);
var proc = await RunProcess(coreInfo, fileName, true, false);
if (proc is null)
{
return -1;
}
return proc.Id;
}
public async Task CoreStop()
{
try
{
if (_process != null)
{
UpdateFunc(true, $"{node.GetSummary()}");
await ProcUtils.ProcessKill(_process, true);
_process = null;
}
if (_processPre != null)
{
await ProcUtils.ProcessKill(_processPre, true);
_processPre = null;
}
if (_linuxSudoPid > 0)
{
await KillProcessAsLinuxSudo();
}
_linuxSudoPid = -1;
}
public async Task<int> LoadCoreConfigSpeedtest(List<ServerTestItem> selecteds)
catch (Exception ex)
{
var coreType = selecteds.Exists(t => t.ConfigType is EConfigType.Hysteria2 or EConfigType.TUIC or EConfigType.WireGuard) ? ECoreType.sing_box : ECoreType.Xray;
var fileName = string.Format(Global.CoreSpeedtestConfigFileName, Utils.GetGuid(false));
var configPath = Utils.GetBinConfigPath(fileName);
var result = await CoreConfigHandler.GenerateClientSpeedtestConfig(_config, configPath, selecteds, coreType);
UpdateFunc(false, result.Msg);
if (result.Success != true)
{
return -1;
}
UpdateFunc(false, string.Format(ResUI.StartService, DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss")));
UpdateFunc(false, configPath);
var coreInfo = CoreInfoHandler.Instance.GetCoreInfo(coreType);
var proc = await RunProcess(coreInfo, fileName, true, false);
if (proc is null)
{
return -1;
}
return proc.Id;
Logging.SaveLog(_tag, ex);
}
}
public async Task<int> LoadCoreConfigSpeedtest(ServerTestItem testItem)
#region Private
private async Task CoreStart(ProfileItem node)
{
var coreType = _config.RunningCoreType = AppHandler.Instance.GetCoreType(node, node.ConfigType);
var coreInfo = CoreInfoHandler.Instance.GetCoreInfo(coreType);
var displayLog = node.ConfigType != EConfigType.Custom || node.DisplayLog;
var proc = await RunProcess(coreInfo, Global.CoreConfigFileName, displayLog, true);
if (proc is null)
{
var node = await AppHandler.Instance.GetProfileItem(testItem.IndexId);
if (node is null)
{
return -1;
}
var fileName = string.Format(Global.CoreSpeedtestConfigFileName, Utils.GetGuid(false));
var configPath = Utils.GetBinConfigPath(fileName);
var result = await CoreConfigHandler.GenerateClientSpeedtestConfig(_config, node, testItem, configPath);
if (result.Success != true)
{
return -1;
}
return;
}
_process = proc;
}
private async Task CoreStartPreService(ProfileItem node)
{
if (_process != null && !_process.HasExited)
{
var coreType = AppHandler.Instance.GetCoreType(node, node.ConfigType);
var coreInfo = CoreInfoHandler.Instance.GetCoreInfo(coreType);
var proc = await RunProcess(coreInfo, fileName, true, false);
if (proc is null)
var itemSocks = await ConfigHandler.GetPreSocksItem(_config, node, coreType);
if (itemSocks != null)
{
return -1;
}
return proc.Id;
}
public async Task CoreStop()
{
try
{
if (_process != null)
var preCoreType = itemSocks.CoreType ?? ECoreType.sing_box;
var fileName = Utils.GetBinConfigPath(Global.CorePreConfigFileName);
var result = await CoreConfigHandler.GenerateClientConfig(itemSocks, fileName);
if (result.Success)
{
await ProcUtils.ProcessKill(_process, true);
_process = null;
}
if (_processPre != null)
{
await ProcUtils.ProcessKill(_processPre, true);
_processPre = null;
}
if (_linuxSudoPid > 0)
{
await KillProcessAsLinuxSudo();
}
_linuxSudoPid = -1;
}
catch (Exception ex)
{
Logging.SaveLog(_tag, ex);
}
}
#region Private
private async Task CoreStart(ProfileItem node)
{
var coreType = _config.RunningCoreType = AppHandler.Instance.GetCoreType(node, node.ConfigType);
var coreInfo = CoreInfoHandler.Instance.GetCoreInfo(coreType);
var displayLog = node.ConfigType != EConfigType.Custom || node.DisplayLog;
var proc = await RunProcess(coreInfo, Global.CoreConfigFileName, displayLog, true);
if (proc is null)
{
return;
}
_process = proc;
}
private async Task CoreStartPreService(ProfileItem node)
{
if (_process != null && !_process.HasExited)
{
var coreType = AppHandler.Instance.GetCoreType(node, node.ConfigType);
var itemSocks = await ConfigHandler.GetPreSocksItem(_config, node, coreType);
if (itemSocks != null)
{
var preCoreType = itemSocks.CoreType ?? ECoreType.sing_box;
var fileName = Utils.GetBinConfigPath(Global.CorePreConfigFileName);
var result = await CoreConfigHandler.GenerateClientConfig(itemSocks, fileName);
if (result.Success)
var coreInfo = CoreInfoHandler.Instance.GetCoreInfo(preCoreType);
var proc = await RunProcess(coreInfo, Global.CorePreConfigFileName, true, true);
if (proc is null)
{
var coreInfo = CoreInfoHandler.Instance.GetCoreInfo(preCoreType);
var proc = await RunProcess(coreInfo, Global.CorePreConfigFileName, true, true);
if (proc is null)
{
return;
}
_processPre = proc;
return;
}
_processPre = proc;
}
}
}
}
private void UpdateFunc(bool notify, string msg)
private void UpdateFunc(bool notify, string msg)
{
_updateFunc?.Invoke(notify, msg);
}
private bool IsNeedSudo(ECoreType eCoreType)
{
return _config.TunModeItem.EnableTun
&& eCoreType == ECoreType.sing_box
&& (Utils.IsNonWindows())
//&& _config.TunModeItem.LinuxSudoPwd.IsNotEmpty()
;
}
#endregion Private
#region Process
private async Task<Process?> RunProcess(CoreInfo? coreInfo, string configPath, bool displayLog, bool mayNeedSudo)
{
var fileName = CoreInfoHandler.Instance.GetCoreExecFile(coreInfo, out var msg);
if (fileName.IsNullOrEmpty())
{
_updateFunc?.Invoke(notify, msg);
UpdateFunc(false, msg);
return null;
}
private bool IsNeedSudo(ECoreType eCoreType)
try
{
return _config.TunModeItem.EnableTun
&& eCoreType == ECoreType.sing_box
&& (Utils.IsNonWindows())
//&& _config.TunModeItem.LinuxSudoPwd.IsNotEmpty()
;
}
#endregion Private
#region Process
private async Task<Process?> RunProcess(CoreInfo? coreInfo, string configPath, bool displayLog, bool mayNeedSudo)
{
var fileName = CoreInfoHandler.Instance.GetCoreExecFile(coreInfo, out var msg);
if (fileName.IsNullOrEmpty())
{
UpdateFunc(false, msg);
return null;
}
try
{
Process proc = new()
{
StartInfo = new()
{
FileName = fileName,
Arguments = string.Format(coreInfo.Arguments, coreInfo.AbsolutePath ? Utils.GetBinConfigPath(configPath).AppendQuotes() : configPath),
WorkingDirectory = Utils.GetBinConfigPath(),
UseShellExecute = false,
RedirectStandardOutput = displayLog,
RedirectStandardError = displayLog,
CreateNoWindow = true,
StandardOutputEncoding = displayLog ? Encoding.UTF8 : null,
StandardErrorEncoding = displayLog ? Encoding.UTF8 : null,
}
};
var isNeedSudo = mayNeedSudo && IsNeedSudo(coreInfo.CoreType);
if (isNeedSudo)
{
await RunProcessAsLinuxSudo(proc, fileName, coreInfo, configPath);
}
if (displayLog)
{
proc.OutputDataReceived += (sender, e) =>
{
if (e.Data.IsNullOrEmpty())
return;
UpdateFunc(false, e.Data + Environment.NewLine);
};
proc.ErrorDataReceived += (sender, e) =>
{
if (e.Data.IsNullOrEmpty())
return;
UpdateFunc(false, e.Data + Environment.NewLine);
};
}
proc.Start();
if (isNeedSudo && _config.TunModeItem.LinuxSudoPwd.IsNotEmpty())
{
var pwd = DesUtils.Decrypt(_config.TunModeItem.LinuxSudoPwd);
await Task.Delay(10);
await proc.StandardInput.WriteLineAsync(pwd);
await Task.Delay(10);
await proc.StandardInput.WriteLineAsync(pwd);
}
if (isNeedSudo)
_linuxSudoPid = proc.Id;
if (displayLog)
{
proc.BeginOutputReadLine();
proc.BeginErrorReadLine();
}
await Task.Delay(500);
AppHandler.Instance.AddProcess(proc.Handle);
if (proc is null or { HasExited: true })
{
throw new Exception(ResUI.FailedToRunCore);
}
return proc;
}
catch (Exception ex)
{
Logging.SaveLog(_tag, ex);
UpdateFunc(mayNeedSudo, ex.Message);
return null;
}
}
#endregion Process
#region Linux
private async Task RunProcessAsLinuxSudo(Process proc, string fileName, CoreInfo coreInfo, string configPath)
{
var cmdLine = $"{fileName.AppendQuotes()} {string.Format(coreInfo.Arguments, Utils.GetBinConfigPath(configPath).AppendQuotes())}";
var shFilePath = await CreateLinuxShellFile(cmdLine, "run_as_sudo.sh");
proc.StartInfo.FileName = shFilePath;
proc.StartInfo.Arguments = "";
proc.StartInfo.WorkingDirectory = "";
if (_config.TunModeItem.LinuxSudoPwd.IsNotEmpty())
{
proc.StartInfo.StandardInputEncoding = Encoding.UTF8;
proc.StartInfo.RedirectStandardInput = true;
}
}
private async Task KillProcessAsLinuxSudo()
{
var cmdLine = $"kill {_linuxSudoPid}";
var shFilePath = await CreateLinuxShellFile(cmdLine, "kill_as_sudo.sh");
Process proc = new()
{
StartInfo = new()
{
FileName = shFilePath,
FileName = fileName,
Arguments = string.Format(coreInfo.Arguments, coreInfo.AbsolutePath ? Utils.GetBinConfigPath(configPath).AppendQuotes() : configPath),
WorkingDirectory = Utils.GetBinConfigPath(),
UseShellExecute = false,
RedirectStandardOutput = displayLog,
RedirectStandardError = displayLog,
CreateNoWindow = true,
StandardInputEncoding = Encoding.UTF8,
RedirectStandardInput = true
StandardOutputEncoding = displayLog ? Encoding.UTF8 : null,
StandardErrorEncoding = displayLog ? Encoding.UTF8 : null,
}
};
var isNeedSudo = mayNeedSudo && IsNeedSudo(coreInfo.CoreType);
if (isNeedSudo)
{
await RunProcessAsLinuxSudo(proc, fileName, coreInfo, configPath);
}
if (displayLog)
{
proc.OutputDataReceived += (sender, e) =>
{
if (e.Data.IsNullOrEmpty())
return;
UpdateFunc(false, e.Data + Environment.NewLine);
};
proc.ErrorDataReceived += (sender, e) =>
{
if (e.Data.IsNullOrEmpty())
return;
UpdateFunc(false, e.Data + Environment.NewLine);
};
}
proc.Start();
if (_config.TunModeItem.LinuxSudoPwd.IsNotEmpty())
if (isNeedSudo && _config.TunModeItem.LinuxSudoPwd.IsNotEmpty())
{
try
{
var pwd = DesUtils.Decrypt(_config.TunModeItem.LinuxSudoPwd);
await Task.Delay(10);
await proc.StandardInput.WriteLineAsync(pwd);
await Task.Delay(10);
await proc.StandardInput.WriteLineAsync(pwd);
}
catch (Exception)
{
// ignored
}
var pwd = DesUtils.Decrypt(_config.TunModeItem.LinuxSudoPwd);
await Task.Delay(10);
await proc.StandardInput.WriteLineAsync(pwd);
await Task.Delay(10);
await proc.StandardInput.WriteLineAsync(pwd);
}
if (isNeedSudo)
_linuxSudoPid = proc.Id;
if (displayLog)
{
proc.BeginOutputReadLine();
proc.BeginErrorReadLine();
}
var timeout = new CancellationTokenSource(TimeSpan.FromSeconds(10));
await proc.WaitForExitAsync(timeout.Token);
await Task.Delay(3000);
await Task.Delay(500);
AppHandler.Instance.AddProcess(proc.Handle);
if (proc is null or { HasExited: true })
{
throw new Exception(ResUI.FailedToRunCore);
}
return proc;
}
private async Task<string> CreateLinuxShellFile(string cmdLine, string fileName)
catch (Exception ex)
{
//Shell scripts
var shFilePath = Utils.GetBinConfigPath(AppHandler.Instance.IsAdministrator ? "root_" + fileName : fileName);
File.Delete(shFilePath);
var sb = new StringBuilder();
sb.AppendLine("#!/bin/sh");
if (AppHandler.Instance.IsAdministrator)
{
sb.AppendLine($"{cmdLine}");
}
else if (_config.TunModeItem.LinuxSudoPwd.IsNullOrEmpty())
{
sb.AppendLine($"pkexec {cmdLine}");
}
else
{
sb.AppendLine($"sudo -S {cmdLine}");
}
Logging.SaveLog(_tag, ex);
UpdateFunc(mayNeedSudo, ex.Message);
return null;
}
}
await File.WriteAllTextAsync(shFilePath, sb.ToString());
await Utils.SetLinuxChmod(shFilePath);
Logging.SaveLog(shFilePath);
#endregion Process
return shFilePath;
#region Linux
private async Task RunProcessAsLinuxSudo(Process proc, string fileName, CoreInfo coreInfo, string configPath)
{
var cmdLine = $"{fileName.AppendQuotes()} {string.Format(coreInfo.Arguments, Utils.GetBinConfigPath(configPath).AppendQuotes())}";
var shFilePath = await CreateLinuxShellFile(cmdLine, "run_as_sudo.sh");
proc.StartInfo.FileName = shFilePath;
proc.StartInfo.Arguments = "";
proc.StartInfo.WorkingDirectory = "";
if (_config.TunModeItem.LinuxSudoPwd.IsNotEmpty())
{
proc.StartInfo.StandardInputEncoding = Encoding.UTF8;
proc.StartInfo.RedirectStandardInput = true;
}
}
private async Task KillProcessAsLinuxSudo()
{
var cmdLine = $"kill {_linuxSudoPid}";
var shFilePath = await CreateLinuxShellFile(cmdLine, "kill_as_sudo.sh");
Process proc = new()
{
StartInfo = new()
{
FileName = shFilePath,
UseShellExecute = false,
CreateNoWindow = true,
StandardInputEncoding = Encoding.UTF8,
RedirectStandardInput = true
}
};
proc.Start();
if (_config.TunModeItem.LinuxSudoPwd.IsNotEmpty())
{
try
{
var pwd = DesUtils.Decrypt(_config.TunModeItem.LinuxSudoPwd);
await Task.Delay(10);
await proc.StandardInput.WriteLineAsync(pwd);
await Task.Delay(10);
await proc.StandardInput.WriteLineAsync(pwd);
}
catch (Exception)
{
// ignored
}
}
#endregion Linux
var timeout = new CancellationTokenSource(TimeSpan.FromSeconds(10));
await proc.WaitForExitAsync(timeout.Token);
await Task.Delay(3000);
}
private async Task<string> CreateLinuxShellFile(string cmdLine, string fileName)
{
//Shell scripts
var shFilePath = Utils.GetBinConfigPath(AppHandler.Instance.IsAdministrator ? "root_" + fileName : fileName);
File.Delete(shFilePath);
var sb = new StringBuilder();
sb.AppendLine("#!/bin/sh");
if (AppHandler.Instance.IsAdministrator)
{
sb.AppendLine($"{cmdLine}");
}
else if (_config.TunModeItem.LinuxSudoPwd.IsNullOrEmpty())
{
sb.AppendLine($"pkexec {cmdLine}");
}
else
{
sb.AppendLine($"sudo -S {cmdLine}");
}
await File.WriteAllTextAsync(shFilePath, sb.ToString());
await Utils.SetLinuxChmod(shFilePath);
Logging.SaveLog(shFilePath);
return shFilePath;
}
#endregion Linux
}
+55 -56
View File
@@ -1,65 +1,65 @@
namespace ServiceLib.Handler
{
public sealed class CoreInfoHandler
{
private static readonly Lazy<CoreInfoHandler> _instance = new(() => new());
private List<CoreInfo>? _coreInfo;
public static CoreInfoHandler Instance => _instance.Value;
namespace ServiceLib.Handler;
public CoreInfoHandler()
public sealed class CoreInfoHandler
{
private static readonly Lazy<CoreInfoHandler> _instance = new(() => new());
private List<CoreInfo>? _coreInfo;
public static CoreInfoHandler Instance => _instance.Value;
public CoreInfoHandler()
{
InitCoreInfo();
}
public CoreInfo? GetCoreInfo(ECoreType coreType)
{
if (_coreInfo == null)
{
InitCoreInfo();
}
return _coreInfo?.FirstOrDefault(t => t.CoreType == coreType);
}
public CoreInfo? GetCoreInfo(ECoreType coreType)
public List<CoreInfo> GetCoreInfo()
{
if (_coreInfo == null)
{
if (_coreInfo == null)
{
InitCoreInfo();
}
return _coreInfo?.FirstOrDefault(t => t.CoreType == coreType);
InitCoreInfo();
}
return _coreInfo ?? [];
}
public List<CoreInfo> GetCoreInfo()
public string GetCoreExecFile(CoreInfo? coreInfo, out string msg)
{
var fileName = string.Empty;
msg = string.Empty;
foreach (var name in coreInfo?.CoreExes)
{
if (_coreInfo == null)
var vName = Utils.GetBinPath(Utils.GetExeName(name), coreInfo.CoreType.ToString());
if (File.Exists(vName))
{
InitCoreInfo();
fileName = vName;
break;
}
return _coreInfo ?? [];
}
public string GetCoreExecFile(CoreInfo? coreInfo, out string msg)
if (fileName.IsNullOrEmpty())
{
var fileName = string.Empty;
msg = string.Empty;
foreach (var name in coreInfo?.CoreExes)
{
var vName = Utils.GetBinPath(Utils.GetExeName(name), coreInfo.CoreType.ToString());
if (File.Exists(vName))
{
fileName = vName;
break;
}
}
if (fileName.IsNullOrEmpty())
{
msg = string.Format(ResUI.NotFoundCore, Utils.GetBinPath("", coreInfo?.CoreType.ToString()), coreInfo?.CoreExes?.LastOrDefault(), coreInfo?.Url);
Logging.SaveLog(msg);
}
return fileName;
msg = string.Format(ResUI.NotFoundCore, Utils.GetBinPath("", coreInfo?.CoreType.ToString()), coreInfo?.CoreExes?.LastOrDefault(), coreInfo?.Url);
Logging.SaveLog(msg);
}
return fileName;
}
private void InitCoreInfo()
{
var urlN = GetCoreUrl(ECoreType.v2rayN);
var urlXray = GetCoreUrl(ECoreType.Xray);
var urlMihomo = GetCoreUrl(ECoreType.mihomo);
var urlSingbox = GetCoreUrl(ECoreType.sing_box);
private void InitCoreInfo()
{
var urlN = GetCoreUrl(ECoreType.v2rayN);
var urlXray = GetCoreUrl(ECoreType.Xray);
var urlMihomo = GetCoreUrl(ECoreType.mihomo);
var urlSingbox = GetCoreUrl(ECoreType.sing_box);
_coreInfo =
[
new CoreInfo
_coreInfo =
[
new CoreInfo
{
CoreType = ECoreType.v2rayN,
Url = GetCoreUrl(ECoreType.v2rayN),
@@ -202,17 +202,16 @@ namespace ServiceLib.Handler
AbsolutePath = false,
}
];
}
];
}
private static string PortableMode()
{
return $" -d {Utils.GetBinPath("").AppendQuotes()}";
}
private static string PortableMode()
{
return $" -d {Utils.GetBinPath("").AppendQuotes()}";
}
private static string GetCoreUrl(ECoreType eCoreType)
{
return $"{Global.GithubUrl}/{Global.CoreUrls[eCoreType]}/releases";
}
private static string GetCoreUrl(ECoreType eCoreType)
{
return $"{Global.GithubUrl}/{Global.CoreUrls[eCoreType]}/releases";
}
}
+212 -213
View File
@@ -1,242 +1,241 @@
using System.Collections.Specialized;
namespace ServiceLib.Handler.Fmt
namespace ServiceLib.Handler.Fmt;
public class BaseFmt
{
public class BaseFmt
protected static string GetIpv6(string address)
{
protected static string GetIpv6(string address)
if (Utils.IsIpv6(address))
{
if (Utils.IsIpv6(address))
{
// 检查地址是否已经被方括号包围,如果没有,则添加方括号
return address.StartsWith('[') && address.EndsWith(']') ? address : $"[{address}]";
}
return address; // 如果不是IPv6地址,直接返回原地址
// 检查地址是否已经被方括号包围,如果没有,则添加方括号
return address.StartsWith('[') && address.EndsWith(']') ? address : $"[{address}]";
}
return address; // 如果不是IPv6地址,直接返回原地址
}
protected static int GetStdTransport(ProfileItem item, string? securityDef, ref Dictionary<string, string> dicQuery)
{
if (item.Flow.IsNotEmpty())
{
dicQuery.Add("flow", item.Flow);
}
protected static int GetStdTransport(ProfileItem item, string? securityDef, ref Dictionary<string, string> dicQuery)
if (item.StreamSecurity.IsNotEmpty())
{
if (item.Flow.IsNotEmpty())
dicQuery.Add("security", item.StreamSecurity);
}
else
{
if (securityDef != null)
{
dicQuery.Add("flow", item.Flow);
dicQuery.Add("security", securityDef);
}
}
if (item.Sni.IsNotEmpty())
{
dicQuery.Add("sni", item.Sni);
}
if (item.Alpn.IsNotEmpty())
{
dicQuery.Add("alpn", Utils.UrlEncode(item.Alpn));
}
if (item.Fingerprint.IsNotEmpty())
{
dicQuery.Add("fp", Utils.UrlEncode(item.Fingerprint));
}
if (item.PublicKey.IsNotEmpty())
{
dicQuery.Add("pbk", Utils.UrlEncode(item.PublicKey));
}
if (item.ShortId.IsNotEmpty())
{
dicQuery.Add("sid", Utils.UrlEncode(item.ShortId));
}
if (item.SpiderX.IsNotEmpty())
{
dicQuery.Add("spx", Utils.UrlEncode(item.SpiderX));
}
if (item.AllowInsecure.Equals("true"))
{
dicQuery.Add("allowInsecure", "1");
}
if (item.StreamSecurity.IsNotEmpty())
{
dicQuery.Add("security", item.StreamSecurity);
}
else
{
if (securityDef != null)
dicQuery.Add("type", item.Network.IsNotEmpty() ? item.Network : nameof(ETransport.tcp));
switch (item.Network)
{
case nameof(ETransport.tcp):
dicQuery.Add("headerType", item.HeaderType.IsNotEmpty() ? item.HeaderType : Global.None);
if (item.RequestHost.IsNotEmpty())
{
dicQuery.Add("security", securityDef);
dicQuery.Add("host", Utils.UrlEncode(item.RequestHost));
}
}
if (item.Sni.IsNotEmpty())
{
dicQuery.Add("sni", item.Sni);
}
if (item.Alpn.IsNotEmpty())
{
dicQuery.Add("alpn", Utils.UrlEncode(item.Alpn));
}
if (item.Fingerprint.IsNotEmpty())
{
dicQuery.Add("fp", Utils.UrlEncode(item.Fingerprint));
}
if (item.PublicKey.IsNotEmpty())
{
dicQuery.Add("pbk", Utils.UrlEncode(item.PublicKey));
}
if (item.ShortId.IsNotEmpty())
{
dicQuery.Add("sid", Utils.UrlEncode(item.ShortId));
}
if (item.SpiderX.IsNotEmpty())
{
dicQuery.Add("spx", Utils.UrlEncode(item.SpiderX));
}
if (item.AllowInsecure.Equals("true"))
{
dicQuery.Add("allowInsecure", "1");
}
break;
dicQuery.Add("type", item.Network.IsNotEmpty() ? item.Network : nameof(ETransport.tcp));
case nameof(ETransport.kcp):
dicQuery.Add("headerType", item.HeaderType.IsNotEmpty() ? item.HeaderType : Global.None);
if (item.Path.IsNotEmpty())
{
dicQuery.Add("seed", Utils.UrlEncode(item.Path));
}
break;
switch (item.Network)
{
case nameof(ETransport.tcp):
dicQuery.Add("headerType", item.HeaderType.IsNotEmpty() ? item.HeaderType : Global.None);
if (item.RequestHost.IsNotEmpty())
{
dicQuery.Add("host", Utils.UrlEncode(item.RequestHost));
}
break;
case nameof(ETransport.ws):
case nameof(ETransport.httpupgrade):
if (item.RequestHost.IsNotEmpty())
{
dicQuery.Add("host", Utils.UrlEncode(item.RequestHost));
}
if (item.Path.IsNotEmpty())
{
dicQuery.Add("path", Utils.UrlEncode(item.Path));
}
break;
case nameof(ETransport.kcp):
dicQuery.Add("headerType", item.HeaderType.IsNotEmpty() ? item.HeaderType : Global.None);
if (item.Path.IsNotEmpty())
{
dicQuery.Add("seed", Utils.UrlEncode(item.Path));
}
break;
case nameof(ETransport.xhttp):
if (item.RequestHost.IsNotEmpty())
{
dicQuery.Add("host", Utils.UrlEncode(item.RequestHost));
}
if (item.Path.IsNotEmpty())
{
dicQuery.Add("path", Utils.UrlEncode(item.Path));
}
if (item.HeaderType.IsNotEmpty() && Global.XhttpMode.Contains(item.HeaderType))
{
dicQuery.Add("mode", Utils.UrlEncode(item.HeaderType));
}
if (item.Extra.IsNotEmpty())
{
dicQuery.Add("extra", Utils.UrlEncode(item.Extra));
}
break;
case nameof(ETransport.ws):
case nameof(ETransport.httpupgrade):
if (item.RequestHost.IsNotEmpty())
{
dicQuery.Add("host", Utils.UrlEncode(item.RequestHost));
}
if (item.Path.IsNotEmpty())
{
dicQuery.Add("path", Utils.UrlEncode(item.Path));
}
break;
case nameof(ETransport.http):
case nameof(ETransport.h2):
dicQuery["type"] = nameof(ETransport.http);
if (item.RequestHost.IsNotEmpty())
{
dicQuery.Add("host", Utils.UrlEncode(item.RequestHost));
}
if (item.Path.IsNotEmpty())
{
dicQuery.Add("path", Utils.UrlEncode(item.Path));
}
break;
case nameof(ETransport.xhttp):
if (item.RequestHost.IsNotEmpty())
{
dicQuery.Add("host", Utils.UrlEncode(item.RequestHost));
}
if (item.Path.IsNotEmpty())
{
dicQuery.Add("path", Utils.UrlEncode(item.Path));
}
if (item.HeaderType.IsNotEmpty() && Global.XhttpMode.Contains(item.HeaderType))
case nameof(ETransport.quic):
dicQuery.Add("headerType", item.HeaderType.IsNotEmpty() ? item.HeaderType : Global.None);
dicQuery.Add("quicSecurity", Utils.UrlEncode(item.RequestHost));
dicQuery.Add("key", Utils.UrlEncode(item.Path));
break;
case nameof(ETransport.grpc):
if (item.Path.IsNotEmpty())
{
dicQuery.Add("authority", Utils.UrlEncode(item.RequestHost));
dicQuery.Add("serviceName", Utils.UrlEncode(item.Path));
if (item.HeaderType is Global.GrpcGunMode or Global.GrpcMultiMode)
{
dicQuery.Add("mode", Utils.UrlEncode(item.HeaderType));
}
if (item.Extra.IsNotEmpty())
{
dicQuery.Add("extra", Utils.UrlEncode(item.Extra));
}
break;
case nameof(ETransport.http):
case nameof(ETransport.h2):
dicQuery["type"] = nameof(ETransport.http);
if (item.RequestHost.IsNotEmpty())
{
dicQuery.Add("host", Utils.UrlEncode(item.RequestHost));
}
if (item.Path.IsNotEmpty())
{
dicQuery.Add("path", Utils.UrlEncode(item.Path));
}
break;
case nameof(ETransport.quic):
dicQuery.Add("headerType", item.HeaderType.IsNotEmpty() ? item.HeaderType : Global.None);
dicQuery.Add("quicSecurity", Utils.UrlEncode(item.RequestHost));
dicQuery.Add("key", Utils.UrlEncode(item.Path));
break;
case nameof(ETransport.grpc):
if (item.Path.IsNotEmpty())
{
dicQuery.Add("authority", Utils.UrlEncode(item.RequestHost));
dicQuery.Add("serviceName", Utils.UrlEncode(item.Path));
if (item.HeaderType is Global.GrpcGunMode or Global.GrpcMultiMode)
{
dicQuery.Add("mode", Utils.UrlEncode(item.HeaderType));
}
}
break;
}
return 0;
}
protected static int ResolveStdTransport(NameValueCollection query, ref ProfileItem item)
{
item.Flow = query["flow"] ?? "";
item.StreamSecurity = query["security"] ?? "";
item.Sni = query["sni"] ?? "";
item.Alpn = Utils.UrlDecode(query["alpn"] ?? "");
item.Fingerprint = Utils.UrlDecode(query["fp"] ?? "");
item.PublicKey = Utils.UrlDecode(query["pbk"] ?? "");
item.ShortId = Utils.UrlDecode(query["sid"] ?? "");
item.SpiderX = Utils.UrlDecode(query["spx"] ?? "");
item.AllowInsecure = (query["allowInsecure"] ?? "") == "1" ? "true" : "";
item.Network = query["type"] ?? nameof(ETransport.tcp);
switch (item.Network)
{
case nameof(ETransport.tcp):
item.HeaderType = query["headerType"] ?? Global.None;
item.RequestHost = Utils.UrlDecode(query["host"] ?? "");
break;
case nameof(ETransport.kcp):
item.HeaderType = query["headerType"] ?? Global.None;
item.Path = Utils.UrlDecode(query["seed"] ?? "");
break;
case nameof(ETransport.ws):
case nameof(ETransport.httpupgrade):
item.RequestHost = Utils.UrlDecode(query["host"] ?? "");
item.Path = Utils.UrlDecode(query["path"] ?? "/");
break;
case nameof(ETransport.xhttp):
item.RequestHost = Utils.UrlDecode(query["host"] ?? "");
item.Path = Utils.UrlDecode(query["path"] ?? "/");
item.HeaderType = Utils.UrlDecode(query["mode"] ?? "");
item.Extra = Utils.UrlDecode(query["extra"] ?? "");
break;
case nameof(ETransport.http):
case nameof(ETransport.h2):
item.Network = nameof(ETransport.h2);
item.RequestHost = Utils.UrlDecode(query["host"] ?? "");
item.Path = Utils.UrlDecode(query["path"] ?? "/");
break;
case nameof(ETransport.quic):
item.HeaderType = query["headerType"] ?? Global.None;
item.RequestHost = query["quicSecurity"] ?? Global.None;
item.Path = Utils.UrlDecode(query["key"] ?? "");
break;
case nameof(ETransport.grpc):
item.RequestHost = Utils.UrlDecode(query["authority"] ?? "");
item.Path = Utils.UrlDecode(query["serviceName"] ?? "");
item.HeaderType = Utils.UrlDecode(query["mode"] ?? Global.GrpcGunMode);
break;
default:
break;
}
return 0;
}
protected static bool Contains(string str, params string[] s)
{
foreach (var item in s)
{
if (str.Contains(item, StringComparison.OrdinalIgnoreCase))
{
return true;
}
break;
}
return 0;
}
protected static int ResolveStdTransport(NameValueCollection query, ref ProfileItem item)
{
item.Flow = query["flow"] ?? "";
item.StreamSecurity = query["security"] ?? "";
item.Sni = query["sni"] ?? "";
item.Alpn = Utils.UrlDecode(query["alpn"] ?? "");
item.Fingerprint = Utils.UrlDecode(query["fp"] ?? "");
item.PublicKey = Utils.UrlDecode(query["pbk"] ?? "");
item.ShortId = Utils.UrlDecode(query["sid"] ?? "");
item.SpiderX = Utils.UrlDecode(query["spx"] ?? "");
item.AllowInsecure = (query["allowInsecure"] ?? "") == "1" ? "true" : "";
item.Network = query["type"] ?? nameof(ETransport.tcp);
switch (item.Network)
{
case nameof(ETransport.tcp):
item.HeaderType = query["headerType"] ?? Global.None;
item.RequestHost = Utils.UrlDecode(query["host"] ?? "");
break;
case nameof(ETransport.kcp):
item.HeaderType = query["headerType"] ?? Global.None;
item.Path = Utils.UrlDecode(query["seed"] ?? "");
break;
case nameof(ETransport.ws):
case nameof(ETransport.httpupgrade):
item.RequestHost = Utils.UrlDecode(query["host"] ?? "");
item.Path = Utils.UrlDecode(query["path"] ?? "/");
break;
case nameof(ETransport.xhttp):
item.RequestHost = Utils.UrlDecode(query["host"] ?? "");
item.Path = Utils.UrlDecode(query["path"] ?? "/");
item.HeaderType = Utils.UrlDecode(query["mode"] ?? "");
item.Extra = Utils.UrlDecode(query["extra"] ?? "");
break;
case nameof(ETransport.http):
case nameof(ETransport.h2):
item.Network = nameof(ETransport.h2);
item.RequestHost = Utils.UrlDecode(query["host"] ?? "");
item.Path = Utils.UrlDecode(query["path"] ?? "/");
break;
case nameof(ETransport.quic):
item.HeaderType = query["headerType"] ?? Global.None;
item.RequestHost = query["quicSecurity"] ?? Global.None;
item.Path = Utils.UrlDecode(query["key"] ?? "");
break;
case nameof(ETransport.grpc):
item.RequestHost = Utils.UrlDecode(query["authority"] ?? "");
item.Path = Utils.UrlDecode(query["serviceName"] ?? "");
item.HeaderType = Utils.UrlDecode(query["mode"] ?? Global.GrpcGunMode);
break;
default:
break;
}
return 0;
}
protected static bool Contains(string str, params string[] s)
{
foreach (var item in s)
{
if (str.Contains(item, StringComparison.OrdinalIgnoreCase))
{
return true;
}
return false;
}
return false;
}
protected static string WriteAllText(string strData, string ext = "json")
{
var fileName = Utils.GetTempPath($"{Utils.GetGuid(false)}.{ext}");
File.WriteAllText(fileName, strData);
return fileName;
}
protected static string WriteAllText(string strData, string ext = "json")
{
var fileName = Utils.GetTempPath($"{Utils.GetGuid(false)}.{ext}");
File.WriteAllText(fileName, strData);
return fileName;
}
protected static string ToUri(EConfigType eConfigType, string address, object port, string userInfo, Dictionary<string, string>? dicQuery, string? remark)
{
var query = dicQuery != null
? ("?" + string.Join("&", dicQuery.Select(x => x.Key + "=" + x.Value).ToArray()))
: string.Empty;
protected static string ToUri(EConfigType eConfigType, string address, object port, string userInfo, Dictionary<string, string>? dicQuery, string? remark)
{
var query = dicQuery != null
? ("?" + string.Join("&", dicQuery.Select(x => x.Key + "=" + x.Value).ToArray()))
: string.Empty;
var url = $"{Utils.UrlEncode(userInfo)}@{GetIpv6(address)}:{port}";
return $"{Global.ProtocolShares[eConfigType]}{url}{query}{remark}";
}
var url = $"{Utils.UrlEncode(userInfo)}@{GetIpv6(address)}:{port}";
return $"{Global.ProtocolShares[eConfigType]}{url}{query}{remark}";
}
}
+16 -17
View File
@@ -1,23 +1,22 @@
namespace ServiceLib.Handler.Fmt
namespace ServiceLib.Handler.Fmt;
public class ClashFmt : BaseFmt
{
public class ClashFmt : BaseFmt
public static ProfileItem? ResolveFull(string strData, string? subRemarks)
{
public static ProfileItem? ResolveFull(string strData, string? subRemarks)
if (Contains(strData, "port", "socks-port", "proxies"))
{
if (Contains(strData, "port", "socks-port", "proxies"))
var fileName = WriteAllText(strData, "yaml");
var profileItem = new ProfileItem
{
var fileName = WriteAllText(strData, "yaml");
var profileItem = new ProfileItem
{
CoreType = ECoreType.mihomo,
Address = fileName,
Remarks = subRemarks ?? "clash_custom"
};
return profileItem;
}
return null;
CoreType = ECoreType.mihomo,
Address = fileName,
Remarks = subRemarks ?? "clash_custom"
};
return profileItem;
}
return null;
}
}
}
+76 -77
View File
@@ -1,92 +1,91 @@
namespace ServiceLib.Handler.Fmt
namespace ServiceLib.Handler.Fmt;
public class FmtHandler
{
public class FmtHandler
private static readonly string _tag = "FmtHandler";
public static string? GetShareUri(ProfileItem item)
{
private static readonly string _tag = "FmtHandler";
public static string? GetShareUri(ProfileItem item)
try
{
try
var url = item.ConfigType switch
{
var url = item.ConfigType switch
{
EConfigType.VMess => VmessFmt.ToUri(item),
EConfigType.Shadowsocks => ShadowsocksFmt.ToUri(item),
EConfigType.SOCKS => SocksFmt.ToUri(item),
EConfigType.Trojan => TrojanFmt.ToUri(item),
EConfigType.VLESS => VLESSFmt.ToUri(item),
EConfigType.Hysteria2 => Hysteria2Fmt.ToUri(item),
EConfigType.TUIC => TuicFmt.ToUri(item),
EConfigType.WireGuard => WireguardFmt.ToUri(item),
_ => null,
};
EConfigType.VMess => VmessFmt.ToUri(item),
EConfigType.Shadowsocks => ShadowsocksFmt.ToUri(item),
EConfigType.SOCKS => SocksFmt.ToUri(item),
EConfigType.Trojan => TrojanFmt.ToUri(item),
EConfigType.VLESS => VLESSFmt.ToUri(item),
EConfigType.Hysteria2 => Hysteria2Fmt.ToUri(item),
EConfigType.TUIC => TuicFmt.ToUri(item),
EConfigType.WireGuard => WireguardFmt.ToUri(item),
_ => null,
};
return url;
}
catch (Exception ex)
{
Logging.SaveLog(_tag, ex);
return "";
}
return url;
}
public static ProfileItem? ResolveConfig(string config, out string msg)
catch (Exception ex)
{
msg = ResUI.ConfigurationFormatIncorrect;
Logging.SaveLog(_tag, ex);
return "";
}
}
try
public static ProfileItem? ResolveConfig(string config, out string msg)
{
msg = ResUI.ConfigurationFormatIncorrect;
try
{
string str = config.TrimEx();
if (str.IsNullOrEmpty())
{
string str = config.TrimEx();
if (str.IsNullOrEmpty())
{
msg = ResUI.FailedReadConfiguration;
return null;
}
if (str.StartsWith(Global.ProtocolShares[EConfigType.VMess]))
{
return VmessFmt.Resolve(str, out msg);
}
else if (str.StartsWith(Global.ProtocolShares[EConfigType.Shadowsocks]))
{
return ShadowsocksFmt.Resolve(str, out msg);
}
else if (str.StartsWith(Global.ProtocolShares[EConfigType.SOCKS]))
{
return SocksFmt.Resolve(str, out msg);
}
else if (str.StartsWith(Global.ProtocolShares[EConfigType.Trojan]))
{
return TrojanFmt.Resolve(str, out msg);
}
else if (str.StartsWith(Global.ProtocolShares[EConfigType.VLESS]))
{
return VLESSFmt.Resolve(str, out msg);
}
else if (str.StartsWith(Global.ProtocolShares[EConfigType.Hysteria2]) || str.StartsWith(Global.Hysteria2ProtocolShare))
{
return Hysteria2Fmt.Resolve(str, out msg);
}
else if (str.StartsWith(Global.ProtocolShares[EConfigType.TUIC]))
{
return TuicFmt.Resolve(str, out msg);
}
else if (str.StartsWith(Global.ProtocolShares[EConfigType.WireGuard]))
{
return WireguardFmt.Resolve(str, out msg);
}
else
{
msg = ResUI.NonvmessOrssProtocol;
return null;
}
msg = ResUI.FailedReadConfiguration;
return null;
}
catch (Exception ex)
if (str.StartsWith(Global.ProtocolShares[EConfigType.VMess]))
{
Logging.SaveLog(_tag, ex);
msg = ResUI.Incorrectconfiguration;
return VmessFmt.Resolve(str, out msg);
}
else if (str.StartsWith(Global.ProtocolShares[EConfigType.Shadowsocks]))
{
return ShadowsocksFmt.Resolve(str, out msg);
}
else if (str.StartsWith(Global.ProtocolShares[EConfigType.SOCKS]))
{
return SocksFmt.Resolve(str, out msg);
}
else if (str.StartsWith(Global.ProtocolShares[EConfigType.Trojan]))
{
return TrojanFmt.Resolve(str, out msg);
}
else if (str.StartsWith(Global.ProtocolShares[EConfigType.VLESS]))
{
return VLESSFmt.Resolve(str, out msg);
}
else if (str.StartsWith(Global.ProtocolShares[EConfigType.Hysteria2]) || str.StartsWith(Global.Hysteria2ProtocolShare))
{
return Hysteria2Fmt.Resolve(str, out msg);
}
else if (str.StartsWith(Global.ProtocolShares[EConfigType.TUIC]))
{
return TuicFmt.Resolve(str, out msg);
}
else if (str.StartsWith(Global.ProtocolShares[EConfigType.WireGuard]))
{
return WireguardFmt.Resolve(str, out msg);
}
else
{
msg = ResUI.NonvmessOrssProtocol;
return null;
}
}
catch (Exception ex)
{
Logging.SaveLog(_tag, ex);
msg = ResUI.Incorrectconfiguration;
return null;
}
}
}
}
+87 -88
View File
@@ -1,102 +1,101 @@
namespace ServiceLib.Handler.Fmt
namespace ServiceLib.Handler.Fmt;
public class Hysteria2Fmt : BaseFmt
{
public class Hysteria2Fmt : BaseFmt
public static ProfileItem? Resolve(string str, out string msg)
{
public static ProfileItem? Resolve(string str, out string msg)
msg = ResUI.ConfigurationFormatIncorrect;
ProfileItem item = new()
{
msg = ResUI.ConfigurationFormatIncorrect;
ProfileItem item = new()
ConfigType = EConfigType.Hysteria2
};
var url = Utils.TryUri(str);
if (url == null)
return null;
item.Address = url.IdnHost;
item.Port = url.Port;
item.Remarks = url.GetComponents(UriComponents.Fragment, UriFormat.Unescaped);
item.Id = Utils.UrlDecode(url.UserInfo);
var query = Utils.ParseQueryString(url.Query);
ResolveStdTransport(query, ref item);
item.Path = Utils.UrlDecode(query["obfs-password"] ?? "");
item.AllowInsecure = (query["insecure"] ?? "") == "1" ? "true" : "false";
item.Ports = Utils.UrlDecode(query["mport"] ?? "").Replace('-', ':');
return item;
}
public static string? ToUri(ProfileItem? item)
{
if (item == null)
return null;
string url = string.Empty;
string remark = string.Empty;
if (item.Remarks.IsNotEmpty())
{
remark = "#" + Utils.UrlEncode(item.Remarks);
}
var dicQuery = new Dictionary<string, string>();
if (item.Sni.IsNotEmpty())
{
dicQuery.Add("sni", item.Sni);
}
if (item.Alpn.IsNotEmpty())
{
dicQuery.Add("alpn", Utils.UrlEncode(item.Alpn));
}
if (item.Path.IsNotEmpty())
{
dicQuery.Add("obfs", "salamander");
dicQuery.Add("obfs-password", Utils.UrlEncode(item.Path));
}
dicQuery.Add("insecure", item.AllowInsecure.ToLower() == "true" ? "1" : "0");
if (item.Ports.IsNotEmpty())
{
dicQuery.Add("mport", Utils.UrlEncode(item.Ports.Replace(':', '-')));
}
return ToUri(EConfigType.Hysteria2, item.Address, item.Port, item.Id, dicQuery, remark);
}
public static ProfileItem? ResolveFull(string strData, string? subRemarks)
{
if (Contains(strData, "server", "up", "down", "listen", "<html>", "<body>"))
{
var fileName = WriteAllText(strData);
var profileItem = new ProfileItem
{
ConfigType = EConfigType.Hysteria2
CoreType = ECoreType.hysteria,
Address = fileName,
Remarks = subRemarks ?? "hysteria_custom"
};
var url = Utils.TryUri(str);
if (url == null)
return null;
item.Address = url.IdnHost;
item.Port = url.Port;
item.Remarks = url.GetComponents(UriComponents.Fragment, UriFormat.Unescaped);
item.Id = Utils.UrlDecode(url.UserInfo);
var query = Utils.ParseQueryString(url.Query);
ResolveStdTransport(query, ref item);
item.Path = Utils.UrlDecode(query["obfs-password"] ?? "");
item.AllowInsecure = (query["insecure"] ?? "") == "1" ? "true" : "false";
item.Ports = Utils.UrlDecode(query["mport"] ?? "").Replace('-', ':');
return item;
return profileItem;
}
public static string? ToUri(ProfileItem? item)
return null;
}
public static ProfileItem? ResolveFull2(string strData, string? subRemarks)
{
if (Contains(strData, "server", "auth", "up", "down", "listen"))
{
if (item == null)
return null;
string url = string.Empty;
var fileName = WriteAllText(strData);
string remark = string.Empty;
if (item.Remarks.IsNotEmpty())
var profileItem = new ProfileItem
{
remark = "#" + Utils.UrlEncode(item.Remarks);
}
var dicQuery = new Dictionary<string, string>();
if (item.Sni.IsNotEmpty())
{
dicQuery.Add("sni", item.Sni);
}
if (item.Alpn.IsNotEmpty())
{
dicQuery.Add("alpn", Utils.UrlEncode(item.Alpn));
}
if (item.Path.IsNotEmpty())
{
dicQuery.Add("obfs", "salamander");
dicQuery.Add("obfs-password", Utils.UrlEncode(item.Path));
}
dicQuery.Add("insecure", item.AllowInsecure.ToLower() == "true" ? "1" : "0");
if (item.Ports.IsNotEmpty())
{
dicQuery.Add("mport", Utils.UrlEncode(item.Ports.Replace(':', '-')));
}
return ToUri(EConfigType.Hysteria2, item.Address, item.Port, item.Id, dicQuery, remark);
CoreType = ECoreType.hysteria2,
Address = fileName,
Remarks = subRemarks ?? "hysteria2_custom"
};
return profileItem;
}
public static ProfileItem? ResolveFull(string strData, string? subRemarks)
{
if (Contains(strData, "server", "up", "down", "listen", "<html>", "<body>"))
{
var fileName = WriteAllText(strData);
var profileItem = new ProfileItem
{
CoreType = ECoreType.hysteria,
Address = fileName,
Remarks = subRemarks ?? "hysteria_custom"
};
return profileItem;
}
return null;
}
public static ProfileItem? ResolveFull2(string strData, string? subRemarks)
{
if (Contains(strData, "server", "auth", "up", "down", "listen"))
{
var fileName = WriteAllText(strData);
var profileItem = new ProfileItem
{
CoreType = ECoreType.hysteria2,
Address = fileName,
Remarks = subRemarks ?? "hysteria2_custom"
};
return profileItem;
}
return null;
}
return null;
}
}
+16 -17
View File
@@ -1,23 +1,22 @@
namespace ServiceLib.Handler.Fmt
namespace ServiceLib.Handler.Fmt;
public class NaiveproxyFmt : BaseFmt
{
public class NaiveproxyFmt : BaseFmt
public static ProfileItem? ResolveFull(string strData, string? subRemarks)
{
public static ProfileItem? ResolveFull(string strData, string? subRemarks)
if (Contains(strData, "listen", "proxy", "<html>", "<body>"))
{
if (Contains(strData, "listen", "proxy", "<html>", "<body>"))
var fileName = WriteAllText(strData);
var profileItem = new ProfileItem
{
var fileName = WriteAllText(strData);
var profileItem = new ProfileItem
{
CoreType = ECoreType.naiveproxy,
Address = fileName,
Remarks = subRemarks ?? "naiveproxy_custom"
};
return profileItem;
}
return null;
CoreType = ECoreType.naiveproxy,
Address = fileName,
Remarks = subRemarks ?? "naiveproxy_custom"
};
return profileItem;
}
return null;
}
}
}
+147 -148
View File
@@ -1,180 +1,179 @@
using System.Text.RegularExpressions;
namespace ServiceLib.Handler.Fmt
namespace ServiceLib.Handler.Fmt;
public class ShadowsocksFmt : BaseFmt
{
public class ShadowsocksFmt : BaseFmt
public static ProfileItem? Resolve(string str, out string msg)
{
public static ProfileItem? Resolve(string str, out string msg)
msg = ResUI.ConfigurationFormatIncorrect;
ProfileItem? item;
item = ResolveSSLegacy(str) ?? ResolveSip002(str);
if (item == null)
{
msg = ResUI.ConfigurationFormatIncorrect;
ProfileItem? item;
item = ResolveSSLegacy(str) ?? ResolveSip002(str);
if (item == null)
{
return null;
}
if (item.Address.Length == 0 || item.Port == 0 || item.Security.Length == 0 || item.Id.Length == 0)
{
return null;
}
item.ConfigType = EConfigType.Shadowsocks;
return item;
return null;
}
if (item.Address.Length == 0 || item.Port == 0 || item.Security.Length == 0 || item.Id.Length == 0)
{
return null;
}
public static string? ToUri(ProfileItem? item)
item.ConfigType = EConfigType.Shadowsocks;
return item;
}
public static string? ToUri(ProfileItem? item)
{
if (item == null)
{
if (item == null)
{
return null;
}
var remark = string.Empty;
if (item.Remarks.IsNotEmpty())
{
remark = "#" + Utils.UrlEncode(item.Remarks);
}
//url = string.Format("{0}:{1}@{2}:{3}",
// item.security,
// item.id,
// item.address,
// item.port);
//url = Utile.Base64Encode(url);
//new Sip002
var pw = Utils.Base64Encode($"{item.Security}:{item.Id}");
return ToUri(EConfigType.Shadowsocks, item.Address, item.Port, pw, null, remark);
return null;
}
var remark = string.Empty;
if (item.Remarks.IsNotEmpty())
{
remark = "#" + Utils.UrlEncode(item.Remarks);
}
//url = string.Format("{0}:{1}@{2}:{3}",
// item.security,
// item.id,
// item.address,
// item.port);
//url = Utile.Base64Encode(url);
//new Sip002
var pw = Utils.Base64Encode($"{item.Security}:{item.Id}");
return ToUri(EConfigType.Shadowsocks, item.Address, item.Port, pw, null, remark);
}
private static readonly Regex UrlFinder = new(@"ss://(?<base64>[A-Za-z0-9+-/=_]+)(?:#(?<tag>\S+))?", RegexOptions.IgnoreCase | RegexOptions.Compiled);
private static readonly Regex DetailsParser = new(@"^((?<method>.+?):(?<password>.*)@(?<hostname>.+?):(?<port>\d+?))$", RegexOptions.IgnoreCase | RegexOptions.Compiled);
private static ProfileItem? ResolveSSLegacy(string result)
{
var match = UrlFinder.Match(result);
if (!match.Success)
{
return null;
}
private static readonly Regex UrlFinder = new(@"ss://(?<base64>[A-Za-z0-9+-/=_]+)(?:#(?<tag>\S+))?", RegexOptions.IgnoreCase | RegexOptions.Compiled);
private static readonly Regex DetailsParser = new(@"^((?<method>.+?):(?<password>.*)@(?<hostname>.+?):(?<port>\d+?))$", RegexOptions.IgnoreCase | RegexOptions.Compiled);
private static ProfileItem? ResolveSSLegacy(string result)
ProfileItem item = new();
var base64 = match.Groups["base64"].Value.TrimEnd('/');
var tag = match.Groups["tag"].Value;
if (tag.IsNotEmpty())
{
var match = UrlFinder.Match(result);
if (!match.Success)
{
return null;
}
item.Remarks = Utils.UrlDecode(tag);
}
Match details;
try
{
details = DetailsParser.Match(Utils.Base64Decode(base64));
}
catch (FormatException)
{
return null;
}
if (!details.Success)
{
return null;
}
item.Security = details.Groups["method"].Value;
item.Id = details.Groups["password"].Value;
item.Address = details.Groups["hostname"].Value;
item.Port = details.Groups["port"].Value.ToInt();
return item;
}
ProfileItem item = new();
var base64 = match.Groups["base64"].Value.TrimEnd('/');
var tag = match.Groups["tag"].Value;
if (tag.IsNotEmpty())
{
item.Remarks = Utils.UrlDecode(tag);
}
Match details;
try
{
details = DetailsParser.Match(Utils.Base64Decode(base64));
}
catch (FormatException)
{
return null;
}
if (!details.Success)
{
return null;
}
item.Security = details.Groups["method"].Value;
item.Id = details.Groups["password"].Value;
item.Address = details.Groups["hostname"].Value;
item.Port = details.Groups["port"].Value.ToInt();
return item;
private static ProfileItem? ResolveSip002(string result)
{
var parsedUrl = Utils.TryUri(result);
if (parsedUrl == null)
{
return null;
}
private static ProfileItem? ResolveSip002(string result)
ProfileItem item = new()
{
var parsedUrl = Utils.TryUri(result);
if (parsedUrl == null)
Remarks = parsedUrl.GetComponents(UriComponents.Fragment, UriFormat.Unescaped),
Address = parsedUrl.IdnHost,
Port = parsedUrl.Port,
};
var rawUserInfo = Utils.UrlDecode(parsedUrl.UserInfo);
//2022-blake3
if (rawUserInfo.Contains(':'))
{
var userInfoParts = rawUserInfo.Split(new[] { ':' }, 2);
if (userInfoParts.Length != 2)
{
return null;
}
item.Security = userInfoParts.First();
item.Id = Utils.UrlDecode(userInfoParts.Last());
}
else
{
// parse base64 UserInfo
var userInfo = Utils.Base64Decode(rawUserInfo);
var userInfoParts = userInfo.Split(new[] { ':' }, 2);
if (userInfoParts.Length != 2)
{
return null;
}
item.Security = userInfoParts.First();
item.Id = userInfoParts.Last();
}
ProfileItem item = new()
var queryParameters = Utils.ParseQueryString(parsedUrl.Query);
if (queryParameters["plugin"] != null)
{
//obfs-host exists
var obfsHost = queryParameters["plugin"]?.Split(';').FirstOrDefault(t => t.Contains("obfs-host"));
if (queryParameters["plugin"].Contains("obfs=http") && obfsHost.IsNotEmpty())
{
Remarks = parsedUrl.GetComponents(UriComponents.Fragment, UriFormat.Unescaped),
Address = parsedUrl.IdnHost,
Port = parsedUrl.Port,
};
var rawUserInfo = Utils.UrlDecode(parsedUrl.UserInfo);
//2022-blake3
if (rawUserInfo.Contains(':'))
{
var userInfoParts = rawUserInfo.Split(new[] { ':' }, 2);
if (userInfoParts.Length != 2)
{
return null;
}
item.Security = userInfoParts.First();
item.Id = Utils.UrlDecode(userInfoParts.Last());
obfsHost = obfsHost?.Replace("obfs-host=", "");
item.Network = Global.DefaultNetwork;
item.HeaderType = Global.TcpHeaderHttp;
item.RequestHost = obfsHost ?? "";
}
else
{
// parse base64 UserInfo
var userInfo = Utils.Base64Decode(rawUserInfo);
var userInfoParts = userInfo.Split(new[] { ':' }, 2);
if (userInfoParts.Length != 2)
{
return null;
}
item.Security = userInfoParts.First();
item.Id = userInfoParts.Last();
return null;
}
var queryParameters = Utils.ParseQueryString(parsedUrl.Query);
if (queryParameters["plugin"] != null)
{
//obfs-host exists
var obfsHost = queryParameters["plugin"]?.Split(';').FirstOrDefault(t => t.Contains("obfs-host"));
if (queryParameters["plugin"].Contains("obfs=http") && obfsHost.IsNotEmpty())
{
obfsHost = obfsHost?.Replace("obfs-host=", "");
item.Network = Global.DefaultNetwork;
item.HeaderType = Global.TcpHeaderHttp;
item.RequestHost = obfsHost ?? "";
}
else
{
return null;
}
}
return item;
}
public static List<ProfileItem>? ResolveSip008(string result)
return item;
}
public static List<ProfileItem>? ResolveSip008(string result)
{
//SsSIP008
var lstSsServer = JsonUtils.Deserialize<List<SsServer>>(result);
if (lstSsServer?.Count <= 0)
{
//SsSIP008
var lstSsServer = JsonUtils.Deserialize<List<SsServer>>(result);
if (lstSsServer?.Count <= 0)
var ssSIP008 = JsonUtils.Deserialize<SsSIP008>(result);
if (ssSIP008?.servers?.Count > 0)
{
var ssSIP008 = JsonUtils.Deserialize<SsSIP008>(result);
if (ssSIP008?.servers?.Count > 0)
{
lstSsServer = ssSIP008.servers;
}
lstSsServer = ssSIP008.servers;
}
if (lstSsServer?.Count > 0)
{
List<ProfileItem> lst = [];
foreach (var it in lstSsServer)
{
var ssItem = new ProfileItem()
{
Remarks = it.remarks,
Security = it.method,
Id = it.password,
Address = it.server,
Port = it.server_port.ToInt()
};
lst.Add(ssItem);
}
return lst;
}
return null;
}
if (lstSsServer?.Count > 0)
{
List<ProfileItem> lst = [];
foreach (var it in lstSsServer)
{
var ssItem = new ProfileItem()
{
Remarks = it.remarks,
Security = it.method,
Id = it.password,
Address = it.server,
Port = it.server_port.ToInt()
};
lst.Add(ssItem);
}
return lst;
}
return null;
}
}
+36 -37
View File
@@ -1,48 +1,47 @@
namespace ServiceLib.Handler.Fmt
namespace ServiceLib.Handler.Fmt;
public class SingboxFmt : BaseFmt
{
public class SingboxFmt : BaseFmt
public static List<ProfileItem>? ResolveFullArray(string strData, string? subRemarks)
{
public static List<ProfileItem>? ResolveFullArray(string strData, string? subRemarks)
var configObjects = JsonUtils.Deserialize<object[]>(strData);
if (configObjects is not { Length: > 0 })
{
var configObjects = JsonUtils.Deserialize<object[]>(strData);
if (configObjects is not { Length: > 0 })
{
return null;
}
List<ProfileItem> lstResult = [];
foreach (var configObject in configObjects)
{
var objectString = JsonUtils.Serialize(configObject);
var profileIt = ResolveFull(objectString, subRemarks);
if (profileIt != null)
{
lstResult.Add(profileIt);
}
}
return lstResult;
return null;
}
public static ProfileItem? ResolveFull(string strData, string? subRemarks)
List<ProfileItem> lstResult = [];
foreach (var configObject in configObjects)
{
var config = JsonUtils.ParseJson(strData);
if (config?["inbounds"] == null
|| config["outbounds"] == null
|| config["route"] == null
|| config["dns"] == null)
var objectString = JsonUtils.Serialize(configObject);
var profileIt = ResolveFull(objectString, subRemarks);
if (profileIt != null)
{
return null;
lstResult.Add(profileIt);
}
var fileName = WriteAllText(strData);
var profileItem = new ProfileItem
{
CoreType = ECoreType.sing_box,
Address = fileName,
Remarks = subRemarks ?? "singbox_custom"
};
return profileItem;
}
return lstResult;
}
public static ProfileItem? ResolveFull(string strData, string? subRemarks)
{
var config = JsonUtils.ParseJson(strData);
if (config?["inbounds"] == null
|| config["outbounds"] == null
|| config["route"] == null
|| config["dns"] == null)
{
return null;
}
var fileName = WriteAllText(strData);
var profileItem = new ProfileItem
{
CoreType = ECoreType.sing_box,
Address = fileName,
Remarks = subRemarks ?? "singbox_custom"
};
return profileItem;
}
}
+94 -95
View File
@@ -1,115 +1,114 @@
namespace ServiceLib.Handler.Fmt
namespace ServiceLib.Handler.Fmt;
public class SocksFmt : BaseFmt
{
public class SocksFmt : BaseFmt
public static ProfileItem? Resolve(string str, out string msg)
{
public static ProfileItem? Resolve(string str, out string msg)
msg = ResUI.ConfigurationFormatIncorrect;
var item = ResolveSocksNew(str) ?? ResolveSocks(str);
if (item == null)
{
msg = ResUI.ConfigurationFormatIncorrect;
var item = ResolveSocksNew(str) ?? ResolveSocks(str);
if (item == null)
{
return null;
}
if (item.Address.Length == 0 || item.Port == 0)
{
return null;
}
item.ConfigType = EConfigType.SOCKS;
return item;
return null;
}
if (item.Address.Length == 0 || item.Port == 0)
{
return null;
}
public static string? ToUri(ProfileItem? item)
item.ConfigType = EConfigType.SOCKS;
return item;
}
public static string? ToUri(ProfileItem? item)
{
if (item == null)
{
if (item == null)
return null;
}
var remark = string.Empty;
if (item.Remarks.IsNotEmpty())
{
remark = "#" + Utils.UrlEncode(item.Remarks);
}
//new
var pw = Utils.Base64Encode($"{item.Security}:{item.Id}");
return ToUri(EConfigType.SOCKS, item.Address, item.Port, pw, null, remark);
}
private static ProfileItem? ResolveSocks(string result)
{
ProfileItem item = new()
{
ConfigType = EConfigType.SOCKS
};
result = result[Global.ProtocolShares[EConfigType.SOCKS].Length..];
//remark
var indexRemark = result.IndexOf("#");
if (indexRemark > 0)
{
try
{
return null;
item.Remarks = Utils.UrlDecode(result.Substring(indexRemark + 1, result.Length - indexRemark - 1));
}
var remark = string.Empty;
if (item.Remarks.IsNotEmpty())
{
remark = "#" + Utils.UrlEncode(item.Remarks);
}
//new
var pw = Utils.Base64Encode($"{item.Security}:{item.Id}");
return ToUri(EConfigType.SOCKS, item.Address, item.Port, pw, null, remark);
catch { }
result = result[..indexRemark];
}
//part decode
var indexS = result.IndexOf("@");
if (indexS > 0)
{
}
else
{
result = Utils.Base64Decode(result);
}
private static ProfileItem? ResolveSocks(string result)
var arr1 = result.Split('@');
if (arr1.Length != 2)
{
ProfileItem item = new()
{
ConfigType = EConfigType.SOCKS
};
result = result[Global.ProtocolShares[EConfigType.SOCKS].Length..];
//remark
var indexRemark = result.IndexOf("#");
if (indexRemark > 0)
{
try
{
item.Remarks = Utils.UrlDecode(result.Substring(indexRemark + 1, result.Length - indexRemark - 1));
}
catch { }
result = result[..indexRemark];
}
//part decode
var indexS = result.IndexOf("@");
if (indexS > 0)
{
}
else
{
result = Utils.Base64Decode(result);
}
return null;
}
var arr21 = arr1.First().Split(':');
var indexPort = arr1.Last().LastIndexOf(":");
if (arr21.Length != 2 || indexPort < 0)
{
return null;
}
item.Address = arr1[1][..indexPort];
item.Port = arr1[1][(indexPort + 1)..].ToInt();
item.Security = arr21.First();
item.Id = arr21[1];
var arr1 = result.Split('@');
if (arr1.Length != 2)
{
return null;
}
var arr21 = arr1.First().Split(':');
var indexPort = arr1.Last().LastIndexOf(":");
if (arr21.Length != 2 || indexPort < 0)
{
return null;
}
item.Address = arr1[1][..indexPort];
item.Port = arr1[1][(indexPort + 1)..].ToInt();
item.Security = arr21.First();
item.Id = arr21[1];
return item;
}
return item;
private static ProfileItem? ResolveSocksNew(string result)
{
var parsedUrl = Utils.TryUri(result);
if (parsedUrl == null)
{
return null;
}
private static ProfileItem? ResolveSocksNew(string result)
ProfileItem item = new()
{
var parsedUrl = Utils.TryUri(result);
if (parsedUrl == null)
{
return null;
}
Remarks = parsedUrl.GetComponents(UriComponents.Fragment, UriFormat.Unescaped),
Address = parsedUrl.IdnHost,
Port = parsedUrl.Port,
};
ProfileItem item = new()
{
Remarks = parsedUrl.GetComponents(UriComponents.Fragment, UriFormat.Unescaped),
Address = parsedUrl.IdnHost,
Port = parsedUrl.Port,
};
// parse base64 UserInfo
var rawUserInfo = Utils.UrlDecode(parsedUrl.UserInfo);
var userInfo = Utils.Base64Decode(rawUserInfo);
var userInfoParts = userInfo.Split([':'], 2);
if (userInfoParts.Length == 2)
{
item.Security = userInfoParts.First();
item.Id = userInfoParts[1];
}
return item;
// parse base64 UserInfo
var rawUserInfo = Utils.UrlDecode(parsedUrl.UserInfo);
var userInfo = Utils.Base64Decode(rawUserInfo);
var userInfoParts = userInfo.Split([':'], 2);
if (userInfoParts.Length == 2)
{
item.Security = userInfoParts.First();
item.Id = userInfoParts[1];
}
return item;
}
}
+37 -38
View File
@@ -1,48 +1,47 @@
namespace ServiceLib.Handler.Fmt
namespace ServiceLib.Handler.Fmt;
public class TrojanFmt : BaseFmt
{
public class TrojanFmt : BaseFmt
public static ProfileItem? Resolve(string str, out string msg)
{
public static ProfileItem? Resolve(string str, out string msg)
msg = ResUI.ConfigurationFormatIncorrect;
ProfileItem item = new()
{
msg = ResUI.ConfigurationFormatIncorrect;
ConfigType = EConfigType.Trojan
};
ProfileItem item = new()
{
ConfigType = EConfigType.Trojan
};
var url = Utils.TryUri(str);
if (url == null)
{
return null;
}
item.Address = url.IdnHost;
item.Port = url.Port;
item.Remarks = url.GetComponents(UriComponents.Fragment, UriFormat.Unescaped);
item.Id = Utils.UrlDecode(url.UserInfo);
var query = Utils.ParseQueryString(url.Query);
_ = ResolveStdTransport(query, ref item);
return item;
var url = Utils.TryUri(str);
if (url == null)
{
return null;
}
public static string? ToUri(ProfileItem? item)
{
if (item == null)
{
return null;
}
var remark = string.Empty;
if (item.Remarks.IsNotEmpty())
{
remark = "#" + Utils.UrlEncode(item.Remarks);
}
var dicQuery = new Dictionary<string, string>();
_ = GetStdTransport(item, null, ref dicQuery);
item.Address = url.IdnHost;
item.Port = url.Port;
item.Remarks = url.GetComponents(UriComponents.Fragment, UriFormat.Unescaped);
item.Id = Utils.UrlDecode(url.UserInfo);
return ToUri(EConfigType.Trojan, item.Address, item.Port, item.Id, dicQuery, remark);
var query = Utils.ParseQueryString(url.Query);
_ = ResolveStdTransport(query, ref item);
return item;
}
public static string? ToUri(ProfileItem? item)
{
if (item == null)
{
return null;
}
var remark = string.Empty;
if (item.Remarks.IsNotEmpty())
{
remark = "#" + Utils.UrlEncode(item.Remarks);
}
var dicQuery = new Dictionary<string, string>();
_ = GetStdTransport(item, null, ref dicQuery);
return ToUri(EConfigType.Trojan, item.Address, item.Port, item.Id, dicQuery, remark);
}
}
+53 -54
View File
@@ -1,64 +1,63 @@
namespace ServiceLib.Handler.Fmt
namespace ServiceLib.Handler.Fmt;
public class TuicFmt : BaseFmt
{
public class TuicFmt : BaseFmt
public static ProfileItem? Resolve(string str, out string msg)
{
public static ProfileItem? Resolve(string str, out string msg)
msg = ResUI.ConfigurationFormatIncorrect;
ProfileItem item = new()
{
msg = ResUI.ConfigurationFormatIncorrect;
ConfigType = EConfigType.TUIC
};
ProfileItem item = new()
{
ConfigType = EConfigType.TUIC
};
var url = Utils.TryUri(str);
if (url == null)
{
return null;
}
item.Address = url.IdnHost;
item.Port = url.Port;
item.Remarks = url.GetComponents(UriComponents.Fragment, UriFormat.Unescaped);
var rawUserInfo = Utils.UrlDecode(url.UserInfo);
var userInfoParts = rawUserInfo.Split(new[] { ':' }, 2);
if (userInfoParts.Length == 2)
{
item.Id = userInfoParts.First();
item.Security = userInfoParts.Last();
}
var query = Utils.ParseQueryString(url.Query);
ResolveStdTransport(query, ref item);
item.HeaderType = query["congestion_control"] ?? "";
return item;
var url = Utils.TryUri(str);
if (url == null)
{
return null;
}
public static string? ToUri(ProfileItem? item)
item.Address = url.IdnHost;
item.Port = url.Port;
item.Remarks = url.GetComponents(UriComponents.Fragment, UriFormat.Unescaped);
var rawUserInfo = Utils.UrlDecode(url.UserInfo);
var userInfoParts = rawUserInfo.Split(new[] { ':' }, 2);
if (userInfoParts.Length == 2)
{
if (item == null)
{
return null;
}
var remark = string.Empty;
if (item.Remarks.IsNotEmpty())
{
remark = "#" + Utils.UrlEncode(item.Remarks);
}
var dicQuery = new Dictionary<string, string>();
if (item.Sni.IsNotEmpty())
{
dicQuery.Add("sni", item.Sni);
}
if (item.Alpn.IsNotEmpty())
{
dicQuery.Add("alpn", Utils.UrlEncode(item.Alpn));
}
dicQuery.Add("congestion_control", item.HeaderType);
return ToUri(EConfigType.TUIC, item.Address, item.Port, $"{item.Id}:{item.Security}", dicQuery, remark);
item.Id = userInfoParts.First();
item.Security = userInfoParts.Last();
}
var query = Utils.ParseQueryString(url.Query);
ResolveStdTransport(query, ref item);
item.HeaderType = query["congestion_control"] ?? "";
return item;
}
public static string? ToUri(ProfileItem? item)
{
if (item == null)
{
return null;
}
var remark = string.Empty;
if (item.Remarks.IsNotEmpty())
{
remark = "#" + Utils.UrlEncode(item.Remarks);
}
var dicQuery = new Dictionary<string, string>();
if (item.Sni.IsNotEmpty())
{
dicQuery.Add("sni", item.Sni);
}
if (item.Alpn.IsNotEmpty())
{
dicQuery.Add("alpn", Utils.UrlEncode(item.Alpn));
}
dicQuery.Add("congestion_control", item.HeaderType);
return ToUri(EConfigType.TUIC, item.Address, item.Port, $"{item.Id}:{item.Security}", dicQuery, remark);
}
}
+37 -38
View File
@@ -1,49 +1,48 @@
namespace ServiceLib.Handler.Fmt
namespace ServiceLib.Handler.Fmt;
public class V2rayFmt : BaseFmt
{
public class V2rayFmt : BaseFmt
public static List<ProfileItem>? ResolveFullArray(string strData, string? subRemarks)
{
public static List<ProfileItem>? ResolveFullArray(string strData, string? subRemarks)
var configObjects = JsonUtils.Deserialize<object[]>(strData);
if (configObjects is not { Length: > 0 })
{
var configObjects = JsonUtils.Deserialize<object[]>(strData);
if (configObjects is not { Length: > 0 })
{
return null;
}
List<ProfileItem> lstResult = [];
foreach (var configObject in configObjects)
{
var objectString = JsonUtils.Serialize(configObject);
var profileIt = ResolveFull(objectString, subRemarks);
if (profileIt != null)
{
lstResult.Add(profileIt);
}
}
return lstResult;
return null;
}
public static ProfileItem? ResolveFull(string strData, string? subRemarks)
List<ProfileItem> lstResult = [];
foreach (var configObject in configObjects)
{
var config = JsonUtils.ParseJson(strData);
if (config?["inbounds"] == null
|| config["outbounds"] == null
|| config["routing"] == null)
var objectString = JsonUtils.Serialize(configObject);
var profileIt = ResolveFull(objectString, subRemarks);
if (profileIt != null)
{
return null;
lstResult.Add(profileIt);
}
var fileName = WriteAllText(strData);
var profileItem = new ProfileItem
{
CoreType = ECoreType.Xray,
Address = fileName,
Remarks = config?["remarks"]?.ToString() ?? subRemarks ?? "v2ray_custom"
};
return profileItem;
}
return lstResult;
}
public static ProfileItem? ResolveFull(string strData, string? subRemarks)
{
var config = JsonUtils.ParseJson(strData);
if (config?["inbounds"] == null
|| config["outbounds"] == null
|| config["routing"] == null)
{
return null;
}
var fileName = WriteAllText(strData);
var profileItem = new ProfileItem
{
CoreType = ECoreType.Xray,
Address = fileName,
Remarks = config?["remarks"]?.ToString() ?? subRemarks ?? "v2ray_custom"
};
return profileItem;
}
}
+49 -50
View File
@@ -1,60 +1,59 @@
namespace ServiceLib.Handler.Fmt
namespace ServiceLib.Handler.Fmt;
public class VLESSFmt : BaseFmt
{
public class VLESSFmt : BaseFmt
public static ProfileItem? Resolve(string str, out string msg)
{
public static ProfileItem? Resolve(string str, out string msg)
msg = ResUI.ConfigurationFormatIncorrect;
ProfileItem item = new()
{
msg = ResUI.ConfigurationFormatIncorrect;
ConfigType = EConfigType.VLESS,
Security = Global.None
};
ProfileItem item = new()
{
ConfigType = EConfigType.VLESS,
Security = Global.None
};
var url = Utils.TryUri(str);
if (url == null)
{
return null;
}
item.Address = url.IdnHost;
item.Port = url.Port;
item.Remarks = url.GetComponents(UriComponents.Fragment, UriFormat.Unescaped);
item.Id = Utils.UrlDecode(url.UserInfo);
var query = Utils.ParseQueryString(url.Query);
item.Security = query["encryption"] ?? Global.None;
item.StreamSecurity = query["security"] ?? "";
_ = ResolveStdTransport(query, ref item);
return item;
var url = Utils.TryUri(str);
if (url == null)
{
return null;
}
public static string? ToUri(ProfileItem? item)
item.Address = url.IdnHost;
item.Port = url.Port;
item.Remarks = url.GetComponents(UriComponents.Fragment, UriFormat.Unescaped);
item.Id = Utils.UrlDecode(url.UserInfo);
var query = Utils.ParseQueryString(url.Query);
item.Security = query["encryption"] ?? Global.None;
item.StreamSecurity = query["security"] ?? "";
_ = ResolveStdTransport(query, ref item);
return item;
}
public static string? ToUri(ProfileItem? item)
{
if (item == null)
{
if (item == null)
{
return null;
}
var remark = string.Empty;
if (item.Remarks.IsNotEmpty())
{
remark = "#" + Utils.UrlEncode(item.Remarks);
}
var dicQuery = new Dictionary<string, string>();
if (item.Security.IsNotEmpty())
{
dicQuery.Add("encryption", item.Security);
}
else
{
dicQuery.Add("encryption", Global.None);
}
_ = GetStdTransport(item, Global.None, ref dicQuery);
return ToUri(EConfigType.VLESS, item.Address, item.Port, item.Id, dicQuery, remark);
return null;
}
var remark = string.Empty;
if (item.Remarks.IsNotEmpty())
{
remark = "#" + Utils.UrlEncode(item.Remarks);
}
var dicQuery = new Dictionary<string, string>();
if (item.Security.IsNotEmpty())
{
dicQuery.Add("encryption", item.Security);
}
else
{
dicQuery.Add("encryption", Global.None);
}
_ = GetStdTransport(item, Global.None, ref dicQuery);
return ToUri(EConfigType.VLESS, item.Address, item.Port, item.Id, dicQuery, remark);
}
}
+109 -110
View File
@@ -1,126 +1,125 @@
namespace ServiceLib.Handler.Fmt
namespace ServiceLib.Handler.Fmt;
public class VmessFmt : BaseFmt
{
public class VmessFmt : BaseFmt
public static ProfileItem? Resolve(string str, out string msg)
{
public static ProfileItem? Resolve(string str, out string msg)
msg = ResUI.ConfigurationFormatIncorrect;
ProfileItem? item;
if (str.IndexOf('?') > 0 && str.IndexOf('&') > 0)
{
msg = ResUI.ConfigurationFormatIncorrect;
ProfileItem? item;
if (str.IndexOf('?') > 0 && str.IndexOf('&') > 0)
{
item = ResolveStdVmess(str);
}
else
{
item = ResolveVmess(str, out msg);
}
return item;
item = ResolveStdVmess(str);
}
else
{
item = ResolveVmess(str, out msg);
}
return item;
}
public static string? ToUri(ProfileItem? item)
{
if (item == null)
{
return null;
}
var vmessQRCode = new VmessQRCode
{
v = item.ConfigVersion,
ps = item.Remarks.TrimEx(),
add = item.Address,
port = item.Port,
id = item.Id,
aid = item.AlterId,
scy = item.Security,
net = item.Network,
type = item.HeaderType,
host = item.RequestHost,
path = item.Path,
tls = item.StreamSecurity,
sni = item.Sni,
alpn = item.Alpn,
fp = item.Fingerprint
};
var url = JsonUtils.Serialize(vmessQRCode);
url = Utils.Base64Encode(url);
url = $"{Global.ProtocolShares[EConfigType.VMess]}{url}";
return url;
}
private static ProfileItem? ResolveVmess(string result, out string msg)
{
msg = string.Empty;
var item = new ProfileItem
{
ConfigType = EConfigType.VMess
};
result = result[Global.ProtocolShares[EConfigType.VMess].Length..];
result = Utils.Base64Decode(result);
var vmessQRCode = JsonUtils.Deserialize<VmessQRCode>(result);
if (vmessQRCode == null)
{
msg = ResUI.FailedConversionConfiguration;
return null;
}
public static string? ToUri(ProfileItem? item)
item.Network = Global.DefaultNetwork;
item.HeaderType = Global.None;
item.ConfigVersion = vmessQRCode.v;
item.Remarks = Utils.ToString(vmessQRCode.ps);
item.Address = Utils.ToString(vmessQRCode.add);
item.Port = vmessQRCode.port;
item.Id = Utils.ToString(vmessQRCode.id);
item.AlterId = vmessQRCode.aid;
item.Security = Utils.ToString(vmessQRCode.scy);
item.Security = vmessQRCode.scy.IsNotEmpty() ? vmessQRCode.scy : Global.DefaultSecurity;
if (vmessQRCode.net.IsNotEmpty())
{
if (item == null)
{
return null;
}
var vmessQRCode = new VmessQRCode
{
v = item.ConfigVersion,
ps = item.Remarks.TrimEx(),
add = item.Address,
port = item.Port,
id = item.Id,
aid = item.AlterId,
scy = item.Security,
net = item.Network,
type = item.HeaderType,
host = item.RequestHost,
path = item.Path,
tls = item.StreamSecurity,
sni = item.Sni,
alpn = item.Alpn,
fp = item.Fingerprint
};
var url = JsonUtils.Serialize(vmessQRCode);
url = Utils.Base64Encode(url);
url = $"{Global.ProtocolShares[EConfigType.VMess]}{url}";
return url;
item.Network = vmessQRCode.net;
}
if (vmessQRCode.type.IsNotEmpty())
{
item.HeaderType = vmessQRCode.type;
}
private static ProfileItem? ResolveVmess(string result, out string msg)
item.RequestHost = Utils.ToString(vmessQRCode.host);
item.Path = Utils.ToString(vmessQRCode.path);
item.StreamSecurity = Utils.ToString(vmessQRCode.tls);
item.Sni = Utils.ToString(vmessQRCode.sni);
item.Alpn = Utils.ToString(vmessQRCode.alpn);
item.Fingerprint = Utils.ToString(vmessQRCode.fp);
return item;
}
public static ProfileItem? ResolveStdVmess(string str)
{
var item = new ProfileItem
{
msg = string.Empty;
var item = new ProfileItem
{
ConfigType = EConfigType.VMess
};
ConfigType = EConfigType.VMess,
Security = "auto"
};
result = result[Global.ProtocolShares[EConfigType.VMess].Length..];
result = Utils.Base64Decode(result);
var vmessQRCode = JsonUtils.Deserialize<VmessQRCode>(result);
if (vmessQRCode == null)
{
msg = ResUI.FailedConversionConfiguration;
return null;
}
item.Network = Global.DefaultNetwork;
item.HeaderType = Global.None;
item.ConfigVersion = vmessQRCode.v;
item.Remarks = Utils.ToString(vmessQRCode.ps);
item.Address = Utils.ToString(vmessQRCode.add);
item.Port = vmessQRCode.port;
item.Id = Utils.ToString(vmessQRCode.id);
item.AlterId = vmessQRCode.aid;
item.Security = Utils.ToString(vmessQRCode.scy);
item.Security = vmessQRCode.scy.IsNotEmpty() ? vmessQRCode.scy : Global.DefaultSecurity;
if (vmessQRCode.net.IsNotEmpty())
{
item.Network = vmessQRCode.net;
}
if (vmessQRCode.type.IsNotEmpty())
{
item.HeaderType = vmessQRCode.type;
}
item.RequestHost = Utils.ToString(vmessQRCode.host);
item.Path = Utils.ToString(vmessQRCode.path);
item.StreamSecurity = Utils.ToString(vmessQRCode.tls);
item.Sni = Utils.ToString(vmessQRCode.sni);
item.Alpn = Utils.ToString(vmessQRCode.alpn);
item.Fingerprint = Utils.ToString(vmessQRCode.fp);
return item;
var url = Utils.TryUri(str);
if (url == null)
{
return null;
}
public static ProfileItem? ResolveStdVmess(string str)
{
var item = new ProfileItem
{
ConfigType = EConfigType.VMess,
Security = "auto"
};
item.Address = url.IdnHost;
item.Port = url.Port;
item.Remarks = url.GetComponents(UriComponents.Fragment, UriFormat.Unescaped);
item.Id = Utils.UrlDecode(url.UserInfo);
var url = Utils.TryUri(str);
if (url == null)
{
return null;
}
var query = Utils.ParseQueryString(url.Query);
ResolveStdTransport(query, ref item);
item.Address = url.IdnHost;
item.Port = url.Port;
item.Remarks = url.GetComponents(UriComponents.Fragment, UriFormat.Unescaped);
item.Id = Utils.UrlDecode(url.UserInfo);
var query = Utils.ParseQueryString(url.Query);
ResolveStdTransport(query, ref item);
return item;
}
return item;
}
}
+57 -58
View File
@@ -1,68 +1,67 @@
namespace ServiceLib.Handler.Fmt
namespace ServiceLib.Handler.Fmt;
public class WireguardFmt : BaseFmt
{
public class WireguardFmt : BaseFmt
public static ProfileItem? Resolve(string str, out string msg)
{
public static ProfileItem? Resolve(string str, out string msg)
msg = ResUI.ConfigurationFormatIncorrect;
ProfileItem item = new()
{
msg = ResUI.ConfigurationFormatIncorrect;
ConfigType = EConfigType.WireGuard
};
ProfileItem item = new()
{
ConfigType = EConfigType.WireGuard
};
var url = Utils.TryUri(str);
if (url == null)
{
return null;
}
item.Address = url.IdnHost;
item.Port = url.Port;
item.Remarks = url.GetComponents(UriComponents.Fragment, UriFormat.Unescaped);
item.Id = Utils.UrlDecode(url.UserInfo);
var query = Utils.ParseQueryString(url.Query);
item.PublicKey = Utils.UrlDecode(query["publickey"] ?? "");
item.Path = Utils.UrlDecode(query["reserved"] ?? "");
item.RequestHost = Utils.UrlDecode(query["address"] ?? "");
item.ShortId = Utils.UrlDecode(query["mtu"] ?? "");
return item;
var url = Utils.TryUri(str);
if (url == null)
{
return null;
}
public static string? ToUri(ProfileItem? item)
item.Address = url.IdnHost;
item.Port = url.Port;
item.Remarks = url.GetComponents(UriComponents.Fragment, UriFormat.Unescaped);
item.Id = Utils.UrlDecode(url.UserInfo);
var query = Utils.ParseQueryString(url.Query);
item.PublicKey = Utils.UrlDecode(query["publickey"] ?? "");
item.Path = Utils.UrlDecode(query["reserved"] ?? "");
item.RequestHost = Utils.UrlDecode(query["address"] ?? "");
item.ShortId = Utils.UrlDecode(query["mtu"] ?? "");
return item;
}
public static string? ToUri(ProfileItem? item)
{
if (item == null)
{
if (item == null)
{
return null;
}
var remark = string.Empty;
if (item.Remarks.IsNotEmpty())
{
remark = "#" + Utils.UrlEncode(item.Remarks);
}
var dicQuery = new Dictionary<string, string>();
if (item.PublicKey.IsNotEmpty())
{
dicQuery.Add("publickey", Utils.UrlEncode(item.PublicKey));
}
if (item.Path.IsNotEmpty())
{
dicQuery.Add("reserved", Utils.UrlEncode(item.Path));
}
if (item.RequestHost.IsNotEmpty())
{
dicQuery.Add("address", Utils.UrlEncode(item.RequestHost));
}
if (item.ShortId.IsNotEmpty())
{
dicQuery.Add("mtu", Utils.UrlEncode(item.ShortId));
}
return ToUri(EConfigType.WireGuard, item.Address, item.Port, item.Id, dicQuery, remark);
return null;
}
var remark = string.Empty;
if (item.Remarks.IsNotEmpty())
{
remark = "#" + Utils.UrlEncode(item.Remarks);
}
var dicQuery = new Dictionary<string, string>();
if (item.PublicKey.IsNotEmpty())
{
dicQuery.Add("publickey", Utils.UrlEncode(item.PublicKey));
}
if (item.Path.IsNotEmpty())
{
dicQuery.Add("reserved", Utils.UrlEncode(item.Path));
}
if (item.RequestHost.IsNotEmpty())
{
dicQuery.Add("address", Utils.UrlEncode(item.RequestHost));
}
if (item.ShortId.IsNotEmpty())
{
dicQuery.Add("mtu", Utils.UrlEncode(item.ShortId));
}
return ToUri(EConfigType.WireGuard, item.Address, item.Port, item.Id, dicQuery, remark);
}
}
+37 -38
View File
@@ -1,44 +1,43 @@
using ReactiveUI;
using ReactiveUI;
namespace ServiceLib.Handler
namespace ServiceLib.Handler;
public class NoticeHandler
{
public class NoticeHandler
private static readonly Lazy<NoticeHandler> _instance = new(() => new());
public static NoticeHandler Instance => _instance.Value;
public void Enqueue(string? content)
{
private static readonly Lazy<NoticeHandler> _instance = new(() => new());
public static NoticeHandler Instance => _instance.Value;
public void Enqueue(string? content)
if (content.IsNullOrEmpty())
{
if (content.IsNullOrEmpty())
{
return;
}
MessageBus.Current.SendMessage(content, EMsgCommand.SendSnackMsg.ToString());
}
public void SendMessage(string? content)
{
if (content.IsNullOrEmpty())
{
return;
}
MessageBus.Current.SendMessage(content, EMsgCommand.SendMsgView.ToString());
}
public void SendMessageEx(string? content)
{
if (content.IsNullOrEmpty())
{
return;
}
content = $"{DateTime.Now:yyyy/MM/dd HH:mm:ss} {content}";
SendMessage(content);
}
public void SendMessageAndEnqueue(string? msg)
{
Enqueue(msg);
SendMessage(msg);
return;
}
MessageBus.Current.SendMessage(content, EMsgCommand.SendSnackMsg.ToString());
}
}
public void SendMessage(string? content)
{
if (content.IsNullOrEmpty())
{
return;
}
MessageBus.Current.SendMessage(content, EMsgCommand.SendMsgView.ToString());
}
public void SendMessageEx(string? content)
{
if (content.IsNullOrEmpty())
{
return;
}
content = $"{DateTime.Now:yyyy/MM/dd HH:mm:ss} {content}";
SendMessage(content);
}
public void SendMessageAndEnqueue(string? msg)
{
Enqueue(msg);
SendMessage(msg);
}
}
+88 -89
View File
@@ -1,115 +1,114 @@
using System.Net.Sockets;
using System.Text;
namespace ServiceLib.Handler
namespace ServiceLib.Handler;
public class PacHandler
{
public class PacHandler
private static string _configPath;
private static int _httpPort;
private static int _pacPort;
private static TcpListener? _tcpListener;
private static byte[] _writeContent;
private static bool _isRunning;
private static bool _needRestart = true;
public static async Task Start(string configPath, int httpPort, int pacPort)
{
private static string _configPath;
private static int _httpPort;
private static int _pacPort;
private static TcpListener? _tcpListener;
private static byte[] _writeContent;
private static bool _isRunning;
private static bool _needRestart = true;
_needRestart = configPath != _configPath || httpPort != _httpPort || pacPort != _pacPort || !_isRunning;
public static async Task Start(string configPath, int httpPort, int pacPort)
_configPath = configPath;
_httpPort = httpPort;
_pacPort = pacPort;
await InitText();
if (_needRestart)
{
_needRestart = configPath != _configPath || httpPort != _httpPort || pacPort != _pacPort || !_isRunning;
Stop();
RunListener();
}
}
_configPath = configPath;
_httpPort = httpPort;
_pacPort = pacPort;
private static async Task InitText()
{
var path = Path.Combine(_configPath, "pac.txt");
await InitText();
if (_needRestart)
{
Stop();
RunListener();
}
// Delete the old pac file
if (File.Exists(path) && Utils.GetFileHash(path).Equals("b590c07280f058ef05d5394aa2f927fe"))
{
File.Delete(path);
}
private static async Task InitText()
if (!File.Exists(path))
{
var path = Path.Combine(_configPath, "pac.txt");
// Delete the old pac file
if (File.Exists(path) && Utils.GetFileHash(path).Equals("b590c07280f058ef05d5394aa2f927fe"))
{
File.Delete(path);
}
if (!File.Exists(path))
{
var pac = EmbedUtils.GetEmbedText(Global.PacFileName);
await File.AppendAllTextAsync(path, pac);
}
var pacText =
(await File.ReadAllTextAsync(path)).Replace("__PROXY__", $"PROXY 127.0.0.1:{_httpPort};DIRECT;");
var sb = new StringBuilder();
sb.AppendLine("HTTP/1.0 200 OK");
sb.AppendLine("Content-type:application/x-ns-proxy-autoconfig");
sb.AppendLine("Connection:close");
sb.AppendLine("Content-Length:" + Encoding.UTF8.GetByteCount(pacText));
sb.AppendLine();
sb.Append(pacText);
_writeContent = Encoding.UTF8.GetBytes(sb.ToString());
var pac = EmbedUtils.GetEmbedText(Global.PacFileName);
await File.AppendAllTextAsync(path, pac);
}
private static void RunListener()
var pacText =
(await File.ReadAllTextAsync(path)).Replace("__PROXY__", $"PROXY 127.0.0.1:{_httpPort};DIRECT;");
var sb = new StringBuilder();
sb.AppendLine("HTTP/1.0 200 OK");
sb.AppendLine("Content-type:application/x-ns-proxy-autoconfig");
sb.AppendLine("Connection:close");
sb.AppendLine("Content-Length:" + Encoding.UTF8.GetByteCount(pacText));
sb.AppendLine();
sb.Append(pacText);
_writeContent = Encoding.UTF8.GetBytes(sb.ToString());
}
private static void RunListener()
{
_tcpListener = TcpListener.Create(_pacPort);
_isRunning = true;
_tcpListener.Start();
Task.Factory.StartNew(async () =>
{
_tcpListener = TcpListener.Create(_pacPort);
_isRunning = true;
_tcpListener.Start();
Task.Factory.StartNew(async () =>
while (_isRunning)
{
while (_isRunning)
try
{
try
if (!_tcpListener.Pending())
{
if (!_tcpListener.Pending())
{
await Task.Delay(10);
continue;
}
await Task.Delay(10);
continue;
}
var client = await _tcpListener.AcceptTcpClientAsync();
await Task.Run(() => WriteContent(client));
}
catch
{
// ignored
}
var client = await _tcpListener.AcceptTcpClientAsync();
await Task.Run(() => WriteContent(client));
}
}, TaskCreationOptions.LongRunning);
}
catch
{
// ignored
}
}
}, TaskCreationOptions.LongRunning);
}
private static void WriteContent(TcpClient client)
{
var stream = client.GetStream();
stream.Write(_writeContent, 0, _writeContent.Length);
stream.Flush();
}
private static void WriteContent(TcpClient client)
{
var stream = client.GetStream();
stream.Write(_writeContent, 0, _writeContent.Length);
stream.Flush();
}
public static void Stop()
public static void Stop()
{
if (_tcpListener == null)
{
if (_tcpListener == null)
{
return;
}
try
{
_isRunning = false;
_tcpListener.Stop();
_tcpListener = null;
}
catch
{
// ignored
}
return;
}
try
{
_isRunning = false;
_tcpListener.Stop();
_tcpListener = null;
}
catch
{
// ignored
}
}
}
+143 -144
View File
@@ -2,181 +2,180 @@ using System.Collections.Concurrent;
//using System.Reactive.Linq;
namespace ServiceLib.Handler
namespace ServiceLib.Handler;
public class ProfileExHandler
{
public class ProfileExHandler
private static readonly Lazy<ProfileExHandler> _instance = new(() => new());
private ConcurrentBag<ProfileExItem> _lstProfileEx = [];
private readonly Queue<string> _queIndexIds = new();
public static ProfileExHandler Instance => _instance.Value;
private static readonly string _tag = "ProfileExHandler";
public ProfileExHandler()
{
private static readonly Lazy<ProfileExHandler> _instance = new(() => new());
private ConcurrentBag<ProfileExItem> _lstProfileEx = [];
private readonly Queue<string> _queIndexIds = new();
public static ProfileExHandler Instance => _instance.Value;
private static readonly string _tag = "ProfileExHandler";
//Init();
}
public ProfileExHandler()
public async Task Init()
{
await InitData();
}
public async Task<ConcurrentBag<ProfileExItem>> GetProfileExs()
{
return await Task.FromResult(_lstProfileEx);
}
private async Task InitData()
{
await SQLiteHelper.Instance.ExecuteAsync($"delete from ProfileExItem where indexId not in ( select indexId from ProfileItem )");
_lstProfileEx = new(await SQLiteHelper.Instance.TableAsync<ProfileExItem>().ToListAsync());
}
private void IndexIdEnqueue(string indexId)
{
if (indexId.IsNotEmpty() && !_queIndexIds.Contains(indexId))
{
//Init();
_queIndexIds.Enqueue(indexId);
}
}
public async Task Init()
private async Task SaveQueueIndexIds()
{
var cnt = _queIndexIds.Count;
if (cnt > 0)
{
await InitData();
}
var lstExists = await SQLiteHelper.Instance.TableAsync<ProfileExItem>().ToListAsync();
List<ProfileExItem> lstInserts = [];
List<ProfileExItem> lstUpdates = [];
public async Task<ConcurrentBag<ProfileExItem>> GetProfileExs()
{
return await Task.FromResult(_lstProfileEx);
}
private async Task InitData()
{
await SQLiteHelper.Instance.ExecuteAsync($"delete from ProfileExItem where indexId not in ( select indexId from ProfileItem )");
_lstProfileEx = new(await SQLiteHelper.Instance.TableAsync<ProfileExItem>().ToListAsync());
}
private void IndexIdEnqueue(string indexId)
{
if (indexId.IsNotEmpty() && !_queIndexIds.Contains(indexId))
for (var i = 0; i < cnt; i++)
{
_queIndexIds.Enqueue(indexId);
}
}
private async Task SaveQueueIndexIds()
{
var cnt = _queIndexIds.Count;
if (cnt > 0)
{
var lstExists = await SQLiteHelper.Instance.TableAsync<ProfileExItem>().ToListAsync();
List<ProfileExItem> lstInserts = [];
List<ProfileExItem> lstUpdates = [];
for (var i = 0; i < cnt; i++)
var id = _queIndexIds.Dequeue();
var item = lstExists.FirstOrDefault(t => t.IndexId == id);
var itemNew = _lstProfileEx?.FirstOrDefault(t => t.IndexId == id);
if (itemNew is null)
{
var id = _queIndexIds.Dequeue();
var item = lstExists.FirstOrDefault(t => t.IndexId == id);
var itemNew = _lstProfileEx?.FirstOrDefault(t => t.IndexId == id);
if (itemNew is null)
{
continue;
}
if (item is not null)
{
lstUpdates.Add(itemNew);
}
else
{
lstInserts.Add(itemNew);
}
continue;
}
try
if (item is not null)
{
if (lstInserts.Count > 0)
{
await SQLiteHelper.Instance.InsertAllAsync(lstInserts);
}
if (lstUpdates.Count > 0)
{
await SQLiteHelper.Instance.UpdateAllAsync(lstUpdates);
}
lstUpdates.Add(itemNew);
}
catch (Exception ex)
else
{
Logging.SaveLog(_tag, ex);
lstInserts.Add(itemNew);
}
}
}
private ProfileExItem AddProfileEx(string indexId)
{
var profileEx = new ProfileExItem()
{
IndexId = indexId,
Delay = 0,
Speed = 0,
Sort = 0,
Message = string.Empty
};
_lstProfileEx.Add(profileEx);
IndexIdEnqueue(indexId);
return profileEx;
}
private ProfileExItem GetProfileExItem(string? indexId)
{
return _lstProfileEx.FirstOrDefault(t => t.IndexId == indexId) ?? AddProfileEx(indexId);
}
public async Task ClearAll()
{
await SQLiteHelper.Instance.ExecuteAsync($"delete from ProfileExItem ");
_lstProfileEx = new();
}
public async Task SaveTo()
{
try
{
await SaveQueueIndexIds();
if (lstInserts.Count > 0)
{
await SQLiteHelper.Instance.InsertAllAsync(lstInserts);
}
if (lstUpdates.Count > 0)
{
await SQLiteHelper.Instance.UpdateAllAsync(lstUpdates);
}
}
catch (Exception ex)
{
Logging.SaveLog(_tag, ex);
}
}
}
public void SetTestDelay(string indexId, int delay)
private ProfileExItem AddProfileEx(string indexId)
{
var profileEx = new ProfileExItem()
{
var profileEx = GetProfileExItem(indexId);
IndexId = indexId,
Delay = 0,
Speed = 0,
Sort = 0,
Message = string.Empty
};
_lstProfileEx.Add(profileEx);
IndexIdEnqueue(indexId);
return profileEx;
}
profileEx.Delay = delay;
IndexIdEnqueue(indexId);
private ProfileExItem GetProfileExItem(string? indexId)
{
return _lstProfileEx.FirstOrDefault(t => t.IndexId == indexId) ?? AddProfileEx(indexId);
}
public async Task ClearAll()
{
await SQLiteHelper.Instance.ExecuteAsync($"delete from ProfileExItem ");
_lstProfileEx = new();
}
public async Task SaveTo()
{
try
{
await SaveQueueIndexIds();
}
public void SetTestSpeed(string indexId, decimal speed)
catch (Exception ex)
{
var profileEx = GetProfileExItem(indexId);
profileEx.Speed = speed;
IndexIdEnqueue(indexId);
}
public void SetTestMessage(string indexId, string message)
{
var profileEx = GetProfileExItem(indexId);
profileEx.Message = message;
IndexIdEnqueue(indexId);
}
public void SetSort(string indexId, int sort)
{
var profileEx = GetProfileExItem(indexId);
profileEx.Sort = sort;
IndexIdEnqueue(indexId);
}
public int GetSort(string indexId)
{
var profileEx = _lstProfileEx.FirstOrDefault(t => t.IndexId == indexId);
if (profileEx == null)
{
return 0;
}
return profileEx.Sort;
}
public int GetMaxSort()
{
if (_lstProfileEx.Count <= 0)
{
return 0;
}
return _lstProfileEx.Max(t => t == null ? 0 : t.Sort);
Logging.SaveLog(_tag, ex);
}
}
public void SetTestDelay(string indexId, int delay)
{
var profileEx = GetProfileExItem(indexId);
profileEx.Delay = delay;
IndexIdEnqueue(indexId);
}
public void SetTestSpeed(string indexId, decimal speed)
{
var profileEx = GetProfileExItem(indexId);
profileEx.Speed = speed;
IndexIdEnqueue(indexId);
}
public void SetTestMessage(string indexId, string message)
{
var profileEx = GetProfileExItem(indexId);
profileEx.Message = message;
IndexIdEnqueue(indexId);
}
public void SetSort(string indexId, int sort)
{
var profileEx = GetProfileExItem(indexId);
profileEx.Sort = sort;
IndexIdEnqueue(indexId);
}
public int GetSort(string indexId)
{
var profileEx = _lstProfileEx.FirstOrDefault(t => t.IndexId == indexId);
if (profileEx == null)
{
return 0;
}
return profileEx.Sort;
}
public int GetMaxSort()
{
if (_lstProfileEx.Count <= 0)
{
return 0;
}
return _lstProfileEx.Max(t => t == null ? 0 : t.Sort);
}
}
+157 -158
View File
@@ -1,164 +1,163 @@
namespace ServiceLib.Handler
namespace ServiceLib.Handler;
public class StatisticsHandler
{
public class StatisticsHandler
private static readonly Lazy<StatisticsHandler> instance = new(() => new());
public static StatisticsHandler Instance => instance.Value;
private Config _config;
private ServerStatItem? _serverStatItem;
private List<ServerStatItem> _lstServerStat;
private Action<ServerSpeedItem>? _updateFunc;
private StatisticsXrayService? _statisticsXray;
private StatisticsSingboxService? _statisticsSingbox;
private static readonly string _tag = "StatisticsHandler";
public List<ServerStatItem> ServerStat => _lstServerStat;
public async Task Init(Config config, Action<ServerSpeedItem> updateFunc)
{
private static readonly Lazy<StatisticsHandler> instance = new(() => new());
public static StatisticsHandler Instance => instance.Value;
private Config _config;
private ServerStatItem? _serverStatItem;
private List<ServerStatItem> _lstServerStat;
private Action<ServerSpeedItem>? _updateFunc;
private StatisticsXrayService? _statisticsXray;
private StatisticsSingboxService? _statisticsSingbox;
private static readonly string _tag = "StatisticsHandler";
public List<ServerStatItem> ServerStat => _lstServerStat;
public async Task Init(Config config, Action<ServerSpeedItem> updateFunc)
_config = config;
_updateFunc = updateFunc;
if (config.GuiItem.EnableStatistics || _config.GuiItem.DisplayRealTimeSpeed)
{
_config = config;
_updateFunc = updateFunc;
if (config.GuiItem.EnableStatistics || _config.GuiItem.DisplayRealTimeSpeed)
{
await InitData();
await InitData();
_statisticsXray = new StatisticsXrayService(config, UpdateServerStatHandler);
_statisticsSingbox = new StatisticsSingboxService(config, UpdateServerStatHandler);
}
}
public void Close()
{
try
{
_statisticsXray?.Close();
_statisticsSingbox?.Close();
}
catch (Exception ex)
{
Logging.SaveLog(_tag, ex);
}
}
public async Task ClearAllServerStatistics()
{
await SQLiteHelper.Instance.ExecuteAsync($"delete from ServerStatItem ");
_serverStatItem = null;
_lstServerStat = new();
}
public async Task SaveTo()
{
try
{
if (_lstServerStat != null)
{
await SQLiteHelper.Instance.UpdateAllAsync(_lstServerStat);
}
}
catch (Exception ex)
{
Logging.SaveLog(_tag, ex);
}
}
public async Task CloneServerStatItem(string indexId, string toIndexId)
{
if (_lstServerStat == null)
{
return;
}
if (indexId == toIndexId)
{
return;
}
var stat = _lstServerStat.FirstOrDefault(t => t.IndexId == indexId);
if (stat == null)
{
return;
}
var toStat = JsonUtils.DeepCopy(stat);
toStat.IndexId = toIndexId;
await SQLiteHelper.Instance.ReplaceAsync(toStat);
_lstServerStat.Add(toStat);
}
private async Task InitData()
{
await SQLiteHelper.Instance.ExecuteAsync($"delete from ServerStatItem where indexId not in ( select indexId from ProfileItem )");
long ticks = DateTime.Now.Date.Ticks;
await SQLiteHelper.Instance.ExecuteAsync($"update ServerStatItem set todayUp = 0,todayDown=0,dateNow={ticks} where dateNow<>{ticks}");
_lstServerStat = await SQLiteHelper.Instance.TableAsync<ServerStatItem>().ToListAsync();
}
private void UpdateServerStatHandler(ServerSpeedItem server)
{
_ = UpdateServerStat(server);
}
private async Task UpdateServerStat(ServerSpeedItem server)
{
await GetServerStatItem(_config.IndexId);
if (_serverStatItem is null)
{
return;
}
if (server.ProxyUp != 0 || server.ProxyDown != 0)
{
_serverStatItem.TodayUp += server.ProxyUp;
_serverStatItem.TodayDown += server.ProxyDown;
_serverStatItem.TotalUp += server.ProxyUp;
_serverStatItem.TotalDown += server.ProxyDown;
}
server.IndexId = _config.IndexId;
server.TodayUp = _serverStatItem.TodayUp;
server.TodayDown = _serverStatItem.TodayDown;
server.TotalUp = _serverStatItem.TotalUp;
server.TotalDown = _serverStatItem.TotalDown;
_updateFunc?.Invoke(server);
}
private async Task GetServerStatItem(string indexId)
{
long ticks = DateTime.Now.Date.Ticks;
if (_serverStatItem != null && _serverStatItem.IndexId != indexId)
{
_serverStatItem = null;
}
if (_serverStatItem == null)
{
_serverStatItem = _lstServerStat.FirstOrDefault(t => t.IndexId == indexId);
if (_serverStatItem == null)
{
_serverStatItem = new ServerStatItem
{
IndexId = indexId,
TotalUp = 0,
TotalDown = 0,
TodayUp = 0,
TodayDown = 0,
DateNow = ticks
};
await SQLiteHelper.Instance.ReplaceAsync(_serverStatItem);
_lstServerStat.Add(_serverStatItem);
}
}
if (_serverStatItem.DateNow != ticks)
{
_serverStatItem.TodayUp = 0;
_serverStatItem.TodayDown = 0;
_serverStatItem.DateNow = ticks;
}
_statisticsXray = new StatisticsXrayService(config, UpdateServerStatHandler);
_statisticsSingbox = new StatisticsSingboxService(config, UpdateServerStatHandler);
}
}
}
public void Close()
{
try
{
_statisticsXray?.Close();
_statisticsSingbox?.Close();
}
catch (Exception ex)
{
Logging.SaveLog(_tag, ex);
}
}
public async Task ClearAllServerStatistics()
{
await SQLiteHelper.Instance.ExecuteAsync($"delete from ServerStatItem ");
_serverStatItem = null;
_lstServerStat = new();
}
public async Task SaveTo()
{
try
{
if (_lstServerStat != null)
{
await SQLiteHelper.Instance.UpdateAllAsync(_lstServerStat);
}
}
catch (Exception ex)
{
Logging.SaveLog(_tag, ex);
}
}
public async Task CloneServerStatItem(string indexId, string toIndexId)
{
if (_lstServerStat == null)
{
return;
}
if (indexId == toIndexId)
{
return;
}
var stat = _lstServerStat.FirstOrDefault(t => t.IndexId == indexId);
if (stat == null)
{
return;
}
var toStat = JsonUtils.DeepCopy(stat);
toStat.IndexId = toIndexId;
await SQLiteHelper.Instance.ReplaceAsync(toStat);
_lstServerStat.Add(toStat);
}
private async Task InitData()
{
await SQLiteHelper.Instance.ExecuteAsync($"delete from ServerStatItem where indexId not in ( select indexId from ProfileItem )");
long ticks = DateTime.Now.Date.Ticks;
await SQLiteHelper.Instance.ExecuteAsync($"update ServerStatItem set todayUp = 0,todayDown=0,dateNow={ticks} where dateNow<>{ticks}");
_lstServerStat = await SQLiteHelper.Instance.TableAsync<ServerStatItem>().ToListAsync();
}
private void UpdateServerStatHandler(ServerSpeedItem server)
{
_ = UpdateServerStat(server);
}
private async Task UpdateServerStat(ServerSpeedItem server)
{
await GetServerStatItem(_config.IndexId);
if (_serverStatItem is null)
{
return;
}
if (server.ProxyUp != 0 || server.ProxyDown != 0)
{
_serverStatItem.TodayUp += server.ProxyUp;
_serverStatItem.TodayDown += server.ProxyDown;
_serverStatItem.TotalUp += server.ProxyUp;
_serverStatItem.TotalDown += server.ProxyDown;
}
server.IndexId = _config.IndexId;
server.TodayUp = _serverStatItem.TodayUp;
server.TodayDown = _serverStatItem.TodayDown;
server.TotalUp = _serverStatItem.TotalUp;
server.TotalDown = _serverStatItem.TotalDown;
_updateFunc?.Invoke(server);
}
private async Task GetServerStatItem(string indexId)
{
long ticks = DateTime.Now.Date.Ticks;
if (_serverStatItem != null && _serverStatItem.IndexId != indexId)
{
_serverStatItem = null;
}
if (_serverStatItem == null)
{
_serverStatItem = _lstServerStat.FirstOrDefault(t => t.IndexId == indexId);
if (_serverStatItem == null)
{
_serverStatItem = new ServerStatItem
{
IndexId = indexId,
TotalUp = 0,
TotalDown = 0,
TodayUp = 0,
TodayDown = 0,
DateNow = ticks
};
await SQLiteHelper.Instance.ReplaceAsync(_serverStatItem);
_lstServerStat.Add(_serverStatItem);
}
}
if (_serverStatItem.DateNow != ticks)
{
_serverStatItem.TodayUp = 0;
_serverStatItem.TodayDown = 0;
_serverStatItem.DateNow = ticks;
}
}
}
@@ -1,33 +1,32 @@
namespace ServiceLib.Handler.SysProxy
namespace ServiceLib.Handler.SysProxy;
public class ProxySettingLinux
{
public class ProxySettingLinux
private static readonly string _proxySetFileName = $"{Global.ProxySetLinuxShellFileName.Replace(Global.NamespaceSample, "")}.sh";
public static async Task SetProxy(string host, int port, string exceptions)
{
private static readonly string _proxySetFileName = $"{Global.ProxySetLinuxShellFileName.Replace(Global.NamespaceSample, "")}.sh";
List<string> args = ["manual", host, port.ToString(), exceptions];
await ExecCmd(args);
}
public static async Task SetProxy(string host, int port, string exceptions)
public static async Task UnsetProxy()
{
List<string> args = ["none"];
await ExecCmd(args);
}
private static async Task ExecCmd(List<string> args)
{
var fileName = Utils.GetBinConfigPath(_proxySetFileName);
if (!File.Exists(fileName))
{
List<string> args = ["manual", host, port.ToString(), exceptions];
await ExecCmd(args);
var contents = EmbedUtils.GetEmbedText(Global.ProxySetLinuxShellFileName);
await File.AppendAllTextAsync(fileName, contents);
await Utils.SetLinuxChmod(fileName);
}
public static async Task UnsetProxy()
{
List<string> args = ["none"];
await ExecCmd(args);
}
private static async Task ExecCmd(List<string> args)
{
var fileName = Utils.GetBinConfigPath(_proxySetFileName);
if (!File.Exists(fileName))
{
var contents = EmbedUtils.GetEmbedText(Global.ProxySetLinuxShellFileName);
await File.AppendAllTextAsync(fileName, contents);
await Utils.SetLinuxChmod(fileName);
}
await Utils.GetCliWrapOutput(fileName, args);
}
await Utils.GetCliWrapOutput(fileName, args);
}
}
@@ -1,38 +1,37 @@
namespace ServiceLib.Handler.SysProxy
namespace ServiceLib.Handler.SysProxy;
public class ProxySettingOSX
{
public class ProxySettingOSX
private static readonly string _proxySetFileName = $"{Global.ProxySetOSXShellFileName.Replace(Global.NamespaceSample, "")}.sh";
public static async Task SetProxy(string host, int port, string exceptions)
{
private static readonly string _proxySetFileName = $"{Global.ProxySetOSXShellFileName.Replace(Global.NamespaceSample, "")}.sh";
public static async Task SetProxy(string host, int port, string exceptions)
List<string> args = ["set", host, port.ToString()];
if (exceptions.IsNotEmpty())
{
List<string> args = ["set", host, port.ToString()];
if (exceptions.IsNotEmpty())
{
args.AddRange(exceptions.Split(','));
}
await ExecCmd(args);
args.AddRange(exceptions.Split(','));
}
public static async Task UnsetProxy()
await ExecCmd(args);
}
public static async Task UnsetProxy()
{
List<string> args = ["clear"];
await ExecCmd(args);
}
private static async Task ExecCmd(List<string> args)
{
var fileName = Utils.GetBinConfigPath(_proxySetFileName);
if (!File.Exists(fileName))
{
List<string> args = ["clear"];
await ExecCmd(args);
var contents = EmbedUtils.GetEmbedText(Global.ProxySetOSXShellFileName);
await File.AppendAllTextAsync(fileName, contents);
await Utils.SetLinuxChmod(fileName);
}
private static async Task ExecCmd(List<string> args)
{
var fileName = Utils.GetBinConfigPath(_proxySetFileName);
if (!File.Exists(fileName))
{
var contents = EmbedUtils.GetEmbedText(Global.ProxySetOSXShellFileName);
await File.AppendAllTextAsync(fileName, contents);
await Utils.SetLinuxChmod(fileName);
}
await Utils.GetCliWrapOutput(fileName, args);
}
await Utils.GetCliWrapOutput(fileName, args);
}
}
@@ -1,360 +1,359 @@
using System.Runtime.InteropServices;
using static ServiceLib.Handler.SysProxy.ProxySettingWindows.InternetConnectionOption;
namespace ServiceLib.Handler.SysProxy
namespace ServiceLib.Handler.SysProxy;
public class ProxySettingWindows
{
public class ProxySettingWindows
private const string _regPath = @"Software\Microsoft\Windows\CurrentVersion\Internet Settings";
private static bool SetProxyFallback(string? strProxy, string? exceptions, int type)
{
private const string _regPath = @"Software\Microsoft\Windows\CurrentVersion\Internet Settings";
private static bool SetProxyFallback(string? strProxy, string? exceptions, int type)
if (type == 1)
{
if (type == 1)
{
WindowsUtils.RegWriteValue(_regPath, "ProxyEnable", 0);
WindowsUtils.RegWriteValue(_regPath, "ProxyServer", string.Empty);
WindowsUtils.RegWriteValue(_regPath, "ProxyOverride", string.Empty);
WindowsUtils.RegWriteValue(_regPath, "AutoConfigURL", string.Empty);
}
if (type == 2)
{
WindowsUtils.RegWriteValue(_regPath, "ProxyEnable", 1);
WindowsUtils.RegWriteValue(_regPath, "ProxyServer", strProxy ?? string.Empty);
WindowsUtils.RegWriteValue(_regPath, "ProxyOverride", exceptions ?? string.Empty);
WindowsUtils.RegWriteValue(_regPath, "AutoConfigURL", string.Empty);
}
else if (type == 4)
{
WindowsUtils.RegWriteValue(_regPath, "ProxyEnable", 0);
WindowsUtils.RegWriteValue(_regPath, "ProxyServer", string.Empty);
WindowsUtils.RegWriteValue(_regPath, "ProxyOverride", string.Empty);
WindowsUtils.RegWriteValue(_regPath, "AutoConfigURL", strProxy ?? string.Empty);
}
return true;
WindowsUtils.RegWriteValue(_regPath, "ProxyEnable", 0);
WindowsUtils.RegWriteValue(_regPath, "ProxyServer", string.Empty);
WindowsUtils.RegWriteValue(_regPath, "ProxyOverride", string.Empty);
WindowsUtils.RegWriteValue(_regPath, "AutoConfigURL", string.Empty);
}
/// <summary>
// set to use no proxy
/// </summary>
/// <exception cref="ApplicationException">Error message with win32 error code</exception>
public static bool UnsetProxy()
if (type == 2)
{
return SetProxy(null, null, 1);
WindowsUtils.RegWriteValue(_regPath, "ProxyEnable", 1);
WindowsUtils.RegWriteValue(_regPath, "ProxyServer", strProxy ?? string.Empty);
WindowsUtils.RegWriteValue(_regPath, "ProxyOverride", exceptions ?? string.Empty);
WindowsUtils.RegWriteValue(_regPath, "AutoConfigURL", string.Empty);
}
/// <summary>
/// Set system proxy settings
/// </summary>
/// <param name="strProxy"> proxy address</param>
/// <param name="exceptions">exception addresses that do not use proxy</param>
/// <param name="type">type of proxy defined in PerConnFlags
/// PROXY_TYPE_DIRECT = 0x00000001, // direct connection (no proxy)
/// PROXY_TYPE_PROXY = 0x00000002, // via named proxy
/// PROXY_TYPE_AUTO_PROXY_URL = 0x00000004, // autoproxy script URL
/// PROXY_TYPE_AUTO_DETECT = 0x00000008 // use autoproxy detection
/// </param>
/// <exception cref="ApplicationException">Error message with win32 error code</exception>
/// <returns>true: one of connection is successfully updated proxy settings</returns>
public static bool SetProxy(string? strProxy, string? exceptions, int type)
else if (type == 4)
{
try
{
// set proxy for LAN
var result = SetConnectionProxy(null, strProxy, exceptions, type);
// set proxy for dial up connections
var connections = EnumerateRasEntries();
foreach (var connection in connections)
{
result |= SetConnectionProxy(connection, strProxy, exceptions, type);
}
return result;
}
catch
{
_ = SetProxyFallback(strProxy, exceptions, type);
return false;
}
WindowsUtils.RegWriteValue(_regPath, "ProxyEnable", 0);
WindowsUtils.RegWriteValue(_regPath, "ProxyServer", string.Empty);
WindowsUtils.RegWriteValue(_regPath, "ProxyOverride", string.Empty);
WindowsUtils.RegWriteValue(_regPath, "AutoConfigURL", strProxy ?? string.Empty);
}
return true;
}
private static bool SetConnectionProxy(string? connectionName, string? strProxy, string? exceptions, int type)
/// <summary>
// set to use no proxy
/// </summary>
/// <exception cref="ApplicationException">Error message with win32 error code</exception>
public static bool UnsetProxy()
{
return SetProxy(null, null, 1);
}
/// <summary>
/// Set system proxy settings
/// </summary>
/// <param name="strProxy"> proxy address</param>
/// <param name="exceptions">exception addresses that do not use proxy</param>
/// <param name="type">type of proxy defined in PerConnFlags
/// PROXY_TYPE_DIRECT = 0x00000001, // direct connection (no proxy)
/// PROXY_TYPE_PROXY = 0x00000002, // via named proxy
/// PROXY_TYPE_AUTO_PROXY_URL = 0x00000004, // autoproxy script URL
/// PROXY_TYPE_AUTO_DETECT = 0x00000008 // use autoproxy detection
/// </param>
/// <exception cref="ApplicationException">Error message with win32 error code</exception>
/// <returns>true: one of connection is successfully updated proxy settings</returns>
public static bool SetProxy(string? strProxy, string? exceptions, int type)
{
try
{
var list = new InternetPerConnOptionList();
var optionCount = 1;
if (type == 1) // No proxy
// set proxy for LAN
var result = SetConnectionProxy(null, strProxy, exceptions, type);
// set proxy for dial up connections
var connections = EnumerateRasEntries();
foreach (var connection in connections)
{
optionCount = 1;
result |= SetConnectionProxy(connection, strProxy, exceptions, type);
}
else if (type is 2 or 4) // named proxy or autoproxy script URL
{
optionCount = exceptions.IsNullOrEmpty() ? 2 : 3;
}
var m_Int = (int)PerConnFlags.PROXY_TYPE_DIRECT;
var m_Option = PerConnOption.INTERNET_PER_CONN_FLAGS;
if (type == 2) // named proxy
{
m_Int = (int)(PerConnFlags.PROXY_TYPE_DIRECT | PerConnFlags.PROXY_TYPE_PROXY);
m_Option = PerConnOption.INTERNET_PER_CONN_PROXY_SERVER;
}
else if (type == 4) // autoproxy script url
{
m_Int = (int)(PerConnFlags.PROXY_TYPE_DIRECT | PerConnFlags.PROXY_TYPE_AUTO_PROXY_URL);
m_Option = PerConnOption.INTERNET_PER_CONN_AUTOCONFIG_URL;
}
var options = new InternetConnectionOption[optionCount];
// USE a proxy server ...
options[0].m_Option = PerConnOption.INTERNET_PER_CONN_FLAGS;
options[0].m_Value.m_Int = m_Int;
// use THIS proxy server
if (optionCount > 1)
{
options[1].m_Option = m_Option;
options[1].m_Value.m_StringPtr = Marshal.StringToHGlobalAuto(strProxy); // !! remember to deallocate memory 1
// except for these addresses ...
if (optionCount > 2)
{
options[2].m_Option = PerConnOption.INTERNET_PER_CONN_PROXY_BYPASS;
options[2].m_Value.m_StringPtr = Marshal.StringToHGlobalAuto(exceptions); // !! remember to deallocate memory 2
}
}
// default stuff
list.dwSize = Marshal.SizeOf(list);
if (connectionName != null)
{
list.szConnection = Marshal.StringToHGlobalAuto(connectionName); // !! remember to deallocate memory 3
}
else
{
list.szConnection = nint.Zero;
}
list.dwOptionCount = options.Length;
list.dwOptionError = 0;
var optSize = Marshal.SizeOf(typeof(InternetConnectionOption));
// make a pointer out of all that ...
var optionsPtr = Marshal.AllocCoTaskMem(optSize * options.Length); // !! remember to deallocate memory 4
// copy the array over into that spot in memory ...
for (var i = 0; i < options.Length; ++i)
{
if (Environment.Is64BitOperatingSystem)
{
var opt = new nint(optionsPtr.ToInt64() + (i * optSize));
Marshal.StructureToPtr(options[i], opt, false);
}
else
{
var opt = new nint(optionsPtr.ToInt32() + (i * optSize));
Marshal.StructureToPtr(options[i], opt, false);
}
}
list.options = optionsPtr;
// and then make a pointer out of the whole list
var ipcoListPtr = Marshal.AllocCoTaskMem(list.dwSize); // !! remember to deallocate memory 5
Marshal.StructureToPtr(list, ipcoListPtr, false);
// and finally, call the API method!
var isSuccess = NativeMethods.InternetSetOption(nint.Zero,
InternetOption.INTERNET_OPTION_PER_CONNECTION_OPTION,
ipcoListPtr, list.dwSize);
var returnvalue = 0; // ERROR_SUCCESS
if (!isSuccess)
{ // get the error codes, they might be helpful
returnvalue = Marshal.GetLastPInvokeError();
}
else
{
// Notify the system that the registry settings have been changed and cause them to be refreshed
_ = NativeMethods.InternetSetOption(nint.Zero, InternetOption.INTERNET_OPTION_SETTINGS_CHANGED, nint.Zero, 0);
_ = NativeMethods.InternetSetOption(nint.Zero, InternetOption.INTERNET_OPTION_REFRESH, nint.Zero, 0);
}
// FREE the data ASAP
if (list.szConnection != nint.Zero)
{
Marshal.FreeHGlobal(list.szConnection); // release mem 3
}
if (optionCount > 1)
{
Marshal.FreeHGlobal(options[1].m_Value.m_StringPtr); // release mem 1
if (optionCount > 2)
{
Marshal.FreeHGlobal(options[2].m_Value.m_StringPtr); // release mem 2
}
}
Marshal.FreeCoTaskMem(optionsPtr); // release mem 4
Marshal.FreeCoTaskMem(ipcoListPtr); // release mem 5
if (returnvalue != 0)
{
// throw the error codes, they might be helpful
throw new ApplicationException($"Set Internet Proxy failed with error code: {Marshal.GetLastWin32Error()}");
}
return true;
return result;
}
/// <summary>
/// Retrieve list of connections including LAN and WAN to support PPPoE connection
/// </summary>
/// <returns>A list of RAS connection names. May be empty list if no dial up connection.</returns>
/// <exception cref="ApplicationException">Error message with win32 error code</exception>
private static IEnumerable<string> EnumerateRasEntries()
catch
{
var entries = 0;
// attempt to query with 1 entry buffer
var rasEntryNames = new RASENTRYNAME[1];
var bufferSize = Marshal.SizeOf(typeof(RASENTRYNAME));
rasEntryNames[0].dwSize = Marshal.SizeOf(typeof(RASENTRYNAME));
var result = NativeMethods.RasEnumEntries(null, null, rasEntryNames, ref bufferSize, ref entries);
// increase buffer if the buffer is not large enough
if (result == (uint)ErrorCode.ERROR_BUFFER_TOO_SMALL)
{
rasEntryNames = new RASENTRYNAME[bufferSize / Marshal.SizeOf(typeof(RASENTRYNAME))];
for (var i = 0; i < rasEntryNames.Length; i++)
{
rasEntryNames[i].dwSize = Marshal.SizeOf(typeof(RASENTRYNAME));
}
result = NativeMethods.RasEnumEntries(null, null, rasEntryNames, ref bufferSize, ref entries);
}
if (result == 0)
{
var entryNames = new List<string>();
for (var i = 0; i < entries; i++)
{
entryNames.Add(rasEntryNames[i].szEntryName);
}
return entryNames;
}
throw new ApplicationException($"RasEnumEntries failed with error code: {result}");
}
#region WinInet structures
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
public struct InternetPerConnOptionList
{
public int dwSize; // size of the INTERNET_PER_CONN_OPTION_LIST struct
public nint szConnection; // connection name to set/query options
public int dwOptionCount; // number of options to set/query
public int dwOptionError; // on error, which option failed
//[MarshalAs(UnmanagedType.)]
public nint options;
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
public struct InternetConnectionOption
{
private static readonly int Size;
public PerConnOption m_Option;
public InternetConnectionOptionValue m_Value;
static InternetConnectionOption()
{
Size = Marshal.SizeOf(typeof(InternetConnectionOption));
}
// Nested Types
[StructLayout(LayoutKind.Explicit)]
public struct InternetConnectionOptionValue
{
// Fields
[FieldOffset(0)]
public System.Runtime.InteropServices.ComTypes.FILETIME m_FileTime;
[FieldOffset(0)]
public int m_Int;
[FieldOffset(0)]
public nint m_StringPtr;
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
public struct RASENTRYNAME
{
public int dwSize;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = RAS_MaxEntryName + 1)]
public string szEntryName;
public int dwFlags;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = MAX_PATH + 1)]
public string szPhonebookPath;
}
// Constants
public const int RAS_MaxEntryName = 256;
public const int MAX_PATH = 260; // Standard MAX_PATH value in Windows
}
#endregion WinInet structures
#region WinInet enums
//
// options manifests for Internet{Query|Set}Option
//
public enum InternetOption : uint
{
INTERNET_OPTION_PER_CONNECTION_OPTION = 75,
INTERNET_OPTION_REFRESH = 37,
INTERNET_OPTION_SETTINGS_CHANGED = 39
}
//
// Options used in INTERNET_PER_CONN_OPTON struct
//
public enum PerConnOption
{
INTERNET_PER_CONN_FLAGS = 1, // Sets or retrieves the connection type. The Value member will contain one or more of the values from PerConnFlags
INTERNET_PER_CONN_PROXY_SERVER = 2, // Sets or retrieves a string containing the proxy servers.
INTERNET_PER_CONN_PROXY_BYPASS = 3, // Sets or retrieves a string containing the URLs that do not use the proxy server.
INTERNET_PER_CONN_AUTOCONFIG_URL = 4//, // Sets or retrieves a string containing the URL to the automatic configuration script.
}
//
// PER_CONN_FLAGS
//
[Flags]
public enum PerConnFlags
{
PROXY_TYPE_DIRECT = 0x00000001, // direct to net
PROXY_TYPE_PROXY = 0x00000002, // via named proxy
PROXY_TYPE_AUTO_PROXY_URL = 0x00000004, // autoproxy URL
PROXY_TYPE_AUTO_DETECT = 0x00000008 // use autoproxy detection
}
public enum ErrorCode : uint
{
ERROR_BUFFER_TOO_SMALL = 603,
ERROR_INVALID_SIZE = 632
}
#endregion WinInet enums
internal static class NativeMethods
{
[DllImport("WinInet.dll", SetLastError = true, CharSet = CharSet.Auto)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool InternetSetOption(nint hInternet, InternetOption dwOption, nint lpBuffer, int dwBufferLength);
[DllImport("Rasapi32.dll", CharSet = CharSet.Auto)]
public static extern uint RasEnumEntries(
string? reserved, // Reserved, must be null
string? lpszPhonebook, // Pointer to full path and filename of phone-book file. If this parameter is NULL, the entries are enumerated from all the remote access phone-book files
[In, Out] RASENTRYNAME[]? lprasentryname, // Buffer to receive RAS entry names
ref int lpcb, // Size of the buffer
ref int lpcEntries // Number of entries written to the buffer
);
_ = SetProxyFallback(strProxy, exceptions, type);
return false;
}
}
private static bool SetConnectionProxy(string? connectionName, string? strProxy, string? exceptions, int type)
{
var list = new InternetPerConnOptionList();
var optionCount = 1;
if (type == 1) // No proxy
{
optionCount = 1;
}
else if (type is 2 or 4) // named proxy or autoproxy script URL
{
optionCount = exceptions.IsNullOrEmpty() ? 2 : 3;
}
var m_Int = (int)PerConnFlags.PROXY_TYPE_DIRECT;
var m_Option = PerConnOption.INTERNET_PER_CONN_FLAGS;
if (type == 2) // named proxy
{
m_Int = (int)(PerConnFlags.PROXY_TYPE_DIRECT | PerConnFlags.PROXY_TYPE_PROXY);
m_Option = PerConnOption.INTERNET_PER_CONN_PROXY_SERVER;
}
else if (type == 4) // autoproxy script url
{
m_Int = (int)(PerConnFlags.PROXY_TYPE_DIRECT | PerConnFlags.PROXY_TYPE_AUTO_PROXY_URL);
m_Option = PerConnOption.INTERNET_PER_CONN_AUTOCONFIG_URL;
}
var options = new InternetConnectionOption[optionCount];
// USE a proxy server ...
options[0].m_Option = PerConnOption.INTERNET_PER_CONN_FLAGS;
options[0].m_Value.m_Int = m_Int;
// use THIS proxy server
if (optionCount > 1)
{
options[1].m_Option = m_Option;
options[1].m_Value.m_StringPtr = Marshal.StringToHGlobalAuto(strProxy); // !! remember to deallocate memory 1
// except for these addresses ...
if (optionCount > 2)
{
options[2].m_Option = PerConnOption.INTERNET_PER_CONN_PROXY_BYPASS;
options[2].m_Value.m_StringPtr = Marshal.StringToHGlobalAuto(exceptions); // !! remember to deallocate memory 2
}
}
// default stuff
list.dwSize = Marshal.SizeOf(list);
if (connectionName != null)
{
list.szConnection = Marshal.StringToHGlobalAuto(connectionName); // !! remember to deallocate memory 3
}
else
{
list.szConnection = nint.Zero;
}
list.dwOptionCount = options.Length;
list.dwOptionError = 0;
var optSize = Marshal.SizeOf(typeof(InternetConnectionOption));
// make a pointer out of all that ...
var optionsPtr = Marshal.AllocCoTaskMem(optSize * options.Length); // !! remember to deallocate memory 4
// copy the array over into that spot in memory ...
for (var i = 0; i < options.Length; ++i)
{
if (Environment.Is64BitOperatingSystem)
{
var opt = new nint(optionsPtr.ToInt64() + (i * optSize));
Marshal.StructureToPtr(options[i], opt, false);
}
else
{
var opt = new nint(optionsPtr.ToInt32() + (i * optSize));
Marshal.StructureToPtr(options[i], opt, false);
}
}
list.options = optionsPtr;
// and then make a pointer out of the whole list
var ipcoListPtr = Marshal.AllocCoTaskMem(list.dwSize); // !! remember to deallocate memory 5
Marshal.StructureToPtr(list, ipcoListPtr, false);
// and finally, call the API method!
var isSuccess = NativeMethods.InternetSetOption(nint.Zero,
InternetOption.INTERNET_OPTION_PER_CONNECTION_OPTION,
ipcoListPtr, list.dwSize);
var returnvalue = 0; // ERROR_SUCCESS
if (!isSuccess)
{ // get the error codes, they might be helpful
returnvalue = Marshal.GetLastPInvokeError();
}
else
{
// Notify the system that the registry settings have been changed and cause them to be refreshed
_ = NativeMethods.InternetSetOption(nint.Zero, InternetOption.INTERNET_OPTION_SETTINGS_CHANGED, nint.Zero, 0);
_ = NativeMethods.InternetSetOption(nint.Zero, InternetOption.INTERNET_OPTION_REFRESH, nint.Zero, 0);
}
// FREE the data ASAP
if (list.szConnection != nint.Zero)
{
Marshal.FreeHGlobal(list.szConnection); // release mem 3
}
if (optionCount > 1)
{
Marshal.FreeHGlobal(options[1].m_Value.m_StringPtr); // release mem 1
if (optionCount > 2)
{
Marshal.FreeHGlobal(options[2].m_Value.m_StringPtr); // release mem 2
}
}
Marshal.FreeCoTaskMem(optionsPtr); // release mem 4
Marshal.FreeCoTaskMem(ipcoListPtr); // release mem 5
if (returnvalue != 0)
{
// throw the error codes, they might be helpful
throw new ApplicationException($"Set Internet Proxy failed with error code: {Marshal.GetLastWin32Error()}");
}
return true;
}
/// <summary>
/// Retrieve list of connections including LAN and WAN to support PPPoE connection
/// </summary>
/// <returns>A list of RAS connection names. May be empty list if no dial up connection.</returns>
/// <exception cref="ApplicationException">Error message with win32 error code</exception>
private static IEnumerable<string> EnumerateRasEntries()
{
var entries = 0;
// attempt to query with 1 entry buffer
var rasEntryNames = new RASENTRYNAME[1];
var bufferSize = Marshal.SizeOf(typeof(RASENTRYNAME));
rasEntryNames[0].dwSize = Marshal.SizeOf(typeof(RASENTRYNAME));
var result = NativeMethods.RasEnumEntries(null, null, rasEntryNames, ref bufferSize, ref entries);
// increase buffer if the buffer is not large enough
if (result == (uint)ErrorCode.ERROR_BUFFER_TOO_SMALL)
{
rasEntryNames = new RASENTRYNAME[bufferSize / Marshal.SizeOf(typeof(RASENTRYNAME))];
for (var i = 0; i < rasEntryNames.Length; i++)
{
rasEntryNames[i].dwSize = Marshal.SizeOf(typeof(RASENTRYNAME));
}
result = NativeMethods.RasEnumEntries(null, null, rasEntryNames, ref bufferSize, ref entries);
}
if (result == 0)
{
var entryNames = new List<string>();
for (var i = 0; i < entries; i++)
{
entryNames.Add(rasEntryNames[i].szEntryName);
}
return entryNames;
}
throw new ApplicationException($"RasEnumEntries failed with error code: {result}");
}
#region WinInet structures
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
public struct InternetPerConnOptionList
{
public int dwSize; // size of the INTERNET_PER_CONN_OPTION_LIST struct
public nint szConnection; // connection name to set/query options
public int dwOptionCount; // number of options to set/query
public int dwOptionError; // on error, which option failed
//[MarshalAs(UnmanagedType.)]
public nint options;
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
public struct InternetConnectionOption
{
private static readonly int Size;
public PerConnOption m_Option;
public InternetConnectionOptionValue m_Value;
static InternetConnectionOption()
{
Size = Marshal.SizeOf(typeof(InternetConnectionOption));
}
// Nested Types
[StructLayout(LayoutKind.Explicit)]
public struct InternetConnectionOptionValue
{
// Fields
[FieldOffset(0)]
public System.Runtime.InteropServices.ComTypes.FILETIME m_FileTime;
[FieldOffset(0)]
public int m_Int;
[FieldOffset(0)]
public nint m_StringPtr;
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
public struct RASENTRYNAME
{
public int dwSize;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = RAS_MaxEntryName + 1)]
public string szEntryName;
public int dwFlags;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = MAX_PATH + 1)]
public string szPhonebookPath;
}
// Constants
public const int RAS_MaxEntryName = 256;
public const int MAX_PATH = 260; // Standard MAX_PATH value in Windows
}
#endregion WinInet structures
#region WinInet enums
//
// options manifests for Internet{Query|Set}Option
//
public enum InternetOption : uint
{
INTERNET_OPTION_PER_CONNECTION_OPTION = 75,
INTERNET_OPTION_REFRESH = 37,
INTERNET_OPTION_SETTINGS_CHANGED = 39
}
//
// Options used in INTERNET_PER_CONN_OPTON struct
//
public enum PerConnOption
{
INTERNET_PER_CONN_FLAGS = 1, // Sets or retrieves the connection type. The Value member will contain one or more of the values from PerConnFlags
INTERNET_PER_CONN_PROXY_SERVER = 2, // Sets or retrieves a string containing the proxy servers.
INTERNET_PER_CONN_PROXY_BYPASS = 3, // Sets or retrieves a string containing the URLs that do not use the proxy server.
INTERNET_PER_CONN_AUTOCONFIG_URL = 4//, // Sets or retrieves a string containing the URL to the automatic configuration script.
}
//
// PER_CONN_FLAGS
//
[Flags]
public enum PerConnFlags
{
PROXY_TYPE_DIRECT = 0x00000001, // direct to net
PROXY_TYPE_PROXY = 0x00000002, // via named proxy
PROXY_TYPE_AUTO_PROXY_URL = 0x00000004, // autoproxy URL
PROXY_TYPE_AUTO_DETECT = 0x00000008 // use autoproxy detection
}
public enum ErrorCode : uint
{
ERROR_BUFFER_TOO_SMALL = 603,
ERROR_INVALID_SIZE = 632
}
#endregion WinInet enums
internal static class NativeMethods
{
[DllImport("WinInet.dll", SetLastError = true, CharSet = CharSet.Auto)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool InternetSetOption(nint hInternet, InternetOption dwOption, nint lpBuffer, int dwBufferLength);
[DllImport("Rasapi32.dll", CharSet = CharSet.Auto)]
public static extern uint RasEnumEntries(
string? reserved, // Reserved, must be null
string? lpszPhonebook, // Pointer to full path and filename of phone-book file. If this parameter is NULL, the entries are enumerated from all the remote access phone-book files
[In, Out] RASENTRYNAME[]? lprasentryname, // Buffer to receive RAS entry names
ref int lpcb, // Size of the buffer
ref int lpcEntries // Number of entries written to the buffer
);
}
}
@@ -1,99 +1,98 @@
namespace ServiceLib.Handler.SysProxy
namespace ServiceLib.Handler.SysProxy;
public static class SysProxyHandler
{
public static class SysProxyHandler
private static readonly string _tag = "SysProxyHandler";
public static async Task<bool> UpdateSysProxy(Config config, bool forceDisable)
{
private static readonly string _tag = "SysProxyHandler";
var type = config.SystemProxyItem.SysProxyType;
public static async Task<bool> UpdateSysProxy(Config config, bool forceDisable)
if (forceDisable && type != ESysProxyType.Unchanged)
{
var type = config.SystemProxyItem.SysProxyType;
if (forceDisable && type != ESysProxyType.Unchanged)
{
type = ESysProxyType.ForcedClear;
}
try
{
var port = AppHandler.Instance.GetLocalPort(EInboundProtocol.socks);
var exceptions = config.SystemProxyItem.SystemProxyExceptions.Replace(" ", "");
if (port <= 0)
{
return false;
}
switch (type)
{
case ESysProxyType.ForcedChange when Utils.IsWindows():
{
GetWindowsProxyString(config, port, out var strProxy, out var strExceptions);
ProxySettingWindows.SetProxy(strProxy, strExceptions, 2);
break;
}
case ESysProxyType.ForcedChange when Utils.IsLinux():
await ProxySettingLinux.SetProxy(Global.Loopback, port, exceptions);
break;
case ESysProxyType.ForcedChange when Utils.IsOSX():
await ProxySettingOSX.SetProxy(Global.Loopback, port, exceptions);
break;
case ESysProxyType.ForcedClear when Utils.IsWindows():
ProxySettingWindows.UnsetProxy();
break;
case ESysProxyType.ForcedClear when Utils.IsLinux():
await ProxySettingLinux.UnsetProxy();
break;
case ESysProxyType.ForcedClear when Utils.IsOSX():
await ProxySettingOSX.UnsetProxy();
break;
case ESysProxyType.Pac when Utils.IsWindows():
await SetWindowsProxyPac(port);
break;
}
if (type != ESysProxyType.Pac && Utils.IsWindows())
{
PacHandler.Stop();
}
}
catch (Exception ex)
{
Logging.SaveLog(_tag, ex);
}
return true;
type = ESysProxyType.ForcedClear;
}
private static void GetWindowsProxyString(Config config, int port, out string strProxy, out string strExceptions)
try
{
strExceptions = config.SystemProxyItem.SystemProxyExceptions.Replace(" ", "");
if (config.SystemProxyItem.NotProxyLocalAddress)
var port = AppHandler.Instance.GetLocalPort(EInboundProtocol.socks);
var exceptions = config.SystemProxyItem.SystemProxyExceptions.Replace(" ", "");
if (port <= 0)
{
strExceptions = $"<local>;{strExceptions}";
return false;
}
switch (type)
{
case ESysProxyType.ForcedChange when Utils.IsWindows():
{
GetWindowsProxyString(config, port, out var strProxy, out var strExceptions);
ProxySettingWindows.SetProxy(strProxy, strExceptions, 2);
break;
}
case ESysProxyType.ForcedChange when Utils.IsLinux():
await ProxySettingLinux.SetProxy(Global.Loopback, port, exceptions);
break;
case ESysProxyType.ForcedChange when Utils.IsOSX():
await ProxySettingOSX.SetProxy(Global.Loopback, port, exceptions);
break;
case ESysProxyType.ForcedClear when Utils.IsWindows():
ProxySettingWindows.UnsetProxy();
break;
case ESysProxyType.ForcedClear when Utils.IsLinux():
await ProxySettingLinux.UnsetProxy();
break;
case ESysProxyType.ForcedClear when Utils.IsOSX():
await ProxySettingOSX.UnsetProxy();
break;
case ESysProxyType.Pac when Utils.IsWindows():
await SetWindowsProxyPac(port);
break;
}
strProxy = string.Empty;
if (config.SystemProxyItem.SystemProxyAdvancedProtocol.IsNullOrEmpty())
if (type != ESysProxyType.Pac && Utils.IsWindows())
{
strProxy = $"{Global.Loopback}:{port}";
}
else
{
strProxy = config.SystemProxyItem.SystemProxyAdvancedProtocol
.Replace("{ip}", Global.Loopback)
.Replace("{http_port}", port.ToString())
.Replace("{socks_port}", port.ToString());
PacHandler.Stop();
}
}
private static async Task SetWindowsProxyPac(int port)
catch (Exception ex)
{
var portPac = AppHandler.Instance.GetLocalPort(EInboundProtocol.pac);
await PacHandler.Start(Utils.GetConfigPath(), port, portPac);
var strProxy = $"{Global.HttpProtocol}{Global.Loopback}:{portPac}/pac?t={DateTime.Now.Ticks}";
ProxySettingWindows.SetProxy(strProxy, "", 4);
Logging.SaveLog(_tag, ex);
}
return true;
}
private static void GetWindowsProxyString(Config config, int port, out string strProxy, out string strExceptions)
{
strExceptions = config.SystemProxyItem.SystemProxyExceptions.Replace(" ", "");
if (config.SystemProxyItem.NotProxyLocalAddress)
{
strExceptions = $"<local>;{strExceptions}";
}
strProxy = string.Empty;
if (config.SystemProxyItem.SystemProxyAdvancedProtocol.IsNullOrEmpty())
{
strProxy = $"{Global.Loopback}:{port}";
}
else
{
strProxy = config.SystemProxyItem.SystemProxyAdvancedProtocol
.Replace("{ip}", Global.Loopback)
.Replace("{http_port}", port.ToString())
.Replace("{socks_port}", port.ToString());
}
}
}
private static async Task SetWindowsProxyPac(int port)
{
var portPac = AppHandler.Instance.GetLocalPort(EInboundProtocol.pac);
await PacHandler.Start(Utils.GetConfigPath(), port, portPac);
var strProxy = $"{Global.HttpProtocol}{Global.Loopback}:{portPac}/pac?t={DateTime.Now.Ticks}";
ProxySettingWindows.SetProxy(strProxy, "", 4);
}
}
+82 -83
View File
@@ -1,98 +1,97 @@
namespace ServiceLib.Handler
namespace ServiceLib.Handler;
public class TaskHandler
{
public class TaskHandler
private static readonly Lazy<TaskHandler> _instance = new(() => new());
public static TaskHandler Instance => _instance.Value;
public void RegUpdateTask(Config config, Action<bool, string> updateFunc)
{
private static readonly Lazy<TaskHandler> _instance = new(() => new());
public static TaskHandler Instance => _instance.Value;
Task.Run(() => ScheduledTasks(config, updateFunc));
}
public void RegUpdateTask(Config config, Action<bool, string> updateFunc)
private async Task ScheduledTasks(Config config, Action<bool, string> updateFunc)
{
Logging.SaveLog("Setup Scheduled Tasks");
var numOfExecuted = 1;
while (true)
{
Task.Run(() => ScheduledTasks(config, updateFunc));
}
//1 minute
await Task.Delay(1000 * 60);
private async Task ScheduledTasks(Config config, Action<bool, string> updateFunc)
{
Logging.SaveLog("Setup Scheduled Tasks");
//Execute once 1 minute
await UpdateTaskRunSubscription(config, updateFunc);
var numOfExecuted = 1;
while (true)
//Execute once 20 minute
if (numOfExecuted % 20 == 0)
{
//1 minute
await Task.Delay(1000 * 60);
//Logging.SaveLog("Execute save config");
//Execute once 1 minute
await UpdateTaskRunSubscription(config, updateFunc);
//Execute once 20 minute
if (numOfExecuted % 20 == 0)
{
//Logging.SaveLog("Execute save config");
await ConfigHandler.SaveConfig(config);
await ProfileExHandler.Instance.SaveTo();
}
//Execute once 1 hour
if (numOfExecuted % 60 == 0)
{
//Logging.SaveLog("Execute delete expired files");
FileManager.DeleteExpiredFiles(Utils.GetBinConfigPath(), DateTime.Now.AddHours(-1));
FileManager.DeleteExpiredFiles(Utils.GetLogPath(), DateTime.Now.AddMonths(-1));
FileManager.DeleteExpiredFiles(Utils.GetTempPath(), DateTime.Now.AddMonths(-1));
//Check once 1 hour
await UpdateTaskRunGeo(config, numOfExecuted / 60, updateFunc);
}
numOfExecuted++;
}
}
private async Task UpdateTaskRunSubscription(Config config, Action<bool, string> updateFunc)
{
var updateTime = ((DateTimeOffset)DateTime.Now).ToUnixTimeSeconds();
var lstSubs = (await AppHandler.Instance.SubItems())?
.Where(t => t.AutoUpdateInterval > 0)
.Where(t => updateTime - t.UpdateTime >= t.AutoUpdateInterval * 60)
.ToList();
if (lstSubs is not { Count: > 0 })
{
return;
await ConfigHandler.SaveConfig(config);
await ProfileExHandler.Instance.SaveTo();
}
Logging.SaveLog("Execute update subscription");
//Execute once 1 hour
if (numOfExecuted % 60 == 0)
{
//Logging.SaveLog("Execute delete expired files");
FileManager.DeleteExpiredFiles(Utils.GetBinConfigPath(), DateTime.Now.AddHours(-1));
FileManager.DeleteExpiredFiles(Utils.GetLogPath(), DateTime.Now.AddMonths(-1));
FileManager.DeleteExpiredFiles(Utils.GetTempPath(), DateTime.Now.AddMonths(-1));
//Check once 1 hour
await UpdateTaskRunGeo(config, numOfExecuted / 60, updateFunc);
}
numOfExecuted++;
}
}
private async Task UpdateTaskRunSubscription(Config config, Action<bool, string> updateFunc)
{
var updateTime = ((DateTimeOffset)DateTime.Now).ToUnixTimeSeconds();
var lstSubs = (await AppHandler.Instance.SubItems())?
.Where(t => t.AutoUpdateInterval > 0)
.Where(t => updateTime - t.UpdateTime >= t.AutoUpdateInterval * 60)
.ToList();
if (lstSubs is not { Count: > 0 })
{
return;
}
Logging.SaveLog("Execute update subscription");
var updateHandle = new UpdateService();
foreach (var item in lstSubs)
{
await updateHandle.UpdateSubscriptionProcess(config, item.Id, true, (bool success, string msg) =>
{
updateFunc?.Invoke(success, msg);
if (success)
{
Logging.SaveLog($"Update subscription end. {msg}");
}
});
item.UpdateTime = updateTime;
await ConfigHandler.AddSubItem(config, item);
await Task.Delay(1000);
}
}
private async Task UpdateTaskRunGeo(Config config, int hours, Action<bool, string> updateFunc)
{
if (config.GuiItem.AutoUpdateInterval > 0 && hours > 0 && hours % config.GuiItem.AutoUpdateInterval == 0)
{
Logging.SaveLog("Execute update geo files");
var updateHandle = new UpdateService();
foreach (var item in lstSubs)
await updateHandle.UpdateGeoFileAll(config, (bool success, string msg) =>
{
await updateHandle.UpdateSubscriptionProcess(config, item.Id, true, (bool success, string msg) =>
{
updateFunc?.Invoke(success, msg);
if (success)
{
Logging.SaveLog($"Update subscription end. {msg}");
}
});
item.UpdateTime = updateTime;
await ConfigHandler.AddSubItem(config, item);
await Task.Delay(1000);
}
}
private async Task UpdateTaskRunGeo(Config config, int hours, Action<bool, string> updateFunc)
{
if (config.GuiItem.AutoUpdateInterval > 0 && hours > 0 && hours % config.GuiItem.AutoUpdateInterval == 0)
{
Logging.SaveLog("Execute update geo files");
var updateHandle = new UpdateService();
await updateHandle.UpdateGeoFileAll(config, (bool success, string msg) =>
{
updateFunc?.Invoke(false, msg);
});
}
updateFunc?.Invoke(false, msg);
});
}
}
}
+157 -158
View File
@@ -1,182 +1,181 @@
using System.Net;
using WebDav;
namespace ServiceLib.Handler
namespace ServiceLib.Handler;
public sealed class WebDavHandler
{
public sealed class WebDavHandler
private static readonly Lazy<WebDavHandler> _instance = new(() => new());
public static WebDavHandler Instance => _instance.Value;
private readonly Config? _config;
private WebDavClient? _client;
private string? _lastDescription;
private string _webDir = Global.AppName + "_backup";
private readonly string _webFileName = "backup.zip";
private readonly string _tag = "WebDav--";
public WebDavHandler()
{
private static readonly Lazy<WebDavHandler> _instance = new(() => new());
public static WebDavHandler Instance => _instance.Value;
_config = AppHandler.Instance.Config;
}
private readonly Config? _config;
private WebDavClient? _client;
private string? _lastDescription;
private string _webDir = Global.AppName + "_backup";
private readonly string _webFileName = "backup.zip";
private readonly string _tag = "WebDav--";
public WebDavHandler()
private async Task<bool> GetClient()
{
try
{
_config = AppHandler.Instance.Config;
if (_config.WebDavItem.Url.IsNullOrEmpty()
|| _config.WebDavItem.UserName.IsNullOrEmpty()
|| _config.WebDavItem.Password.IsNullOrEmpty())
{
throw new ArgumentException("webdav parameter error or null");
}
if (_client != null)
{
_client?.Dispose();
_client = null;
}
if (_config.WebDavItem.DirName.IsNullOrEmpty())
{
_webDir = Global.AppName + "_backup";
}
else
{
_webDir = _config.WebDavItem.DirName.TrimEx();
}
var clientParams = new WebDavClientParams
{
BaseAddress = new Uri(_config.WebDavItem.Url),
Credentials = new NetworkCredential(_config.WebDavItem.UserName, _config.WebDavItem.Password)
};
_client = new WebDavClient(clientParams);
}
private async Task<bool> GetClient()
catch (Exception ex)
{
try
{
if (_config.WebDavItem.Url.IsNullOrEmpty()
|| _config.WebDavItem.UserName.IsNullOrEmpty()
|| _config.WebDavItem.Password.IsNullOrEmpty())
{
throw new ArgumentException("webdav parameter error or null");
}
if (_client != null)
{
_client?.Dispose();
_client = null;
}
if (_config.WebDavItem.DirName.IsNullOrEmpty())
{
_webDir = Global.AppName + "_backup";
}
else
{
_webDir = _config.WebDavItem.DirName.TrimEx();
}
var clientParams = new WebDavClientParams
{
BaseAddress = new Uri(_config.WebDavItem.Url),
Credentials = new NetworkCredential(_config.WebDavItem.UserName, _config.WebDavItem.Password)
};
_client = new WebDavClient(clientParams);
}
catch (Exception ex)
{
SaveLog(ex);
return false;
}
return await Task.FromResult(true);
}
private async Task<bool> TryCreateDir()
{
if (_client is null)
{
return false;
}
try
{
var result2 = await _client.Mkcol(_webDir);
if (result2.IsSuccessful)
{
return true;
}
SaveLog(result2.Description);
}
catch (Exception ex)
{
SaveLog(ex);
}
SaveLog(ex);
return false;
}
return await Task.FromResult(true);
}
private void SaveLog(string desc)
private async Task<bool> TryCreateDir()
{
if (_client is null)
{
_lastDescription = desc;
Logging.SaveLog(_tag + desc);
}
private void SaveLog(Exception ex)
{
_lastDescription = ex.Message;
Logging.SaveLog(_tag, ex);
}
public async Task<bool> CheckConnection()
{
if (await GetClient() == false)
{
return false;
}
await TryCreateDir();
try
{
var testName = "readme_test";
var myContent = new StringContent(testName);
var result = await _client.PutFile($"{_webDir}/{testName}", myContent);
if (result.IsSuccessful)
{
await _client.Delete($"{_webDir}/{testName}");
return true;
}
else
{
SaveLog(result.Description);
}
}
catch (Exception ex)
{
SaveLog(ex);
}
return false;
}
public async Task<bool> PutFile(string fileName)
try
{
if (await GetClient() == false)
var result2 = await _client.Mkcol(_webDir);
if (result2.IsSuccessful)
{
return false;
}
await TryCreateDir();
try
{
await using var fs = File.OpenRead(fileName);
var result = await _client.PutFile($"{_webDir}/{_webFileName}", fs); // upload a resource
if (result.IsSuccessful)
{
return true;
}
SaveLog(result.Description);
}
catch (Exception ex)
{
SaveLog(ex);
}
return false;
}
public async Task<bool> GetRawFile(string fileName)
{
if (await GetClient() == false)
{
return false;
}
await TryCreateDir();
try
{
var response = await _client.GetRawFile($"{_webDir}/{_webFileName}");
if (!response.IsSuccessful)
{
SaveLog(response.Description);
return false;
}
await using var outputFileStream = new FileStream(fileName, FileMode.Create);
await response.Stream.CopyToAsync(outputFileStream);
return true;
}
catch (Exception ex)
{
SaveLog(ex);
}
SaveLog(result2.Description);
}
catch (Exception ex)
{
SaveLog(ex);
}
return false;
}
private void SaveLog(string desc)
{
_lastDescription = desc;
Logging.SaveLog(_tag + desc);
}
private void SaveLog(Exception ex)
{
_lastDescription = ex.Message;
Logging.SaveLog(_tag, ex);
}
public async Task<bool> CheckConnection()
{
if (await GetClient() == false)
{
return false;
}
await TryCreateDir();
public string GetLastError() => _lastDescription ?? string.Empty;
try
{
var testName = "readme_test";
var myContent = new StringContent(testName);
var result = await _client.PutFile($"{_webDir}/{testName}", myContent);
if (result.IsSuccessful)
{
await _client.Delete($"{_webDir}/{testName}");
return true;
}
else
{
SaveLog(result.Description);
}
}
catch (Exception ex)
{
SaveLog(ex);
}
return false;
}
public async Task<bool> PutFile(string fileName)
{
if (await GetClient() == false)
{
return false;
}
await TryCreateDir();
try
{
await using var fs = File.OpenRead(fileName);
var result = await _client.PutFile($"{_webDir}/{_webFileName}", fs); // upload a resource
if (result.IsSuccessful)
{
return true;
}
SaveLog(result.Description);
}
catch (Exception ex)
{
SaveLog(ex);
}
return false;
}
public async Task<bool> GetRawFile(string fileName)
{
if (await GetClient() == false)
{
return false;
}
await TryCreateDir();
try
{
var response = await _client.GetRawFile($"{_webDir}/{_webFileName}");
if (!response.IsSuccessful)
{
SaveLog(response.Description);
return false;
}
await using var outputFileStream = new FileStream(fileName, FileMode.Create);
await response.Stream.CopyToAsync(outputFileStream);
return true;
}
catch (Exception ex)
{
SaveLog(ex);
}
return false;
}
public string GetLastError() => _lastDescription ?? string.Empty;
}