mirror of
https://github.com/2dust/v2rayN.git
synced 2025-04-19 13:42:24 +00:00
Compare commits
13 commits
6ad0762731
...
24ccfb8077
Author | SHA1 | Date | |
---|---|---|---|
![]() |
24ccfb8077 | ||
![]() |
204451db6c | ||
![]() |
f553bbc41e | ||
![]() |
8cb4f2f961 | ||
![]() |
4d3db56065 | ||
![]() |
d92540121f | ||
![]() |
17d586ea26 | ||
![]() |
9a096d31fc | ||
![]() |
bf83dbdfea | ||
![]() |
e31cd0e199 | ||
![]() |
1e11477e27 | ||
![]() |
e0750df96c | ||
![]() |
e3580b05f7 |
204 changed files with 24422 additions and 24339 deletions
|
@ -1,26 +1,25 @@
|
||||||
namespace AmazTool
|
namespace AmazTool;
|
||||||
|
|
||||||
|
internal static class Program
|
||||||
{
|
{
|
||||||
internal static class Program
|
[STAThread]
|
||||||
|
private static void Main(string[] args)
|
||||||
{
|
{
|
||||||
[STAThread]
|
if (args.Length == 0)
|
||||||
private static void Main(string[] args)
|
|
||||||
{
|
{
|
||||||
if (args.Length == 0)
|
Console.WriteLine(Resx.Resource.Guidelines);
|
||||||
{
|
Thread.Sleep(5000);
|
||||||
Console.WriteLine(Resx.Resource.Guidelines);
|
return;
|
||||||
Thread.Sleep(5000);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var argData = Uri.UnescapeDataString(string.Join(" ", args));
|
|
||||||
if (argData.Equals("rebootas"))
|
|
||||||
{
|
|
||||||
Thread.Sleep(1000);
|
|
||||||
Utils.StartV2RayN();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
UpgradeApp.Upgrade(argData);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var argData = Uri.UnescapeDataString(string.Join(" ", args));
|
||||||
|
if (argData.Equals("rebootas"))
|
||||||
|
{
|
||||||
|
Thread.Sleep(1000);
|
||||||
|
Utils.StartV2RayN();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
UpgradeApp.Upgrade(argData);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,116 +2,115 @@ using System.Diagnostics;
|
||||||
using System.IO.Compression;
|
using System.IO.Compression;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
|
||||||
namespace AmazTool
|
namespace AmazTool;
|
||||||
|
|
||||||
|
internal class UpgradeApp
|
||||||
{
|
{
|
||||||
internal class UpgradeApp
|
public static void Upgrade(string fileName)
|
||||||
{
|
{
|
||||||
public static void Upgrade(string fileName)
|
Console.WriteLine($"{Resx.Resource.StartUnzipping}\n{fileName}");
|
||||||
|
|
||||||
|
Utils.Waiting(5);
|
||||||
|
|
||||||
|
if (!File.Exists(fileName))
|
||||||
{
|
{
|
||||||
Console.WriteLine($"{Resx.Resource.StartUnzipping}\n{fileName}");
|
Console.WriteLine(Resx.Resource.UpgradeFileNotFound);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
Utils.Waiting(5);
|
Console.WriteLine(Resx.Resource.TryTerminateProcess);
|
||||||
|
try
|
||||||
if (!File.Exists(fileName))
|
{
|
||||||
|
var existing = Process.GetProcessesByName(Utils.V2rayN);
|
||||||
|
foreach (var pp in existing)
|
||||||
{
|
{
|
||||||
Console.WriteLine(Resx.Resource.UpgradeFileNotFound);
|
var path = pp.MainModule?.FileName ?? "";
|
||||||
return;
|
if (path.StartsWith(Utils.GetPath(Utils.V2rayN)))
|
||||||
}
|
|
||||||
|
|
||||||
Console.WriteLine(Resx.Resource.TryTerminateProcess);
|
|
||||||
try
|
|
||||||
{
|
|
||||||
var existing = Process.GetProcessesByName(Utils.V2rayN);
|
|
||||||
foreach (var pp in existing)
|
|
||||||
{
|
{
|
||||||
var path = pp.MainModule?.FileName ?? "";
|
pp?.Kill();
|
||||||
if (path.StartsWith(Utils.GetPath(Utils.V2rayN)))
|
pp?.WaitForExit(1000);
|
||||||
{
|
|
||||||
pp?.Kill();
|
|
||||||
pp?.WaitForExit(1000);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
}
|
||||||
{
|
catch (Exception ex)
|
||||||
// Access may be denied without admin right. The user may not be an administrator.
|
{
|
||||||
Console.WriteLine(Resx.Resource.FailedTerminateProcess + ex.StackTrace);
|
// Access may be denied without admin right. The user may not be an administrator.
|
||||||
}
|
Console.WriteLine(Resx.Resource.FailedTerminateProcess + ex.StackTrace);
|
||||||
|
}
|
||||||
|
|
||||||
Console.WriteLine(Resx.Resource.StartUnzipping);
|
Console.WriteLine(Resx.Resource.StartUnzipping);
|
||||||
StringBuilder sb = new();
|
StringBuilder sb = new();
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var thisAppOldFile = $"{Utils.GetExePath()}.tmp";
|
var thisAppOldFile = $"{Utils.GetExePath()}.tmp";
|
||||||
File.Delete(thisAppOldFile);
|
File.Delete(thisAppOldFile);
|
||||||
var splitKey = "/";
|
var splitKey = "/";
|
||||||
|
|
||||||
using var archive = ZipFile.OpenRead(fileName);
|
using var archive = ZipFile.OpenRead(fileName);
|
||||||
foreach (var entry in archive.Entries)
|
foreach (var entry in archive.Entries)
|
||||||
|
{
|
||||||
|
try
|
||||||
{
|
{
|
||||||
|
if (entry.Length == 0)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
Console.WriteLine(entry.FullName);
|
||||||
|
|
||||||
|
var lst = entry.FullName.Split(splitKey);
|
||||||
|
if (lst.Length == 1)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
var fullName = string.Join(splitKey, lst[1..lst.Length]);
|
||||||
|
|
||||||
|
if (string.Equals(Utils.GetExePath(), Utils.GetPath(fullName), StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
File.Move(Utils.GetExePath(), thisAppOldFile);
|
||||||
|
}
|
||||||
|
|
||||||
|
var entryOutputPath = Utils.GetPath(fullName);
|
||||||
|
Directory.CreateDirectory(Path.GetDirectoryName(entryOutputPath)!);
|
||||||
|
//In the bin folder, if the file already exists, it will be skipped
|
||||||
|
if (fullName.StartsWith("bin") && File.Exists(entryOutputPath))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (entry.Length == 0)
|
entry.ExtractToFile(entryOutputPath, true);
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
Console.WriteLine(entry.FullName);
|
|
||||||
|
|
||||||
var lst = entry.FullName.Split(splitKey);
|
|
||||||
if (lst.Length == 1)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
var fullName = string.Join(splitKey, lst[1..lst.Length]);
|
|
||||||
|
|
||||||
if (string.Equals(Utils.GetExePath(), Utils.GetPath(fullName), StringComparison.OrdinalIgnoreCase))
|
|
||||||
{
|
|
||||||
File.Move(Utils.GetExePath(), thisAppOldFile);
|
|
||||||
}
|
|
||||||
|
|
||||||
var entryOutputPath = Utils.GetPath(fullName);
|
|
||||||
Directory.CreateDirectory(Path.GetDirectoryName(entryOutputPath)!);
|
|
||||||
//In the bin folder, if the file already exists, it will be skipped
|
|
||||||
if (fullName.StartsWith("bin") && File.Exists(entryOutputPath))
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
entry.ExtractToFile(entryOutputPath, true);
|
|
||||||
}
|
|
||||||
catch
|
|
||||||
{
|
|
||||||
Thread.Sleep(1000);
|
|
||||||
entry.ExtractToFile(entryOutputPath, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
Console.WriteLine(entryOutputPath);
|
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch
|
||||||
{
|
{
|
||||||
sb.Append(ex.StackTrace);
|
Thread.Sleep(1000);
|
||||||
|
entry.ExtractToFile(entryOutputPath, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Console.WriteLine(entryOutputPath);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
sb.Append(ex.StackTrace);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
Console.WriteLine(Resx.Resource.FailedUpgrade + ex.StackTrace);
|
|
||||||
//return;
|
|
||||||
}
|
|
||||||
if (sb.Length > 0)
|
|
||||||
{
|
|
||||||
Console.WriteLine(Resx.Resource.FailedUpgrade + sb.ToString());
|
|
||||||
//return;
|
|
||||||
}
|
|
||||||
|
|
||||||
Console.WriteLine(Resx.Resource.Restartv2rayN);
|
|
||||||
Utils.Waiting(2);
|
|
||||||
|
|
||||||
Utils.StartV2RayN();
|
|
||||||
}
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Console.WriteLine(Resx.Resource.FailedUpgrade + ex.StackTrace);
|
||||||
|
//return;
|
||||||
|
}
|
||||||
|
if (sb.Length > 0)
|
||||||
|
{
|
||||||
|
Console.WriteLine(Resx.Resource.FailedUpgrade + sb.ToString());
|
||||||
|
//return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Console.WriteLine(Resx.Resource.Restartv2rayN);
|
||||||
|
Utils.Waiting(2);
|
||||||
|
|
||||||
|
Utils.StartV2RayN();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,52 +1,51 @@
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
|
|
||||||
namespace AmazTool
|
namespace AmazTool;
|
||||||
|
|
||||||
|
internal class Utils
|
||||||
{
|
{
|
||||||
internal class Utils
|
public static string GetExePath()
|
||||||
{
|
{
|
||||||
public static string GetExePath()
|
return Environment.ProcessPath ?? Process.GetCurrentProcess().MainModule?.FileName ?? string.Empty;
|
||||||
{
|
}
|
||||||
return Environment.ProcessPath ?? Process.GetCurrentProcess().MainModule?.FileName ?? string.Empty;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static string StartupPath()
|
public static string StartupPath()
|
||||||
{
|
{
|
||||||
return AppDomain.CurrentDomain.BaseDirectory;
|
return AppDomain.CurrentDomain.BaseDirectory;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static string GetPath(string fileName)
|
public static string GetPath(string fileName)
|
||||||
|
{
|
||||||
|
var startupPath = StartupPath();
|
||||||
|
if (string.IsNullOrEmpty(fileName))
|
||||||
{
|
{
|
||||||
var startupPath = StartupPath();
|
return startupPath;
|
||||||
if (string.IsNullOrEmpty(fileName))
|
}
|
||||||
|
return Path.Combine(startupPath, fileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string V2rayN => "v2rayN";
|
||||||
|
|
||||||
|
public static void StartV2RayN()
|
||||||
|
{
|
||||||
|
Process process = new()
|
||||||
|
{
|
||||||
|
StartInfo = new()
|
||||||
{
|
{
|
||||||
return startupPath;
|
UseShellExecute = true,
|
||||||
|
FileName = V2rayN,
|
||||||
|
WorkingDirectory = StartupPath()
|
||||||
}
|
}
|
||||||
return Path.Combine(startupPath, fileName);
|
};
|
||||||
}
|
process.Start();
|
||||||
|
}
|
||||||
|
|
||||||
public static string V2rayN => "v2rayN";
|
public static void Waiting(int second)
|
||||||
|
{
|
||||||
public static void StartV2RayN()
|
for (var i = second; i > 0; i--)
|
||||||
{
|
{
|
||||||
Process process = new()
|
Console.WriteLine(i);
|
||||||
{
|
Thread.Sleep(1000);
|
||||||
StartInfo = new()
|
|
||||||
{
|
|
||||||
UseShellExecute = true,
|
|
||||||
FileName = V2rayN,
|
|
||||||
WorkingDirectory = StartupPath()
|
|
||||||
}
|
|
||||||
};
|
|
||||||
process.Start();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void Waiting(int second)
|
|
||||||
{
|
|
||||||
for (var i = second; i > 0; i--)
|
|
||||||
{
|
|
||||||
Console.WriteLine(i);
|
|
||||||
Thread.Sleep(1000);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,14 +1,14 @@
|
||||||
<Project>
|
<Project>
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<Version>7.10.5</Version>
|
<Version>7.11.0</Version>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net8.0</TargetFramework>
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
<TargetLatestRuntimePatch>true</TargetLatestRuntimePatch>
|
<TargetLatestRuntimePatch>true</TargetLatestRuntimePatch>
|
||||||
<CheckForOverflowUnderflow>true</CheckForOverflowUnderflow>
|
<CheckForOverflowUnderflow>true</CheckForOverflowUnderflow>
|
||||||
<NoWarn>CA1031;CS1591;NU1507;CA1416</NoWarn>
|
<NoWarn>CA1031;CS1591;NU1507;CA1416;IDE0058</NoWarn>
|
||||||
<Nullable>annotations</Nullable>
|
<Nullable>annotations</Nullable>
|
||||||
<ImplicitUsings>enable</ImplicitUsings>
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
<Authors>2dust</Authors>
|
<Authors>2dust</Authors>
|
||||||
|
|
|
@ -5,10 +5,10 @@
|
||||||
<CentralPackageVersionOverrideEnabled>false</CentralPackageVersionOverrideEnabled>
|
<CentralPackageVersionOverrideEnabled>false</CentralPackageVersionOverrideEnabled>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageVersion Include="Avalonia.Controls.DataGrid" Version="11.2.5" />
|
<PackageVersion Include="Avalonia.Controls.DataGrid" Version="11.2.6" />
|
||||||
<PackageVersion Include="Avalonia.Desktop" Version="11.2.5" />
|
<PackageVersion Include="Avalonia.Desktop" Version="11.2.6" />
|
||||||
<PackageVersion Include="Avalonia.Diagnostics" Version="11.2.5" />
|
<PackageVersion Include="Avalonia.Diagnostics" Version="11.2.6" />
|
||||||
<PackageVersion Include="Avalonia.ReactiveUI" Version="11.2.5" />
|
<PackageVersion Include="Avalonia.ReactiveUI" Version="11.2.6" />
|
||||||
<PackageVersion Include="CliWrap" Version="3.8.2" />
|
<PackageVersion Include="CliWrap" Version="3.8.2" />
|
||||||
<PackageVersion Include="Downloader" Version="3.3.4" />
|
<PackageVersion Include="Downloader" Version="3.3.4" />
|
||||||
<PackageVersion Include="H.NotifyIcon.Wpf" Version="2.3.0" />
|
<PackageVersion Include="H.NotifyIcon.Wpf" Version="2.3.0" />
|
||||||
|
@ -18,12 +18,12 @@
|
||||||
<PackageVersion Include="ReactiveUI" Version="20.2.45" />
|
<PackageVersion Include="ReactiveUI" Version="20.2.45" />
|
||||||
<PackageVersion Include="ReactiveUI.Fody" Version="19.5.41" />
|
<PackageVersion Include="ReactiveUI.Fody" Version="19.5.41" />
|
||||||
<PackageVersion Include="ReactiveUI.WPF" Version="20.2.45" />
|
<PackageVersion Include="ReactiveUI.WPF" Version="20.2.45" />
|
||||||
<PackageVersion Include="Semi.Avalonia" Version="11.2.1.5" />
|
<PackageVersion Include="Semi.Avalonia" Version="11.2.1.6" />
|
||||||
<PackageVersion Include="Semi.Avalonia.DataGrid" Version="11.2.1.5" />
|
<PackageVersion Include="Semi.Avalonia.DataGrid" Version="11.2.1.6" />
|
||||||
<PackageVersion Include="Splat.NLog" Version="15.3.1" />
|
<PackageVersion Include="Splat.NLog" Version="15.3.1" />
|
||||||
<PackageVersion Include="sqlite-net-pcl" Version="1.9.172" />
|
<PackageVersion Include="sqlite-net-pcl" Version="1.9.172" />
|
||||||
<PackageVersion Include="TaskScheduler" Version="2.12.1" />
|
<PackageVersion Include="TaskScheduler" Version="2.12.1" />
|
||||||
<PackageVersion Include="WebDav.Client" Version="2.8.0" />
|
<PackageVersion Include="WebDav.Client" Version="2.9.0" />
|
||||||
<PackageVersion Include="YamlDotNet" Version="16.3.0" />
|
<PackageVersion Include="YamlDotNet" Version="16.3.0" />
|
||||||
<PackageVersion Include="ZXing.Net.Bindings.SkiaSharp" Version="0.16.14" />
|
<PackageVersion Include="ZXing.Net.Bindings.SkiaSharp" Version="0.16.14" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
|
@ -1,10 +1,9 @@
|
||||||
using ReactiveUI;
|
using ReactiveUI;
|
||||||
|
|
||||||
namespace ServiceLib.Base
|
namespace ServiceLib.Base;
|
||||||
|
|
||||||
|
public class MyReactiveObject : ReactiveObject
|
||||||
{
|
{
|
||||||
public class MyReactiveObject : ReactiveObject
|
protected static Config? _config;
|
||||||
{
|
protected Func<EViewAction, object?, Task<bool>>? _updateView;
|
||||||
protected static Config? _config;
|
}
|
||||||
protected Func<EViewAction, object?, Task<bool>>? _updateView;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,101 +1,100 @@
|
||||||
using System.Security.Cryptography;
|
using System.Security.Cryptography;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
|
||||||
namespace ServiceLib.Common
|
namespace ServiceLib.Common;
|
||||||
|
|
||||||
|
public class AesUtils
|
||||||
{
|
{
|
||||||
public class AesUtils
|
private const int KeySize = 256; // AES-256
|
||||||
|
private const int IvSize = 16; // AES block size
|
||||||
|
private const int Iterations = 10000;
|
||||||
|
private static readonly byte[] Salt = Encoding.ASCII.GetBytes("saltysalt".PadRight(16, ' ')); // google浏览器默认盐值
|
||||||
|
private static readonly string DefaultPassword = Utils.GetMd5(Utils.GetHomePath() + "AesUtils");
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Encrypt
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="text">Plain text</param>
|
||||||
|
/// <param name="password">Password for key derivation or direct key in ASCII bytes</param>
|
||||||
|
/// <returns>Base64 encoded cipher text with IV</returns>
|
||||||
|
public static string Encrypt(string text, string? password = null)
|
||||||
{
|
{
|
||||||
private const int KeySize = 256; // AES-256
|
if (string.IsNullOrEmpty(text))
|
||||||
private const int IvSize = 16; // AES block size
|
return string.Empty;
|
||||||
private const int Iterations = 10000;
|
|
||||||
private static readonly byte[] Salt = Encoding.ASCII.GetBytes("saltysalt".PadRight(16, ' ')); // google浏览器默认盐值
|
|
||||||
private static readonly string DefaultPassword = Utils.GetMd5(Utils.GetHomePath() + "AesUtils");
|
|
||||||
|
|
||||||
/// <summary>
|
var plaintext = Encoding.UTF8.GetBytes(text);
|
||||||
/// Encrypt
|
var key = GetKey(password);
|
||||||
/// </summary>
|
var iv = GenerateIv();
|
||||||
/// <param name="text">Plain text</param>
|
|
||||||
/// <param name="password">Password for key derivation or direct key in ASCII bytes</param>
|
using var aes = Aes.Create();
|
||||||
/// <returns>Base64 encoded cipher text with IV</returns>
|
aes.Key = key;
|
||||||
public static string Encrypt(string text, string? password = null)
|
aes.IV = iv;
|
||||||
|
|
||||||
|
using var ms = new MemoryStream();
|
||||||
|
ms.Write(iv, 0, iv.Length);
|
||||||
|
|
||||||
|
using (var cs = new CryptoStream(ms, aes.CreateEncryptor(), CryptoStreamMode.Write))
|
||||||
{
|
{
|
||||||
if (string.IsNullOrEmpty(text))
|
cs.Write(plaintext, 0, plaintext.Length);
|
||||||
return string.Empty;
|
cs.FlushFinalBlock();
|
||||||
|
|
||||||
var plaintext = Encoding.UTF8.GetBytes(text);
|
|
||||||
var key = GetKey(password);
|
|
||||||
var iv = GenerateIv();
|
|
||||||
|
|
||||||
using var aes = Aes.Create();
|
|
||||||
aes.Key = key;
|
|
||||||
aes.IV = iv;
|
|
||||||
|
|
||||||
using var ms = new MemoryStream();
|
|
||||||
ms.Write(iv, 0, iv.Length);
|
|
||||||
|
|
||||||
using (var cs = new CryptoStream(ms, aes.CreateEncryptor(), CryptoStreamMode.Write))
|
|
||||||
{
|
|
||||||
cs.Write(plaintext, 0, plaintext.Length);
|
|
||||||
cs.FlushFinalBlock();
|
|
||||||
}
|
|
||||||
|
|
||||||
var cipherTextWithIv = ms.ToArray();
|
|
||||||
return Convert.ToBase64String(cipherTextWithIv);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
var cipherTextWithIv = ms.ToArray();
|
||||||
/// Decrypt
|
return Convert.ToBase64String(cipherTextWithIv);
|
||||||
/// </summary>
|
|
||||||
/// <param name="cipherTextWithIv">Base64 encoded cipher text with IV</param>
|
|
||||||
/// <param name="password">Password for key derivation or direct key in ASCII bytes</param>
|
|
||||||
/// <returns>Plain text</returns>
|
|
||||||
public static string Decrypt(string cipherTextWithIv, string? password = null)
|
|
||||||
{
|
|
||||||
if (string.IsNullOrEmpty(cipherTextWithIv))
|
|
||||||
return string.Empty;
|
|
||||||
|
|
||||||
var cipherTextWithIvBytes = Convert.FromBase64String(cipherTextWithIv);
|
|
||||||
var key = GetKey(password);
|
|
||||||
|
|
||||||
var iv = new byte[IvSize];
|
|
||||||
Buffer.BlockCopy(cipherTextWithIvBytes, 0, iv, 0, IvSize);
|
|
||||||
|
|
||||||
var cipherText = new byte[cipherTextWithIvBytes.Length - IvSize];
|
|
||||||
Buffer.BlockCopy(cipherTextWithIvBytes, IvSize, cipherText, 0, cipherText.Length);
|
|
||||||
|
|
||||||
using var aes = Aes.Create();
|
|
||||||
aes.Key = key;
|
|
||||||
aes.IV = iv;
|
|
||||||
|
|
||||||
using var ms = new MemoryStream();
|
|
||||||
using (var cs = new CryptoStream(ms, aes.CreateDecryptor(), CryptoStreamMode.Write))
|
|
||||||
{
|
|
||||||
cs.Write(cipherText, 0, cipherText.Length);
|
|
||||||
cs.FlushFinalBlock();
|
|
||||||
}
|
|
||||||
|
|
||||||
var plainText = ms.ToArray();
|
|
||||||
return Encoding.UTF8.GetString(plainText);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static byte[] GetKey(string? password)
|
|
||||||
{
|
|
||||||
if (password.IsNullOrEmpty())
|
|
||||||
{
|
|
||||||
password = DefaultPassword;
|
|
||||||
}
|
|
||||||
|
|
||||||
using var pbkdf2 = new Rfc2898DeriveBytes(password, Salt, Iterations, HashAlgorithmName.SHA256);
|
|
||||||
return pbkdf2.GetBytes(KeySize / 8);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static byte[] GenerateIv()
|
|
||||||
{
|
|
||||||
var randomNumber = new byte[IvSize];
|
|
||||||
|
|
||||||
using var rng = RandomNumberGenerator.Create();
|
|
||||||
rng.GetBytes(randomNumber);
|
|
||||||
return randomNumber;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
/// <summary>
|
||||||
|
/// Decrypt
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="cipherTextWithIv">Base64 encoded cipher text with IV</param>
|
||||||
|
/// <param name="password">Password for key derivation or direct key in ASCII bytes</param>
|
||||||
|
/// <returns>Plain text</returns>
|
||||||
|
public static string Decrypt(string cipherTextWithIv, string? password = null)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(cipherTextWithIv))
|
||||||
|
return string.Empty;
|
||||||
|
|
||||||
|
var cipherTextWithIvBytes = Convert.FromBase64String(cipherTextWithIv);
|
||||||
|
var key = GetKey(password);
|
||||||
|
|
||||||
|
var iv = new byte[IvSize];
|
||||||
|
Buffer.BlockCopy(cipherTextWithIvBytes, 0, iv, 0, IvSize);
|
||||||
|
|
||||||
|
var cipherText = new byte[cipherTextWithIvBytes.Length - IvSize];
|
||||||
|
Buffer.BlockCopy(cipherTextWithIvBytes, IvSize, cipherText, 0, cipherText.Length);
|
||||||
|
|
||||||
|
using var aes = Aes.Create();
|
||||||
|
aes.Key = key;
|
||||||
|
aes.IV = iv;
|
||||||
|
|
||||||
|
using var ms = new MemoryStream();
|
||||||
|
using (var cs = new CryptoStream(ms, aes.CreateDecryptor(), CryptoStreamMode.Write))
|
||||||
|
{
|
||||||
|
cs.Write(cipherText, 0, cipherText.Length);
|
||||||
|
cs.FlushFinalBlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
var plainText = ms.ToArray();
|
||||||
|
return Encoding.UTF8.GetString(plainText);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static byte[] GetKey(string? password)
|
||||||
|
{
|
||||||
|
if (password.IsNullOrEmpty())
|
||||||
|
{
|
||||||
|
password = DefaultPassword;
|
||||||
|
}
|
||||||
|
|
||||||
|
using var pbkdf2 = new Rfc2898DeriveBytes(password, Salt, Iterations, HashAlgorithmName.SHA256);
|
||||||
|
return pbkdf2.GetBytes(KeySize / 8);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static byte[] GenerateIv()
|
||||||
|
{
|
||||||
|
var randomNumber = new byte[IvSize];
|
||||||
|
|
||||||
|
using var rng = RandomNumberGenerator.Create();
|
||||||
|
rng.GetBytes(randomNumber);
|
||||||
|
return randomNumber;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -1,75 +1,74 @@
|
||||||
using System.Security.Cryptography;
|
using System.Security.Cryptography;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
|
||||||
namespace ServiceLib.Common
|
namespace ServiceLib.Common;
|
||||||
|
|
||||||
|
public class DesUtils
|
||||||
{
|
{
|
||||||
public class DesUtils
|
/// <summary>
|
||||||
|
/// Encrypt
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="text"></param>
|
||||||
|
/// /// <param name="key"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static string Encrypt(string? text, string? key = null)
|
||||||
{
|
{
|
||||||
/// <summary>
|
if (text.IsNullOrEmpty())
|
||||||
/// Encrypt
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="text"></param>
|
|
||||||
/// /// <param name="key"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
public static string Encrypt(string? text, string? key = null)
|
|
||||||
{
|
{
|
||||||
if (text.IsNullOrEmpty())
|
return string.Empty;
|
||||||
{
|
|
||||||
return string.Empty;
|
|
||||||
}
|
|
||||||
GetKeyIv(key ?? GetDefaultKey(), out var rgbKey, out var rgbIv);
|
|
||||||
var dsp = DES.Create();
|
|
||||||
using var memStream = new MemoryStream();
|
|
||||||
using var cryStream = new CryptoStream(memStream, dsp.CreateEncryptor(rgbKey, rgbIv), CryptoStreamMode.Write);
|
|
||||||
using var sWriter = new StreamWriter(cryStream);
|
|
||||||
sWriter.Write(text);
|
|
||||||
sWriter.Flush();
|
|
||||||
cryStream.FlushFinalBlock();
|
|
||||||
memStream.Flush();
|
|
||||||
return Convert.ToBase64String(memStream.GetBuffer(), 0, (int)memStream.Length);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Decrypt
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="encryptText"></param>
|
|
||||||
/// <param name="key"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
public static string Decrypt(string? encryptText, string? key = null)
|
|
||||||
{
|
|
||||||
if (encryptText.IsNullOrEmpty())
|
|
||||||
{
|
|
||||||
return string.Empty;
|
|
||||||
}
|
|
||||||
GetKeyIv(key ?? GetDefaultKey(), out var rgbKey, out var rgbIv);
|
|
||||||
var dsp = DES.Create();
|
|
||||||
var buffer = Convert.FromBase64String(encryptText);
|
|
||||||
|
|
||||||
using var memStream = new MemoryStream();
|
|
||||||
using var cryStream = new CryptoStream(memStream, dsp.CreateDecryptor(rgbKey, rgbIv), CryptoStreamMode.Write);
|
|
||||||
cryStream.Write(buffer, 0, buffer.Length);
|
|
||||||
cryStream.FlushFinalBlock();
|
|
||||||
return Encoding.UTF8.GetString(memStream.ToArray());
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void GetKeyIv(string key, out byte[] rgbKey, out byte[] rgbIv)
|
|
||||||
{
|
|
||||||
if (key.IsNullOrEmpty())
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException("The key cannot be null");
|
|
||||||
}
|
|
||||||
if (key.Length <= 8)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException("The key length cannot be less than 8 characters.");
|
|
||||||
}
|
|
||||||
|
|
||||||
rgbKey = Encoding.ASCII.GetBytes(key.Substring(0, 8));
|
|
||||||
rgbIv = Encoding.ASCII.GetBytes(key.Insert(0, "w").Substring(0, 8));
|
|
||||||
}
|
|
||||||
|
|
||||||
private static string GetDefaultKey()
|
|
||||||
{
|
|
||||||
return Utils.GetMd5(Utils.GetHomePath() + "DesUtils");
|
|
||||||
}
|
}
|
||||||
|
GetKeyIv(key ?? GetDefaultKey(), out var rgbKey, out var rgbIv);
|
||||||
|
var dsp = DES.Create();
|
||||||
|
using var memStream = new MemoryStream();
|
||||||
|
using var cryStream = new CryptoStream(memStream, dsp.CreateEncryptor(rgbKey, rgbIv), CryptoStreamMode.Write);
|
||||||
|
using var sWriter = new StreamWriter(cryStream);
|
||||||
|
sWriter.Write(text);
|
||||||
|
sWriter.Flush();
|
||||||
|
cryStream.FlushFinalBlock();
|
||||||
|
memStream.Flush();
|
||||||
|
return Convert.ToBase64String(memStream.GetBuffer(), 0, (int)memStream.Length);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
/// <summary>
|
||||||
|
/// Decrypt
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="encryptText"></param>
|
||||||
|
/// <param name="key"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static string Decrypt(string? encryptText, string? key = null)
|
||||||
|
{
|
||||||
|
if (encryptText.IsNullOrEmpty())
|
||||||
|
{
|
||||||
|
return string.Empty;
|
||||||
|
}
|
||||||
|
GetKeyIv(key ?? GetDefaultKey(), out var rgbKey, out var rgbIv);
|
||||||
|
var dsp = DES.Create();
|
||||||
|
var buffer = Convert.FromBase64String(encryptText);
|
||||||
|
|
||||||
|
using var memStream = new MemoryStream();
|
||||||
|
using var cryStream = new CryptoStream(memStream, dsp.CreateDecryptor(rgbKey, rgbIv), CryptoStreamMode.Write);
|
||||||
|
cryStream.Write(buffer, 0, buffer.Length);
|
||||||
|
cryStream.FlushFinalBlock();
|
||||||
|
return Encoding.UTF8.GetString(memStream.ToArray());
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void GetKeyIv(string key, out byte[] rgbKey, out byte[] rgbIv)
|
||||||
|
{
|
||||||
|
if (key.IsNullOrEmpty())
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException("The key cannot be null");
|
||||||
|
}
|
||||||
|
if (key.Length <= 8)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException("The key length cannot be less than 8 characters.");
|
||||||
|
}
|
||||||
|
|
||||||
|
rgbKey = Encoding.ASCII.GetBytes(key.Substring(0, 8));
|
||||||
|
rgbIv = Encoding.ASCII.GetBytes(key.Insert(0, "w").Substring(0, 8));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string GetDefaultKey()
|
||||||
|
{
|
||||||
|
return Utils.GetMd5(Utils.GetHomePath() + "DesUtils");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -1,181 +1,180 @@
|
||||||
using System.Net;
|
using System.Net;
|
||||||
using Downloader;
|
using Downloader;
|
||||||
|
|
||||||
namespace ServiceLib.Common
|
namespace ServiceLib.Common;
|
||||||
|
|
||||||
|
public class DownloaderHelper
|
||||||
{
|
{
|
||||||
public class DownloaderHelper
|
private static readonly Lazy<DownloaderHelper> _instance = new(() => new());
|
||||||
|
public static DownloaderHelper Instance => _instance.Value;
|
||||||
|
|
||||||
|
public async Task<string?> DownloadStringAsync(IWebProxy? webProxy, string url, string? userAgent, int timeout)
|
||||||
{
|
{
|
||||||
private static readonly Lazy<DownloaderHelper> _instance = new(() => new());
|
if (url.IsNullOrEmpty())
|
||||||
public static DownloaderHelper Instance => _instance.Value;
|
|
||||||
|
|
||||||
public async Task<string?> DownloadStringAsync(IWebProxy? webProxy, string url, string? userAgent, int timeout)
|
|
||||||
{
|
{
|
||||||
if (url.IsNullOrEmpty())
|
return null;
|
||||||
{
|
}
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
Uri uri = new(url);
|
Uri uri = new(url);
|
||||||
//Authorization Header
|
//Authorization Header
|
||||||
var headers = new WebHeaderCollection();
|
var headers = new WebHeaderCollection();
|
||||||
if (uri.UserInfo.IsNotEmpty())
|
if (uri.UserInfo.IsNotEmpty())
|
||||||
{
|
{
|
||||||
headers.Add(HttpRequestHeader.Authorization, "Basic " + Utils.Base64Encode(uri.UserInfo));
|
headers.Add(HttpRequestHeader.Authorization, "Basic " + Utils.Base64Encode(uri.UserInfo));
|
||||||
}
|
}
|
||||||
|
|
||||||
var downloadOpt = new DownloadConfiguration()
|
var downloadOpt = new DownloadConfiguration()
|
||||||
{
|
{
|
||||||
Timeout = timeout * 1000,
|
Timeout = timeout * 1000,
|
||||||
MaxTryAgainOnFailover = 2,
|
MaxTryAgainOnFailover = 2,
|
||||||
RequestConfiguration =
|
RequestConfiguration =
|
||||||
{
|
{
|
||||||
Headers = headers,
|
Headers = headers,
|
||||||
UserAgent = userAgent,
|
UserAgent = userAgent,
|
||||||
Timeout = timeout * 1000,
|
Timeout = timeout * 1000,
|
||||||
Proxy = webProxy
|
Proxy = webProxy
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
await using var downloader = new Downloader.DownloadService(downloadOpt);
|
await using var downloader = new Downloader.DownloadService(downloadOpt);
|
||||||
downloader.DownloadFileCompleted += (sender, value) =>
|
downloader.DownloadFileCompleted += (sender, value) =>
|
||||||
|
{
|
||||||
|
if (value.Error != null)
|
||||||
{
|
{
|
||||||
if (value.Error != null)
|
throw value.Error;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
using var cts = new CancellationTokenSource();
|
||||||
|
await using var stream = await downloader.DownloadFileTaskAsync(address: url, cts.Token).WaitAsync(TimeSpan.FromSeconds(timeout), cts.Token);
|
||||||
|
using StreamReader reader = new(stream);
|
||||||
|
|
||||||
|
downloadOpt = null;
|
||||||
|
|
||||||
|
return await reader.ReadToEndAsync(cts.Token);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task DownloadDataAsync4Speed(IWebProxy webProxy, string url, IProgress<string> progress, int timeout)
|
||||||
|
{
|
||||||
|
if (url.IsNullOrEmpty())
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(url));
|
||||||
|
}
|
||||||
|
|
||||||
|
var downloadOpt = new DownloadConfiguration()
|
||||||
|
{
|
||||||
|
Timeout = timeout * 1000,
|
||||||
|
MaxTryAgainOnFailover = 2,
|
||||||
|
RequestConfiguration =
|
||||||
|
{
|
||||||
|
Timeout= timeout * 1000,
|
||||||
|
Proxy = webProxy
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
var totalDatetime = DateTime.Now;
|
||||||
|
var totalSecond = 0;
|
||||||
|
var hasValue = false;
|
||||||
|
double maxSpeed = 0;
|
||||||
|
await using var downloader = new Downloader.DownloadService(downloadOpt);
|
||||||
|
//downloader.DownloadStarted += (sender, value) =>
|
||||||
|
//{
|
||||||
|
// if (progress != null)
|
||||||
|
// {
|
||||||
|
// progress.Report("Start download data...");
|
||||||
|
// }
|
||||||
|
//};
|
||||||
|
downloader.DownloadProgressChanged += (sender, value) =>
|
||||||
|
{
|
||||||
|
var ts = DateTime.Now - totalDatetime;
|
||||||
|
if (progress != null && ts.Seconds > totalSecond)
|
||||||
|
{
|
||||||
|
hasValue = true;
|
||||||
|
totalSecond = ts.Seconds;
|
||||||
|
if (value.BytesPerSecondSpeed > maxSpeed)
|
||||||
|
{
|
||||||
|
maxSpeed = value.BytesPerSecondSpeed;
|
||||||
|
var speed = (maxSpeed / 1000 / 1000).ToString("#0.0");
|
||||||
|
progress.Report(speed);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
downloader.DownloadFileCompleted += (sender, value) =>
|
||||||
|
{
|
||||||
|
if (progress != null)
|
||||||
|
{
|
||||||
|
if (!hasValue && value.Error != null)
|
||||||
|
{
|
||||||
|
progress.Report(value.Error?.Message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
//progress.Report("......");
|
||||||
|
using var cts = new CancellationTokenSource();
|
||||||
|
cts.CancelAfter(timeout * 1000);
|
||||||
|
await using var stream = await downloader.DownloadFileTaskAsync(address: url, cts.Token);
|
||||||
|
|
||||||
|
downloadOpt = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task DownloadFileAsync(IWebProxy? webProxy, string url, string fileName, IProgress<double> progress, int timeout)
|
||||||
|
{
|
||||||
|
if (url.IsNullOrEmpty())
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(url));
|
||||||
|
}
|
||||||
|
if (fileName.IsNullOrEmpty())
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(fileName));
|
||||||
|
}
|
||||||
|
if (File.Exists(fileName))
|
||||||
|
{
|
||||||
|
File.Delete(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
var downloadOpt = new DownloadConfiguration()
|
||||||
|
{
|
||||||
|
Timeout = timeout * 1000,
|
||||||
|
MaxTryAgainOnFailover = 2,
|
||||||
|
RequestConfiguration =
|
||||||
|
{
|
||||||
|
Timeout= timeout * 1000,
|
||||||
|
Proxy = webProxy
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
var progressPercentage = 0;
|
||||||
|
var hasValue = false;
|
||||||
|
await using var downloader = new Downloader.DownloadService(downloadOpt);
|
||||||
|
downloader.DownloadStarted += (sender, value) => progress?.Report(0);
|
||||||
|
downloader.DownloadProgressChanged += (sender, value) =>
|
||||||
|
{
|
||||||
|
hasValue = true;
|
||||||
|
var percent = (int)value.ProgressPercentage;// Convert.ToInt32((totalRead * 1d) / (total * 1d) * 100);
|
||||||
|
if (progressPercentage != percent && percent % 10 == 0)
|
||||||
|
{
|
||||||
|
progressPercentage = percent;
|
||||||
|
progress.Report(percent);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
downloader.DownloadFileCompleted += (sender, value) =>
|
||||||
|
{
|
||||||
|
if (progress != null)
|
||||||
|
{
|
||||||
|
if (hasValue && value.Error == null)
|
||||||
|
{
|
||||||
|
progress.Report(101);
|
||||||
|
}
|
||||||
|
else if (value.Error != null)
|
||||||
{
|
{
|
||||||
throw value.Error;
|
throw value.Error;
|
||||||
}
|
}
|
||||||
};
|
|
||||||
|
|
||||||
using var cts = new CancellationTokenSource();
|
|
||||||
await using var stream = await downloader.DownloadFileTaskAsync(address: url, cts.Token).WaitAsync(TimeSpan.FromSeconds(timeout), cts.Token);
|
|
||||||
using StreamReader reader = new(stream);
|
|
||||||
|
|
||||||
downloadOpt = null;
|
|
||||||
|
|
||||||
return await reader.ReadToEndAsync(cts.Token);
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task DownloadDataAsync4Speed(IWebProxy webProxy, string url, IProgress<string> progress, int timeout)
|
|
||||||
{
|
|
||||||
if (url.IsNullOrEmpty())
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException(nameof(url));
|
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
var downloadOpt = new DownloadConfiguration()
|
using var cts = new CancellationTokenSource();
|
||||||
{
|
await downloader.DownloadFileTaskAsync(url, fileName, cts.Token);
|
||||||
Timeout = timeout * 1000,
|
|
||||||
MaxTryAgainOnFailover = 2,
|
|
||||||
RequestConfiguration =
|
|
||||||
{
|
|
||||||
Timeout= timeout * 1000,
|
|
||||||
Proxy = webProxy
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
var totalDatetime = DateTime.Now;
|
downloadOpt = null;
|
||||||
var totalSecond = 0;
|
|
||||||
var hasValue = false;
|
|
||||||
double maxSpeed = 0;
|
|
||||||
await using var downloader = new Downloader.DownloadService(downloadOpt);
|
|
||||||
//downloader.DownloadStarted += (sender, value) =>
|
|
||||||
//{
|
|
||||||
// if (progress != null)
|
|
||||||
// {
|
|
||||||
// progress.Report("Start download data...");
|
|
||||||
// }
|
|
||||||
//};
|
|
||||||
downloader.DownloadProgressChanged += (sender, value) =>
|
|
||||||
{
|
|
||||||
var ts = DateTime.Now - totalDatetime;
|
|
||||||
if (progress != null && ts.Seconds > totalSecond)
|
|
||||||
{
|
|
||||||
hasValue = true;
|
|
||||||
totalSecond = ts.Seconds;
|
|
||||||
if (value.BytesPerSecondSpeed > maxSpeed)
|
|
||||||
{
|
|
||||||
maxSpeed = value.BytesPerSecondSpeed;
|
|
||||||
var speed = (maxSpeed / 1000 / 1000).ToString("#0.0");
|
|
||||||
progress.Report(speed);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
downloader.DownloadFileCompleted += (sender, value) =>
|
|
||||||
{
|
|
||||||
if (progress != null)
|
|
||||||
{
|
|
||||||
if (!hasValue && value.Error != null)
|
|
||||||
{
|
|
||||||
progress.Report(value.Error?.Message);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
//progress.Report("......");
|
|
||||||
using var cts = new CancellationTokenSource();
|
|
||||||
cts.CancelAfter(timeout * 1000);
|
|
||||||
await using var stream = await downloader.DownloadFileTaskAsync(address: url, cts.Token);
|
|
||||||
|
|
||||||
downloadOpt = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task DownloadFileAsync(IWebProxy? webProxy, string url, string fileName, IProgress<double> progress, int timeout)
|
|
||||||
{
|
|
||||||
if (url.IsNullOrEmpty())
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException(nameof(url));
|
|
||||||
}
|
|
||||||
if (fileName.IsNullOrEmpty())
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException(nameof(fileName));
|
|
||||||
}
|
|
||||||
if (File.Exists(fileName))
|
|
||||||
{
|
|
||||||
File.Delete(fileName);
|
|
||||||
}
|
|
||||||
|
|
||||||
var downloadOpt = new DownloadConfiguration()
|
|
||||||
{
|
|
||||||
Timeout = timeout * 1000,
|
|
||||||
MaxTryAgainOnFailover = 2,
|
|
||||||
RequestConfiguration =
|
|
||||||
{
|
|
||||||
Timeout= timeout * 1000,
|
|
||||||
Proxy = webProxy
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
var progressPercentage = 0;
|
|
||||||
var hasValue = false;
|
|
||||||
await using var downloader = new Downloader.DownloadService(downloadOpt);
|
|
||||||
downloader.DownloadStarted += (sender, value) => progress?.Report(0);
|
|
||||||
downloader.DownloadProgressChanged += (sender, value) =>
|
|
||||||
{
|
|
||||||
hasValue = true;
|
|
||||||
var percent = (int)value.ProgressPercentage;// Convert.ToInt32((totalRead * 1d) / (total * 1d) * 100);
|
|
||||||
if (progressPercentage != percent && percent % 10 == 0)
|
|
||||||
{
|
|
||||||
progressPercentage = percent;
|
|
||||||
progress.Report(percent);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
downloader.DownloadFileCompleted += (sender, value) =>
|
|
||||||
{
|
|
||||||
if (progress != null)
|
|
||||||
{
|
|
||||||
if (hasValue && value.Error == null)
|
|
||||||
{
|
|
||||||
progress.Report(101);
|
|
||||||
}
|
|
||||||
else if (value.Error != null)
|
|
||||||
{
|
|
||||||
throw value.Error;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
using var cts = new CancellationTokenSource();
|
|
||||||
await downloader.DownloadFileTaskAsync(url, fileName, cts.Token);
|
|
||||||
|
|
||||||
downloadOpt = null;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,226 +2,225 @@ using System.Formats.Tar;
|
||||||
using System.IO.Compression;
|
using System.IO.Compression;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
|
||||||
namespace ServiceLib.Common
|
namespace ServiceLib.Common;
|
||||||
{
|
|
||||||
public static class FileManager
|
|
||||||
{
|
|
||||||
private static readonly string _tag = "FileManager";
|
|
||||||
|
|
||||||
public static bool ByteArrayToFile(string fileName, byte[] content)
|
public static class FileManager
|
||||||
|
{
|
||||||
|
private static readonly string _tag = "FileManager";
|
||||||
|
|
||||||
|
public static bool ByteArrayToFile(string fileName, byte[] content)
|
||||||
|
{
|
||||||
|
try
|
||||||
{
|
{
|
||||||
try
|
File.WriteAllBytes(fileName, content);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Logging.SaveLog(_tag, ex);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void DecompressFile(string fileName, byte[] content)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
using var fs = File.Create(fileName);
|
||||||
|
using GZipStream input = new(new MemoryStream(content), CompressionMode.Decompress, false);
|
||||||
|
input.CopyTo(fs);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Logging.SaveLog(_tag, ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void DecompressFile(string fileName, string toPath, string? toName)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
FileInfo fileInfo = new(fileName);
|
||||||
|
using var originalFileStream = fileInfo.OpenRead();
|
||||||
|
using var decompressedFileStream = File.Create(toName != null ? Path.Combine(toPath, toName) : toPath);
|
||||||
|
using GZipStream decompressionStream = new(originalFileStream, CompressionMode.Decompress);
|
||||||
|
decompressionStream.CopyTo(decompressedFileStream);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Logging.SaveLog(_tag, ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void DecompressTarFile(string fileName, string toPath)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
using var fs = new FileStream(fileName, FileMode.Open, FileAccess.Read);
|
||||||
|
using var gz = new GZipStream(fs, CompressionMode.Decompress, leaveOpen: true);
|
||||||
|
TarFile.ExtractToDirectory(gz, toPath, overwriteFiles: true);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Logging.SaveLog(_tag, ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string NonExclusiveReadAllText(string path)
|
||||||
|
{
|
||||||
|
return NonExclusiveReadAllText(path, Encoding.Default);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string NonExclusiveReadAllText(string path, Encoding encoding)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
using FileStream fs = new(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
|
||||||
|
using StreamReader sr = new(fs, encoding);
|
||||||
|
return sr.ReadToEnd();
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Logging.SaveLog(_tag, ex);
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool ZipExtractToFile(string fileName, string toPath, string ignoredName)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
using var archive = ZipFile.OpenRead(fileName);
|
||||||
|
foreach (var entry in archive.Entries)
|
||||||
{
|
{
|
||||||
File.WriteAllBytes(fileName, content);
|
if (entry.Length == 0)
|
||||||
return true;
|
{
|
||||||
}
|
continue;
|
||||||
catch (Exception ex)
|
}
|
||||||
{
|
try
|
||||||
Logging.SaveLog(_tag, ex);
|
{
|
||||||
|
if (ignoredName.IsNotEmpty() && entry.Name.Contains(ignoredName))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
entry.ExtractToFile(Path.Combine(toPath, entry.Name), true);
|
||||||
|
}
|
||||||
|
catch (IOException ex)
|
||||||
|
{
|
||||||
|
Logging.SaveLog(_tag, ex);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Logging.SaveLog(_tag, ex);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
public static void DecompressFile(string fileName, byte[] content)
|
public static List<string>? GetFilesFromZip(string fileName)
|
||||||
|
{
|
||||||
|
if (!File.Exists(fileName))
|
||||||
{
|
{
|
||||||
try
|
return null;
|
||||||
|
}
|
||||||
|
try
|
||||||
|
{
|
||||||
|
using var archive = ZipFile.OpenRead(fileName);
|
||||||
|
return archive.Entries.Select(entry => entry.FullName).ToList();
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Logging.SaveLog(_tag, ex);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool CreateFromDirectory(string sourceDirectoryName, string destinationArchiveFileName)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (File.Exists(destinationArchiveFileName))
|
||||||
{
|
{
|
||||||
using var fs = File.Create(fileName);
|
File.Delete(destinationArchiveFileName);
|
||||||
using GZipStream input = new(new MemoryStream(content), CompressionMode.Decompress, false);
|
|
||||||
input.CopyTo(fs);
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
Logging.SaveLog(_tag, ex);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ZipFile.CreateFromDirectory(sourceDirectoryName, destinationArchiveFileName, CompressionLevel.SmallestSize, true);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Logging.SaveLog(_tag, ex);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void CopyDirectory(string sourceDir, string destinationDir, bool recursive, bool overwrite, string? ignoredName = null)
|
||||||
|
{
|
||||||
|
// Get information about the source directory
|
||||||
|
var dir = new DirectoryInfo(sourceDir);
|
||||||
|
|
||||||
|
// Check if the source directory exists
|
||||||
|
if (!dir.Exists)
|
||||||
|
{
|
||||||
|
throw new DirectoryNotFoundException($"Source directory not found: {dir.FullName}");
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void DecompressFile(string fileName, string toPath, string? toName)
|
// Cache directories before we start copying
|
||||||
|
var dirs = dir.GetDirectories();
|
||||||
|
|
||||||
|
// Create the destination directory
|
||||||
|
_ = Directory.CreateDirectory(destinationDir);
|
||||||
|
|
||||||
|
// Get the files in the source directory and copy to the destination directory
|
||||||
|
foreach (var file in dir.GetFiles())
|
||||||
{
|
{
|
||||||
try
|
if (ignoredName.IsNotEmpty() && file.Name.Contains(ignoredName))
|
||||||
{
|
{
|
||||||
FileInfo fileInfo = new(fileName);
|
continue;
|
||||||
using var originalFileStream = fileInfo.OpenRead();
|
|
||||||
using var decompressedFileStream = File.Create(toName != null ? Path.Combine(toPath, toName) : toPath);
|
|
||||||
using GZipStream decompressionStream = new(originalFileStream, CompressionMode.Decompress);
|
|
||||||
decompressionStream.CopyTo(decompressedFileStream);
|
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
if (file.Extension == file.Name)
|
||||||
{
|
{
|
||||||
Logging.SaveLog(_tag, ex);
|
continue;
|
||||||
}
|
}
|
||||||
|
var targetFilePath = Path.Combine(destinationDir, file.Name);
|
||||||
|
if (!overwrite && File.Exists(targetFilePath))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
_ = file.CopyTo(targetFilePath, overwrite);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void DecompressTarFile(string fileName, string toPath)
|
// If recursive and copying subdirectories, recursively call this method
|
||||||
|
if (recursive)
|
||||||
{
|
{
|
||||||
try
|
foreach (var subDir in dirs)
|
||||||
{
|
{
|
||||||
using var fs = new FileStream(fileName, FileMode.Open, FileAccess.Read);
|
var newDestinationDir = Path.Combine(destinationDir, subDir.Name);
|
||||||
using var gz = new GZipStream(fs, CompressionMode.Decompress, leaveOpen: true);
|
CopyDirectory(subDir.FullName, newDestinationDir, true, overwrite, ignoredName);
|
||||||
TarFile.ExtractToDirectory(gz, toPath, overwriteFiles: true);
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
Logging.SaveLog(_tag, ex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static string NonExclusiveReadAllText(string path)
|
|
||||||
{
|
|
||||||
return NonExclusiveReadAllText(path, Encoding.Default);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static string NonExclusiveReadAllText(string path, Encoding encoding)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
using FileStream fs = new(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
|
|
||||||
using StreamReader sr = new(fs, encoding);
|
|
||||||
return sr.ReadToEnd();
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
Logging.SaveLog(_tag, ex);
|
|
||||||
throw;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static bool ZipExtractToFile(string fileName, string toPath, string ignoredName)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
using var archive = ZipFile.OpenRead(fileName);
|
|
||||||
foreach (var entry in archive.Entries)
|
|
||||||
{
|
|
||||||
if (entry.Length == 0)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
try
|
|
||||||
{
|
|
||||||
if (ignoredName.IsNotEmpty() && entry.Name.Contains(ignoredName))
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
entry.ExtractToFile(Path.Combine(toPath, entry.Name), true);
|
|
||||||
}
|
|
||||||
catch (IOException ex)
|
|
||||||
{
|
|
||||||
Logging.SaveLog(_tag, ex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
Logging.SaveLog(_tag, ex);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static List<string>? GetFilesFromZip(string fileName)
|
|
||||||
{
|
|
||||||
if (!File.Exists(fileName))
|
|
||||||
{
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
try
|
|
||||||
{
|
|
||||||
using var archive = ZipFile.OpenRead(fileName);
|
|
||||||
return archive.Entries.Select(entry => entry.FullName).ToList();
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
Logging.SaveLog(_tag, ex);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static bool CreateFromDirectory(string sourceDirectoryName, string destinationArchiveFileName)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
if (File.Exists(destinationArchiveFileName))
|
|
||||||
{
|
|
||||||
File.Delete(destinationArchiveFileName);
|
|
||||||
}
|
|
||||||
|
|
||||||
ZipFile.CreateFromDirectory(sourceDirectoryName, destinationArchiveFileName, CompressionLevel.SmallestSize, true);
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
Logging.SaveLog(_tag, ex);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void CopyDirectory(string sourceDir, string destinationDir, bool recursive, bool overwrite, string? ignoredName = null)
|
|
||||||
{
|
|
||||||
// Get information about the source directory
|
|
||||||
var dir = new DirectoryInfo(sourceDir);
|
|
||||||
|
|
||||||
// Check if the source directory exists
|
|
||||||
if (!dir.Exists)
|
|
||||||
{
|
|
||||||
throw new DirectoryNotFoundException($"Source directory not found: {dir.FullName}");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Cache directories before we start copying
|
|
||||||
var dirs = dir.GetDirectories();
|
|
||||||
|
|
||||||
// Create the destination directory
|
|
||||||
_ = Directory.CreateDirectory(destinationDir);
|
|
||||||
|
|
||||||
// Get the files in the source directory and copy to the destination directory
|
|
||||||
foreach (var file in dir.GetFiles())
|
|
||||||
{
|
|
||||||
if (ignoredName.IsNotEmpty() && file.Name.Contains(ignoredName))
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (file.Extension == file.Name)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
var targetFilePath = Path.Combine(destinationDir, file.Name);
|
|
||||||
if (!overwrite && File.Exists(targetFilePath))
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
_ = file.CopyTo(targetFilePath, overwrite);
|
|
||||||
}
|
|
||||||
|
|
||||||
// If recursive and copying subdirectories, recursively call this method
|
|
||||||
if (recursive)
|
|
||||||
{
|
|
||||||
foreach (var subDir in dirs)
|
|
||||||
{
|
|
||||||
var newDestinationDir = Path.Combine(destinationDir, subDir.Name);
|
|
||||||
CopyDirectory(subDir.FullName, newDestinationDir, true, overwrite, ignoredName);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void DeleteExpiredFiles(string sourceDir, DateTime dtLine)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
var files = Directory.GetFiles(sourceDir, "*.*");
|
|
||||||
foreach (var filePath in files)
|
|
||||||
{
|
|
||||||
var file = new FileInfo(filePath);
|
|
||||||
if (file.CreationTime >= dtLine)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
file.Delete();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch
|
|
||||||
{
|
|
||||||
// ignored
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void DeleteExpiredFiles(string sourceDir, DateTime dtLine)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var files = Directory.GetFiles(sourceDir, "*.*");
|
||||||
|
foreach (var filePath in files)
|
||||||
|
{
|
||||||
|
var file = new FileInfo(filePath);
|
||||||
|
if (file.CreationTime >= dtLine)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
file.Delete();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
// ignored
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,205 +2,204 @@ using System.Net.Http.Headers;
|
||||||
using System.Net.Mime;
|
using System.Net.Mime;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
|
||||||
namespace ServiceLib.Common
|
namespace ServiceLib.Common;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// </summary>
|
||||||
|
public class HttpClientHelper
|
||||||
{
|
{
|
||||||
/// <summary>
|
private static readonly Lazy<HttpClientHelper> _instance = new(() =>
|
||||||
/// </summary>
|
|
||||||
public class HttpClientHelper
|
|
||||||
{
|
{
|
||||||
private static readonly Lazy<HttpClientHelper> _instance = new(() =>
|
SocketsHttpHandler handler = new() { UseCookies = false };
|
||||||
{
|
HttpClientHelper helper = new(new HttpClient(handler));
|
||||||
SocketsHttpHandler handler = new() { UseCookies = false };
|
return helper;
|
||||||
HttpClientHelper helper = new(new HttpClient(handler));
|
});
|
||||||
return helper;
|
|
||||||
});
|
|
||||||
|
|
||||||
public static HttpClientHelper Instance => _instance.Value;
|
public static HttpClientHelper Instance => _instance.Value;
|
||||||
private readonly HttpClient httpClient;
|
private readonly HttpClient httpClient;
|
||||||
|
|
||||||
private HttpClientHelper(HttpClient httpClient)
|
private HttpClientHelper(HttpClient httpClient)
|
||||||
|
{
|
||||||
|
this.httpClient = httpClient;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<string?> TryGetAsync(string url)
|
||||||
|
{
|
||||||
|
if (url.IsNullOrEmpty())
|
||||||
{
|
{
|
||||||
this.httpClient = httpClient;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<string?> TryGetAsync(string url)
|
try
|
||||||
{
|
{
|
||||||
if (url.IsNullOrEmpty())
|
var response = await httpClient.GetAsync(url);
|
||||||
{
|
return await response.Content.ReadAsStringAsync();
|
||||||
return null;
|
}
|
||||||
}
|
catch
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
try
|
public async Task<string?> GetAsync(string url)
|
||||||
{
|
{
|
||||||
var response = await httpClient.GetAsync(url);
|
if (url.IsNullOrEmpty())
|
||||||
return await response.Content.ReadAsStringAsync();
|
{
|
||||||
}
|
return null;
|
||||||
catch
|
}
|
||||||
{
|
return await httpClient.GetStringAsync(url);
|
||||||
return null;
|
}
|
||||||
}
|
|
||||||
|
public async Task<string?> GetAsync(HttpClient client, string url, CancellationToken token = default)
|
||||||
|
{
|
||||||
|
if (url.IsNullOrEmpty())
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return await client.GetStringAsync(url, token);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task PutAsync(string url, Dictionary<string, string> headers)
|
||||||
|
{
|
||||||
|
var jsonContent = JsonUtils.Serialize(headers);
|
||||||
|
var content = new StringContent(jsonContent, Encoding.UTF8, MediaTypeNames.Application.Json);
|
||||||
|
|
||||||
|
await httpClient.PutAsync(url, content);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task PatchAsync(string url, Dictionary<string, string> headers)
|
||||||
|
{
|
||||||
|
var myContent = JsonUtils.Serialize(headers);
|
||||||
|
var buffer = Encoding.UTF8.GetBytes(myContent);
|
||||||
|
var byteContent = new ByteArrayContent(buffer);
|
||||||
|
byteContent.Headers.ContentType = new MediaTypeHeaderValue("application/json");
|
||||||
|
|
||||||
|
await httpClient.PatchAsync(url, byteContent);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task DeleteAsync(string url)
|
||||||
|
{
|
||||||
|
await httpClient.DeleteAsync(url);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static async Task DownloadFileAsync(HttpClient client, string url, string fileName, IProgress<double>? progress, CancellationToken token = default)
|
||||||
|
{
|
||||||
|
ArgumentNullException.ThrowIfNull(url);
|
||||||
|
ArgumentNullException.ThrowIfNull(fileName);
|
||||||
|
if (File.Exists(fileName))
|
||||||
|
{
|
||||||
|
File.Delete(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<string?> GetAsync(string url)
|
using var response = await client.GetAsync(url, HttpCompletionOption.ResponseHeadersRead, token);
|
||||||
|
|
||||||
|
if (!response.IsSuccessStatusCode)
|
||||||
{
|
{
|
||||||
if (url.IsNullOrEmpty())
|
throw new Exception(response.StatusCode.ToString());
|
||||||
{
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
return await httpClient.GetStringAsync(url);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<string?> GetAsync(HttpClient client, string url, CancellationToken token = default)
|
var total = response.Content.Headers.ContentLength ?? -1L;
|
||||||
|
var canReportProgress = total != -1 && progress != null;
|
||||||
|
|
||||||
|
await using var stream = await response.Content.ReadAsStreamAsync(token);
|
||||||
|
await using var file = File.Create(fileName);
|
||||||
|
var totalRead = 0L;
|
||||||
|
var buffer = new byte[1024 * 1024];
|
||||||
|
var progressPercentage = 0;
|
||||||
|
|
||||||
|
while (true)
|
||||||
{
|
{
|
||||||
if (url.IsNullOrEmpty())
|
token.ThrowIfCancellationRequested();
|
||||||
|
|
||||||
|
var read = await stream.ReadAsync(buffer, token);
|
||||||
|
totalRead += read;
|
||||||
|
|
||||||
|
if (read == 0)
|
||||||
{
|
{
|
||||||
return null;
|
break;
|
||||||
}
|
}
|
||||||
return await client.GetStringAsync(url, token);
|
await file.WriteAsync(buffer.AsMemory(0, read), token);
|
||||||
}
|
|
||||||
|
|
||||||
public async Task PutAsync(string url, Dictionary<string, string> headers)
|
|
||||||
{
|
|
||||||
var jsonContent = JsonUtils.Serialize(headers);
|
|
||||||
var content = new StringContent(jsonContent, Encoding.UTF8, MediaTypeNames.Application.Json);
|
|
||||||
|
|
||||||
await httpClient.PutAsync(url, content);
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task PatchAsync(string url, Dictionary<string, string> headers)
|
|
||||||
{
|
|
||||||
var myContent = JsonUtils.Serialize(headers);
|
|
||||||
var buffer = Encoding.UTF8.GetBytes(myContent);
|
|
||||||
var byteContent = new ByteArrayContent(buffer);
|
|
||||||
byteContent.Headers.ContentType = new MediaTypeHeaderValue("application/json");
|
|
||||||
|
|
||||||
await httpClient.PatchAsync(url, byteContent);
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task DeleteAsync(string url)
|
|
||||||
{
|
|
||||||
await httpClient.DeleteAsync(url);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static async Task DownloadFileAsync(HttpClient client, string url, string fileName, IProgress<double>? progress, CancellationToken token = default)
|
|
||||||
{
|
|
||||||
ArgumentNullException.ThrowIfNull(url);
|
|
||||||
ArgumentNullException.ThrowIfNull(fileName);
|
|
||||||
if (File.Exists(fileName))
|
|
||||||
{
|
|
||||||
File.Delete(fileName);
|
|
||||||
}
|
|
||||||
|
|
||||||
using var response = await client.GetAsync(url, HttpCompletionOption.ResponseHeadersRead, token);
|
|
||||||
|
|
||||||
if (!response.IsSuccessStatusCode)
|
|
||||||
{
|
|
||||||
throw new Exception(response.StatusCode.ToString());
|
|
||||||
}
|
|
||||||
|
|
||||||
var total = response.Content.Headers.ContentLength ?? -1L;
|
|
||||||
var canReportProgress = total != -1 && progress != null;
|
|
||||||
|
|
||||||
await using var stream = await response.Content.ReadAsStreamAsync(token);
|
|
||||||
await using var file = File.Create(fileName);
|
|
||||||
var totalRead = 0L;
|
|
||||||
var buffer = new byte[1024 * 1024];
|
|
||||||
var progressPercentage = 0;
|
|
||||||
|
|
||||||
while (true)
|
|
||||||
{
|
|
||||||
token.ThrowIfCancellationRequested();
|
|
||||||
|
|
||||||
var read = await stream.ReadAsync(buffer, token);
|
|
||||||
totalRead += read;
|
|
||||||
|
|
||||||
if (read == 0)
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
await file.WriteAsync(buffer.AsMemory(0, read), token);
|
|
||||||
|
|
||||||
if (canReportProgress)
|
|
||||||
{
|
|
||||||
var percent = (int)(100.0 * totalRead / total);
|
|
||||||
//if (progressPercentage != percent && percent % 10 == 0)
|
|
||||||
{
|
|
||||||
progressPercentage = percent;
|
|
||||||
progress?.Report(percent);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (canReportProgress)
|
if (canReportProgress)
|
||||||
{
|
{
|
||||||
progress?.Report(101);
|
var percent = (int)(100.0 * totalRead / total);
|
||||||
|
//if (progressPercentage != percent && percent % 10 == 0)
|
||||||
|
{
|
||||||
|
progressPercentage = percent;
|
||||||
|
progress?.Report(percent);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (canReportProgress)
|
||||||
public async Task DownloadDataAsync4Speed(HttpClient client, string url, IProgress<string> progress, CancellationToken token = default)
|
|
||||||
{
|
{
|
||||||
if (url.IsNullOrEmpty())
|
progress?.Report(101);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task DownloadDataAsync4Speed(HttpClient client, string url, IProgress<string> progress, CancellationToken token = default)
|
||||||
|
{
|
||||||
|
if (url.IsNullOrEmpty())
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(url));
|
||||||
|
}
|
||||||
|
|
||||||
|
var response = await client.GetAsync(url, HttpCompletionOption.ResponseHeadersRead, token);
|
||||||
|
|
||||||
|
if (!response.IsSuccessStatusCode)
|
||||||
|
{
|
||||||
|
throw new Exception(response.StatusCode.ToString());
|
||||||
|
}
|
||||||
|
|
||||||
|
//var total = response.Content.Headers.ContentLength.HasValue ? response.Content.Headers.ContentLength.Value : -1L;
|
||||||
|
//var canReportProgress = total != -1 && progress != null;
|
||||||
|
|
||||||
|
await using var stream = await response.Content.ReadAsStreamAsync(token);
|
||||||
|
var totalRead = 0L;
|
||||||
|
var buffer = new byte[1024 * 64];
|
||||||
|
var isMoreToRead = true;
|
||||||
|
var progressSpeed = string.Empty;
|
||||||
|
var totalDatetime = DateTime.Now;
|
||||||
|
var totalSecond = 0;
|
||||||
|
|
||||||
|
do
|
||||||
|
{
|
||||||
|
if (token.IsCancellationRequested)
|
||||||
{
|
{
|
||||||
throw new ArgumentNullException(nameof(url));
|
if (totalRead > 0)
|
||||||
}
|
|
||||||
|
|
||||||
var response = await client.GetAsync(url, HttpCompletionOption.ResponseHeadersRead, token);
|
|
||||||
|
|
||||||
if (!response.IsSuccessStatusCode)
|
|
||||||
{
|
|
||||||
throw new Exception(response.StatusCode.ToString());
|
|
||||||
}
|
|
||||||
|
|
||||||
//var total = response.Content.Headers.ContentLength.HasValue ? response.Content.Headers.ContentLength.Value : -1L;
|
|
||||||
//var canReportProgress = total != -1 && progress != null;
|
|
||||||
|
|
||||||
await using var stream = await response.Content.ReadAsStreamAsync(token);
|
|
||||||
var totalRead = 0L;
|
|
||||||
var buffer = new byte[1024 * 64];
|
|
||||||
var isMoreToRead = true;
|
|
||||||
var progressSpeed = string.Empty;
|
|
||||||
var totalDatetime = DateTime.Now;
|
|
||||||
var totalSecond = 0;
|
|
||||||
|
|
||||||
do
|
|
||||||
{
|
|
||||||
if (token.IsCancellationRequested)
|
|
||||||
{
|
{
|
||||||
if (totalRead > 0)
|
return;
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
token.ThrowIfCancellationRequested();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var read = await stream.ReadAsync(buffer, token);
|
|
||||||
|
|
||||||
if (read == 0)
|
|
||||||
{
|
|
||||||
isMoreToRead = false;
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
var data = new byte[read];
|
token.ThrowIfCancellationRequested();
|
||||||
buffer.ToList().CopyTo(0, data, 0, read);
|
}
|
||||||
|
}
|
||||||
|
|
||||||
totalRead += read;
|
var read = await stream.ReadAsync(buffer, token);
|
||||||
|
|
||||||
var ts = DateTime.Now - totalDatetime;
|
if (read == 0)
|
||||||
if (progress != null && ts.Seconds > totalSecond)
|
{
|
||||||
|
isMoreToRead = false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var data = new byte[read];
|
||||||
|
buffer.ToList().CopyTo(0, data, 0, read);
|
||||||
|
|
||||||
|
totalRead += read;
|
||||||
|
|
||||||
|
var ts = DateTime.Now - totalDatetime;
|
||||||
|
if (progress != null && ts.Seconds > totalSecond)
|
||||||
|
{
|
||||||
|
totalSecond = ts.Seconds;
|
||||||
|
var speed = (totalRead * 1d / ts.TotalMilliseconds / 1000).ToString("#0.0");
|
||||||
|
if (progressSpeed != speed)
|
||||||
{
|
{
|
||||||
totalSecond = ts.Seconds;
|
progressSpeed = speed;
|
||||||
var speed = (totalRead * 1d / ts.TotalMilliseconds / 1000).ToString("#0.0");
|
progress.Report(speed);
|
||||||
if (progressSpeed != speed)
|
|
||||||
{
|
|
||||||
progressSpeed = speed;
|
|
||||||
progress.Report(speed);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} while (isMoreToRead);
|
}
|
||||||
}
|
} while (isMoreToRead);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,7 @@
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
namespace ServiceLib.Common
|
namespace ServiceLib.Common;
|
||||||
{
|
|
||||||
/*
|
/*
|
||||||
* See:
|
* See:
|
||||||
* http://stackoverflow.com/questions/6266820/working-example-of-createjobobject-setinformationjobobject-pinvoke-in-net
|
* http://stackoverflow.com/questions/6266820/working-example-of-createjobobject-setinformationjobobject-pinvoke-in-net
|
||||||
|
@ -178,4 +177,4 @@ namespace ServiceLib.Common
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion Helper classes
|
#endregion Helper classes
|
||||||
}
|
|
||||||
|
|
|
@ -1,131 +1,130 @@
|
||||||
using System.Text.Json;
|
using System.Text.Json;
|
||||||
using System.Text.Json.Nodes;
|
using System.Text.Json.Nodes;
|
||||||
using System.Text.Json.Serialization;
|
using System.Text.Json.Serialization;
|
||||||
|
|
||||||
namespace ServiceLib.Common
|
namespace ServiceLib.Common;
|
||||||
|
|
||||||
|
public class JsonUtils
|
||||||
{
|
{
|
||||||
public class JsonUtils
|
private static readonly string _tag = "JsonUtils";
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// DeepCopy
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T"></typeparam>
|
||||||
|
/// <param name="obj"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static T DeepCopy<T>(T obj)
|
||||||
{
|
{
|
||||||
private static readonly string _tag = "JsonUtils";
|
return Deserialize<T>(Serialize(obj, false))!;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// DeepCopy
|
/// Deserialize to object
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <typeparam name="T"></typeparam>
|
/// <typeparam name="T"></typeparam>
|
||||||
/// <param name="obj"></param>
|
/// <param name="strJson"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public static T DeepCopy<T>(T obj)
|
public static T? Deserialize<T>(string? strJson)
|
||||||
|
{
|
||||||
|
try
|
||||||
{
|
{
|
||||||
return Deserialize<T>(Serialize(obj, false))!;
|
if (string.IsNullOrWhiteSpace(strJson))
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Deserialize to object
|
|
||||||
/// </summary>
|
|
||||||
/// <typeparam name="T"></typeparam>
|
|
||||||
/// <param name="strJson"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
public static T? Deserialize<T>(string? strJson)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
if (string.IsNullOrWhiteSpace(strJson))
|
|
||||||
{
|
|
||||||
return default;
|
|
||||||
}
|
|
||||||
var options = new JsonSerializerOptions
|
|
||||||
{
|
|
||||||
PropertyNameCaseInsensitive = true
|
|
||||||
};
|
|
||||||
return JsonSerializer.Deserialize<T>(strJson, options);
|
|
||||||
}
|
|
||||||
catch
|
|
||||||
{
|
{
|
||||||
return default;
|
return default;
|
||||||
}
|
}
|
||||||
|
var options = new JsonSerializerOptions
|
||||||
|
{
|
||||||
|
PropertyNameCaseInsensitive = true
|
||||||
|
};
|
||||||
|
return JsonSerializer.Deserialize<T>(strJson, options);
|
||||||
}
|
}
|
||||||
|
catch
|
||||||
/// <summary>
|
|
||||||
/// parse
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="strJson"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
public static JsonNode? ParseJson(string strJson)
|
|
||||||
{
|
{
|
||||||
try
|
return default;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// parse
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="strJson"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static JsonNode? ParseJson(string strJson)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (string.IsNullOrWhiteSpace(strJson))
|
||||||
{
|
{
|
||||||
if (string.IsNullOrWhiteSpace(strJson))
|
|
||||||
{
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
return JsonNode.Parse(strJson);
|
|
||||||
}
|
|
||||||
catch
|
|
||||||
{
|
|
||||||
//SaveLog(ex.Message, ex);
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
return JsonNode.Parse(strJson);
|
||||||
}
|
}
|
||||||
|
catch
|
||||||
/// <summary>
|
|
||||||
/// Serialize Object to Json string
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="obj"></param>
|
|
||||||
/// <param name="indented"></param>
|
|
||||||
/// <param name="nullValue"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
public static string Serialize(object? obj, bool indented = true, bool nullValue = false)
|
|
||||||
{
|
{
|
||||||
var result = string.Empty;
|
//SaveLog(ex.Message, ex);
|
||||||
try
|
return null;
|
||||||
{
|
|
||||||
if (obj == null)
|
|
||||||
{
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
var options = new JsonSerializerOptions
|
|
||||||
{
|
|
||||||
WriteIndented = indented,
|
|
||||||
DefaultIgnoreCondition = nullValue ? JsonIgnoreCondition.Never : JsonIgnoreCondition.WhenWritingNull
|
|
||||||
};
|
|
||||||
result = JsonSerializer.Serialize(obj, options);
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
Logging.SaveLog(_tag, ex);
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Serialize Object to Json string
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="obj"></param>
|
|
||||||
/// <param name="options"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
public static string Serialize(object? obj, JsonSerializerOptions options)
|
|
||||||
{
|
|
||||||
var result = string.Empty;
|
|
||||||
try
|
|
||||||
{
|
|
||||||
if (obj == null)
|
|
||||||
{
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
result = JsonSerializer.Serialize(obj, options);
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
Logging.SaveLog(_tag, ex);
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// SerializeToNode
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="obj"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
public static JsonNode? SerializeToNode(object? obj) => JsonSerializer.SerializeToNode(obj);
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
/// <summary>
|
||||||
|
/// Serialize Object to Json string
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="obj"></param>
|
||||||
|
/// <param name="indented"></param>
|
||||||
|
/// <param name="nullValue"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static string Serialize(object? obj, bool indented = true, bool nullValue = false)
|
||||||
|
{
|
||||||
|
var result = string.Empty;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (obj == null)
|
||||||
|
{
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
var options = new JsonSerializerOptions
|
||||||
|
{
|
||||||
|
WriteIndented = indented,
|
||||||
|
DefaultIgnoreCondition = nullValue ? JsonIgnoreCondition.Never : JsonIgnoreCondition.WhenWritingNull
|
||||||
|
};
|
||||||
|
result = JsonSerializer.Serialize(obj, options);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Logging.SaveLog(_tag, ex);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Serialize Object to Json string
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="obj"></param>
|
||||||
|
/// <param name="options"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static string Serialize(object? obj, JsonSerializerOptions options)
|
||||||
|
{
|
||||||
|
var result = string.Empty;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (obj == null)
|
||||||
|
{
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
result = JsonSerializer.Serialize(obj, options);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Logging.SaveLog(_tag, ex);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// SerializeToNode
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="obj"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static JsonNode? SerializeToNode(object? obj) => JsonSerializer.SerializeToNode(obj);
|
||||||
|
}
|
||||||
|
|
|
@ -2,53 +2,54 @@ using NLog;
|
||||||
using NLog.Config;
|
using NLog.Config;
|
||||||
using NLog.Targets;
|
using NLog.Targets;
|
||||||
|
|
||||||
namespace ServiceLib.Common
|
namespace ServiceLib.Common;
|
||||||
|
|
||||||
|
public class Logging
|
||||||
{
|
{
|
||||||
public class Logging
|
private static readonly Logger _logger1 = LogManager.GetLogger("Log1");
|
||||||
|
private static readonly Logger _logger2 = LogManager.GetLogger("Log2");
|
||||||
|
|
||||||
|
public static void Setup()
|
||||||
{
|
{
|
||||||
public static void Setup()
|
LoggingConfiguration config = new();
|
||||||
|
FileTarget fileTarget = new();
|
||||||
|
config.AddTarget("file", fileTarget);
|
||||||
|
fileTarget.Layout = "${longdate}-${level:uppercase=true} ${message}";
|
||||||
|
fileTarget.FileName = Utils.GetLogPath("${shortdate}.txt");
|
||||||
|
config.LoggingRules.Add(new LoggingRule("*", LogLevel.Debug, fileTarget));
|
||||||
|
LogManager.Configuration = config;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void LoggingEnabled(bool enable)
|
||||||
|
{
|
||||||
|
if (!enable)
|
||||||
{
|
{
|
||||||
LoggingConfiguration config = new();
|
LogManager.SuspendLogging();
|
||||||
FileTarget fileTarget = new();
|
}
|
||||||
config.AddTarget("file", fileTarget);
|
}
|
||||||
fileTarget.Layout = "${longdate}-${level:uppercase=true} ${message}";
|
|
||||||
fileTarget.FileName = Utils.GetLogPath("${shortdate}.txt");
|
public static void SaveLog(string strContent)
|
||||||
config.LoggingRules.Add(new LoggingRule("*", LogLevel.Debug, fileTarget));
|
{
|
||||||
LogManager.Configuration = config;
|
if (!LogManager.IsLoggingEnabled())
|
||||||
|
{
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void LoggingEnabled(bool enable)
|
_logger1.Info(strContent);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void SaveLog(string strTitle, Exception ex)
|
||||||
|
{
|
||||||
|
if (!LogManager.IsLoggingEnabled())
|
||||||
{
|
{
|
||||||
if (!enable)
|
return;
|
||||||
{
|
|
||||||
LogManager.SuspendLogging();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void SaveLog(string strContent)
|
_logger2.Debug($"{strTitle},{ex.Message}");
|
||||||
|
_logger2.Debug(ex.StackTrace);
|
||||||
|
if (ex?.InnerException != null)
|
||||||
{
|
{
|
||||||
if (!LogManager.IsLoggingEnabled())
|
_logger2.Error(ex.InnerException);
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
LogManager.GetLogger("Log1").Info(strContent);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void SaveLog(string strTitle, Exception ex)
|
|
||||||
{
|
|
||||||
if (!LogManager.IsLoggingEnabled())
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var logger = LogManager.GetLogger("Log2");
|
|
||||||
logger.Debug($"{strTitle},{ex.Message}");
|
|
||||||
logger.Debug(ex.StackTrace);
|
|
||||||
if (ex?.InnerException != null)
|
|
||||||
{
|
|
||||||
logger.Error(ex.InnerException);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,90 +1,89 @@
|
||||||
using QRCoder;
|
using QRCoder;
|
||||||
using SkiaSharp;
|
using SkiaSharp;
|
||||||
using ZXing.SkiaSharp;
|
using ZXing.SkiaSharp;
|
||||||
|
|
||||||
namespace ServiceLib.Common
|
namespace ServiceLib.Common;
|
||||||
|
|
||||||
|
public class QRCodeHelper
|
||||||
{
|
{
|
||||||
public class QRCodeHelper
|
public static byte[]? GenQRCode(string? url)
|
||||||
{
|
{
|
||||||
public static byte[]? GenQRCode(string? url)
|
using QRCodeGenerator qrGenerator = new();
|
||||||
{
|
using var qrCodeData = qrGenerator.CreateQrCode(url ?? string.Empty, QRCodeGenerator.ECCLevel.Q);
|
||||||
using QRCodeGenerator qrGenerator = new();
|
using PngByteQRCode qrCode = new(qrCodeData);
|
||||||
using var qrCodeData = qrGenerator.CreateQrCode(url ?? string.Empty, QRCodeGenerator.ECCLevel.Q);
|
return qrCode.GetGraphic(20);
|
||||||
using PngByteQRCode qrCode = new(qrCodeData);
|
|
||||||
return qrCode.GetGraphic(20);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static string? ParseBarcode(string? fileName)
|
|
||||||
{
|
|
||||||
if (fileName == null || !File.Exists(fileName))
|
|
||||||
{
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
var image = SKImage.FromEncodedData(fileName);
|
|
||||||
var bitmap = SKBitmap.FromImage(image);
|
|
||||||
|
|
||||||
return ReaderBarcode(bitmap);
|
|
||||||
}
|
|
||||||
catch
|
|
||||||
{
|
|
||||||
// ignored
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static string? ParseBarcode(byte[]? bytes)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
var bitmap = SKBitmap.Decode(bytes);
|
|
||||||
//using var stream = new FileStream("test2.png", FileMode.Create, FileAccess.Write);
|
|
||||||
//using var image = SKImage.FromBitmap(bitmap);
|
|
||||||
//using var encodedImage = image.Encode();
|
|
||||||
//encodedImage.SaveTo(stream);
|
|
||||||
return ReaderBarcode(bitmap);
|
|
||||||
}
|
|
||||||
catch
|
|
||||||
{
|
|
||||||
// ignored
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static string? ReaderBarcode(SKBitmap? bitmap)
|
|
||||||
{
|
|
||||||
var reader = new BarcodeReader();
|
|
||||||
var result = reader.Decode(bitmap);
|
|
||||||
|
|
||||||
if (result != null && result.Text.IsNotEmpty())
|
|
||||||
{
|
|
||||||
return result.Text;
|
|
||||||
}
|
|
||||||
|
|
||||||
//FlipBitmap
|
|
||||||
var result2 = reader.Decode(FlipBitmap(bitmap));
|
|
||||||
return result2?.Text;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static SKBitmap FlipBitmap(SKBitmap bmp)
|
|
||||||
{
|
|
||||||
// Create a bitmap (to return)
|
|
||||||
var flipped = new SKBitmap(bmp.Width, bmp.Height, bmp.Info.ColorType, bmp.Info.AlphaType);
|
|
||||||
|
|
||||||
// Create a canvas to draw into the bitmap
|
|
||||||
using var canvas = new SKCanvas(flipped);
|
|
||||||
|
|
||||||
// Set a transform matrix which moves the bitmap to the right,
|
|
||||||
// and then "scales" it by -1, which just flips the pixels
|
|
||||||
// horizontally
|
|
||||||
canvas.Translate(bmp.Width, 0);
|
|
||||||
canvas.Scale(-1, 1);
|
|
||||||
canvas.DrawBitmap(bmp, 0, 0);
|
|
||||||
return flipped;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
public static string? ParseBarcode(string? fileName)
|
||||||
|
{
|
||||||
|
if (fileName == null || !File.Exists(fileName))
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var image = SKImage.FromEncodedData(fileName);
|
||||||
|
var bitmap = SKBitmap.FromImage(image);
|
||||||
|
|
||||||
|
return ReaderBarcode(bitmap);
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
// ignored
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string? ParseBarcode(byte[]? bytes)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var bitmap = SKBitmap.Decode(bytes);
|
||||||
|
//using var stream = new FileStream("test2.png", FileMode.Create, FileAccess.Write);
|
||||||
|
//using var image = SKImage.FromBitmap(bitmap);
|
||||||
|
//using var encodedImage = image.Encode();
|
||||||
|
//encodedImage.SaveTo(stream);
|
||||||
|
return ReaderBarcode(bitmap);
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
// ignored
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string? ReaderBarcode(SKBitmap? bitmap)
|
||||||
|
{
|
||||||
|
var reader = new BarcodeReader();
|
||||||
|
var result = reader.Decode(bitmap);
|
||||||
|
|
||||||
|
if (result != null && result.Text.IsNotEmpty())
|
||||||
|
{
|
||||||
|
return result.Text;
|
||||||
|
}
|
||||||
|
|
||||||
|
//FlipBitmap
|
||||||
|
var result2 = reader.Decode(FlipBitmap(bitmap));
|
||||||
|
return result2?.Text;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static SKBitmap FlipBitmap(SKBitmap bmp)
|
||||||
|
{
|
||||||
|
// Create a bitmap (to return)
|
||||||
|
var flipped = new SKBitmap(bmp.Width, bmp.Height, bmp.Info.ColorType, bmp.Info.AlphaType);
|
||||||
|
|
||||||
|
// Create a canvas to draw into the bitmap
|
||||||
|
using var canvas = new SKCanvas(flipped);
|
||||||
|
|
||||||
|
// Set a transform matrix which moves the bitmap to the right,
|
||||||
|
// and then "scales" it by -1, which just flips the pixels
|
||||||
|
// horizontally
|
||||||
|
canvas.Translate(bmp.Width, 0);
|
||||||
|
canvas.Scale(-1, 1);
|
||||||
|
canvas.DrawBitmap(bmp, 0, 0);
|
||||||
|
return flipped;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -1,187 +1,186 @@
|
||||||
namespace ServiceLib.Common
|
namespace ServiceLib.Common;
|
||||||
|
|
||||||
|
public class SemanticVersion
|
||||||
{
|
{
|
||||||
public class SemanticVersion
|
private readonly int major;
|
||||||
|
private readonly int minor;
|
||||||
|
private readonly int patch;
|
||||||
|
private readonly string version;
|
||||||
|
|
||||||
|
public SemanticVersion(int major, int minor, int patch)
|
||||||
{
|
{
|
||||||
private readonly int major;
|
this.major = major;
|
||||||
private readonly int minor;
|
this.minor = minor;
|
||||||
private readonly int patch;
|
this.patch = patch;
|
||||||
private readonly string version;
|
version = $"{major}.{minor}.{patch}";
|
||||||
|
}
|
||||||
|
|
||||||
public SemanticVersion(int major, int minor, int patch)
|
public SemanticVersion(string? version)
|
||||||
|
{
|
||||||
|
try
|
||||||
{
|
{
|
||||||
this.major = major;
|
if (string.IsNullOrEmpty(version))
|
||||||
this.minor = minor;
|
|
||||||
this.patch = patch;
|
|
||||||
version = $"{major}.{minor}.{patch}";
|
|
||||||
}
|
|
||||||
|
|
||||||
public SemanticVersion(string? version)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
if (string.IsNullOrEmpty(version))
|
|
||||||
{
|
|
||||||
major = 0;
|
|
||||||
minor = 0;
|
|
||||||
patch = 0;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
this.version = version.RemovePrefix('v');
|
|
||||||
|
|
||||||
var parts = this.version.Split('.');
|
|
||||||
if (parts.Length == 2)
|
|
||||||
{
|
|
||||||
major = int.Parse(parts.First());
|
|
||||||
minor = int.Parse(parts.Last());
|
|
||||||
patch = 0;
|
|
||||||
}
|
|
||||||
else if (parts.Length is 3 or 4)
|
|
||||||
{
|
|
||||||
major = int.Parse(parts[0]);
|
|
||||||
minor = int.Parse(parts[1]);
|
|
||||||
patch = int.Parse(parts[2]);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
throw new ArgumentException("Invalid version string");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch
|
|
||||||
{
|
{
|
||||||
major = 0;
|
major = 0;
|
||||||
minor = 0;
|
minor = 0;
|
||||||
patch = 0;
|
patch = 0;
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
}
|
this.version = version.RemovePrefix('v');
|
||||||
|
|
||||||
public override bool Equals(object? obj)
|
var parts = this.version.Split('.');
|
||||||
{
|
if (parts.Length == 2)
|
||||||
if (obj is SemanticVersion other)
|
|
||||||
{
|
{
|
||||||
return major == other.major && minor == other.minor && patch == other.patch;
|
major = int.Parse(parts.First());
|
||||||
|
minor = int.Parse(parts.Last());
|
||||||
|
patch = 0;
|
||||||
|
}
|
||||||
|
else if (parts.Length is 3 or 4)
|
||||||
|
{
|
||||||
|
major = int.Parse(parts[0]);
|
||||||
|
minor = int.Parse(parts[1]);
|
||||||
|
patch = int.Parse(parts[2]);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
return false;
|
throw new ArgumentException("Invalid version string");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
catch
|
||||||
public override int GetHashCode()
|
|
||||||
{
|
{
|
||||||
return major.GetHashCode() ^ minor.GetHashCode() ^ patch.GetHashCode();
|
major = 0;
|
||||||
|
minor = 0;
|
||||||
|
patch = 0;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
public override bool Equals(object? obj)
|
||||||
/// Use ToVersionString(string? prefix) instead if possible.
|
{
|
||||||
/// </summary>
|
if (obj is SemanticVersion other)
|
||||||
/// <returns>major.minor.patch</returns>
|
{
|
||||||
public override string ToString()
|
return major == other.major && minor == other.minor && patch == other.patch;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override int GetHashCode()
|
||||||
|
{
|
||||||
|
return major.GetHashCode() ^ minor.GetHashCode() ^ patch.GetHashCode();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Use ToVersionString(string? prefix) instead if possible.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>major.minor.patch</returns>
|
||||||
|
public override string ToString()
|
||||||
|
{
|
||||||
|
return version;
|
||||||
|
}
|
||||||
|
|
||||||
|
public string ToVersionString(string? prefix = null)
|
||||||
|
{
|
||||||
|
if (prefix == null)
|
||||||
{
|
{
|
||||||
return version;
|
return version;
|
||||||
}
|
}
|
||||||
|
else
|
||||||
public string ToVersionString(string? prefix = null)
|
|
||||||
{
|
{
|
||||||
if (prefix == null)
|
return $"{prefix}{version}";
|
||||||
{
|
|
||||||
return version;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return $"{prefix}{version}";
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static bool operator ==(SemanticVersion v1, SemanticVersion v2)
|
|
||||||
{ return v1.Equals(v2); }
|
|
||||||
|
|
||||||
public static bool operator !=(SemanticVersion v1, SemanticVersion v2)
|
|
||||||
{ return !v1.Equals(v2); }
|
|
||||||
|
|
||||||
public static bool operator >=(SemanticVersion v1, SemanticVersion v2)
|
|
||||||
{ return v1.GreaterEquals(v2); }
|
|
||||||
|
|
||||||
public static bool operator <=(SemanticVersion v1, SemanticVersion v2)
|
|
||||||
{ return v1.LessEquals(v2); }
|
|
||||||
|
|
||||||
#region Private
|
|
||||||
|
|
||||||
private bool GreaterEquals(SemanticVersion other)
|
|
||||||
{
|
|
||||||
if (major < other.major)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
else if (major > other.major)
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (minor < other.minor)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
else if (minor > other.minor)
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (patch < other.patch)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
else if (patch > other.patch)
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private bool LessEquals(SemanticVersion other)
|
|
||||||
{
|
|
||||||
if (major < other.major)
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
else if (major > other.major)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (minor < other.minor)
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
else if (minor > other.minor)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (patch < other.patch)
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
else if (patch > other.patch)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion Private
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static bool operator ==(SemanticVersion v1, SemanticVersion v2)
|
||||||
|
{ return v1.Equals(v2); }
|
||||||
|
|
||||||
|
public static bool operator !=(SemanticVersion v1, SemanticVersion v2)
|
||||||
|
{ return !v1.Equals(v2); }
|
||||||
|
|
||||||
|
public static bool operator >=(SemanticVersion v1, SemanticVersion v2)
|
||||||
|
{ return v1.GreaterEquals(v2); }
|
||||||
|
|
||||||
|
public static bool operator <=(SemanticVersion v1, SemanticVersion v2)
|
||||||
|
{ return v1.LessEquals(v2); }
|
||||||
|
|
||||||
|
#region Private
|
||||||
|
|
||||||
|
private bool GreaterEquals(SemanticVersion other)
|
||||||
|
{
|
||||||
|
if (major < other.major)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
else if (major > other.major)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (minor < other.minor)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
else if (minor > other.minor)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (patch < other.patch)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
else if (patch > other.patch)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool LessEquals(SemanticVersion other)
|
||||||
|
{
|
||||||
|
if (major < other.major)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else if (major > other.major)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (minor < other.minor)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else if (minor > other.minor)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (patch < other.patch)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else if (patch > other.patch)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion Private
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,91 +1,90 @@
|
||||||
using System.Collections;
|
using System.Collections;
|
||||||
using SQLite;
|
using SQLite;
|
||||||
|
|
||||||
namespace ServiceLib.Common
|
namespace ServiceLib.Common;
|
||||||
|
|
||||||
|
public sealed class SQLiteHelper
|
||||||
{
|
{
|
||||||
public sealed class SQLiteHelper
|
private static readonly Lazy<SQLiteHelper> _instance = new(() => new());
|
||||||
|
public static SQLiteHelper Instance => _instance.Value;
|
||||||
|
private readonly string _connstr;
|
||||||
|
private SQLiteConnection _db;
|
||||||
|
private SQLiteAsyncConnection _dbAsync;
|
||||||
|
private readonly string _configDB = "guiNDB.db";
|
||||||
|
|
||||||
|
public SQLiteHelper()
|
||||||
{
|
{
|
||||||
private static readonly Lazy<SQLiteHelper> _instance = new(() => new());
|
_connstr = Utils.GetConfigPath(_configDB);
|
||||||
public static SQLiteHelper Instance => _instance.Value;
|
_db = new SQLiteConnection(_connstr, false);
|
||||||
private readonly string _connstr;
|
_dbAsync = new SQLiteAsyncConnection(_connstr, false);
|
||||||
private SQLiteConnection _db;
|
}
|
||||||
private SQLiteAsyncConnection _dbAsync;
|
|
||||||
private readonly string _configDB = "guiNDB.db";
|
|
||||||
|
|
||||||
public SQLiteHelper()
|
public CreateTableResult CreateTable<T>()
|
||||||
|
{
|
||||||
|
return _db.CreateTable<T>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<int> InsertAllAsync(IEnumerable models)
|
||||||
|
{
|
||||||
|
return await _dbAsync.InsertAllAsync(models);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<int> InsertAsync(object model)
|
||||||
|
{
|
||||||
|
return await _dbAsync.InsertAsync(model);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<int> ReplaceAsync(object model)
|
||||||
|
{
|
||||||
|
return await _dbAsync.InsertOrReplaceAsync(model);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<int> UpdateAsync(object model)
|
||||||
|
{
|
||||||
|
return await _dbAsync.UpdateAsync(model);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<int> UpdateAllAsync(IEnumerable models)
|
||||||
|
{
|
||||||
|
return await _dbAsync.UpdateAllAsync(models);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<int> DeleteAsync(object model)
|
||||||
|
{
|
||||||
|
return await _dbAsync.DeleteAsync(model);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<int> DeleteAllAsync<T>()
|
||||||
|
{
|
||||||
|
return await _dbAsync.DeleteAllAsync<T>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<int> ExecuteAsync(string sql)
|
||||||
|
{
|
||||||
|
return await _dbAsync.ExecuteAsync(sql);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<List<T>> QueryAsync<T>(string sql) where T : new()
|
||||||
|
{
|
||||||
|
return await _dbAsync.QueryAsync<T>(sql);
|
||||||
|
}
|
||||||
|
|
||||||
|
public AsyncTableQuery<T> TableAsync<T>() where T : new()
|
||||||
|
{
|
||||||
|
return _dbAsync.Table<T>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task DisposeDbConnectionAsync()
|
||||||
|
{
|
||||||
|
await Task.Factory.StartNew(() =>
|
||||||
{
|
{
|
||||||
_connstr = Utils.GetConfigPath(_configDB);
|
_db?.Close();
|
||||||
_db = new SQLiteConnection(_connstr, false);
|
_db?.Dispose();
|
||||||
_dbAsync = new SQLiteAsyncConnection(_connstr, false);
|
_db = null;
|
||||||
}
|
|
||||||
|
|
||||||
public CreateTableResult CreateTable<T>()
|
_dbAsync?.GetConnection()?.Close();
|
||||||
{
|
_dbAsync?.GetConnection()?.Dispose();
|
||||||
return _db.CreateTable<T>();
|
_dbAsync = null;
|
||||||
}
|
});
|
||||||
|
|
||||||
public async Task<int> InsertAllAsync(IEnumerable models)
|
|
||||||
{
|
|
||||||
return await _dbAsync.InsertAllAsync(models);
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task<int> InsertAsync(object model)
|
|
||||||
{
|
|
||||||
return await _dbAsync.InsertAsync(model);
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task<int> ReplaceAsync(object model)
|
|
||||||
{
|
|
||||||
return await _dbAsync.InsertOrReplaceAsync(model);
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task<int> UpdateAsync(object model)
|
|
||||||
{
|
|
||||||
return await _dbAsync.UpdateAsync(model);
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task<int> UpdateAllAsync(IEnumerable models)
|
|
||||||
{
|
|
||||||
return await _dbAsync.UpdateAllAsync(models);
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task<int> DeleteAsync(object model)
|
|
||||||
{
|
|
||||||
return await _dbAsync.DeleteAsync(model);
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task<int> DeleteAllAsync<T>()
|
|
||||||
{
|
|
||||||
return await _dbAsync.DeleteAllAsync<T>();
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task<int> ExecuteAsync(string sql)
|
|
||||||
{
|
|
||||||
return await _dbAsync.ExecuteAsync(sql);
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task<List<T>> QueryAsync<T>(string sql) where T : new()
|
|
||||||
{
|
|
||||||
return await _dbAsync.QueryAsync<T>(sql);
|
|
||||||
}
|
|
||||||
|
|
||||||
public AsyncTableQuery<T> TableAsync<T>() where T : new()
|
|
||||||
{
|
|
||||||
return _dbAsync.Table<T>();
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task DisposeDbConnectionAsync()
|
|
||||||
{
|
|
||||||
await Task.Factory.StartNew(() =>
|
|
||||||
{
|
|
||||||
_db?.Close();
|
|
||||||
_db?.Dispose();
|
|
||||||
_db = null;
|
|
||||||
|
|
||||||
_dbAsync?.GetConnection()?.Close();
|
|
||||||
_dbAsync?.GetConnection()?.Dispose();
|
|
||||||
_dbAsync = null;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,83 +1,82 @@
|
||||||
using System.Diagnostics.CodeAnalysis;
|
using System.Diagnostics.CodeAnalysis;
|
||||||
|
|
||||||
namespace ServiceLib.Common
|
namespace ServiceLib.Common;
|
||||||
|
|
||||||
|
public static class StringEx
|
||||||
{
|
{
|
||||||
public static class StringEx
|
public static bool IsNullOrEmpty([NotNullWhen(false)] this string? value)
|
||||||
{
|
{
|
||||||
public static bool IsNullOrEmpty([NotNullWhen(false)] this string? value)
|
return string.IsNullOrEmpty(value) || string.IsNullOrWhiteSpace(value);
|
||||||
{
|
}
|
||||||
return string.IsNullOrEmpty(value) || string.IsNullOrWhiteSpace(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static bool IsNullOrWhiteSpace([NotNullWhen(false)] this string? value)
|
public static bool IsNullOrWhiteSpace([NotNullWhen(false)] this string? value)
|
||||||
{
|
{
|
||||||
return string.IsNullOrWhiteSpace(value);
|
return string.IsNullOrWhiteSpace(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static bool IsNotEmpty([NotNullWhen(false)] this string? value)
|
public static bool IsNotEmpty([NotNullWhen(false)] this string? value)
|
||||||
{
|
{
|
||||||
return !string.IsNullOrEmpty(value);
|
return !string.IsNullOrEmpty(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static bool BeginWithAny(this string s, IEnumerable<char> chars)
|
public static bool BeginWithAny(this string s, IEnumerable<char> chars)
|
||||||
|
{
|
||||||
|
if (s.IsNullOrEmpty())
|
||||||
{
|
{
|
||||||
if (s.IsNullOrEmpty())
|
return false;
|
||||||
|
}
|
||||||
|
return chars.Contains(s.First());
|
||||||
|
}
|
||||||
|
|
||||||
|
private static bool IsWhiteSpace(this string value)
|
||||||
|
{
|
||||||
|
return value.All(char.IsWhiteSpace);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static IEnumerable<string> NonWhiteSpaceLines(this TextReader reader)
|
||||||
|
{
|
||||||
|
while (reader.ReadLine() is { } line)
|
||||||
|
{
|
||||||
|
if (line.IsWhiteSpace())
|
||||||
{
|
{
|
||||||
return false;
|
continue;
|
||||||
}
|
}
|
||||||
return chars.Contains(s.First());
|
yield return line;
|
||||||
}
|
|
||||||
|
|
||||||
private static bool IsWhiteSpace(this string value)
|
|
||||||
{
|
|
||||||
return value.All(char.IsWhiteSpace);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static IEnumerable<string> NonWhiteSpaceLines(this TextReader reader)
|
|
||||||
{
|
|
||||||
while (reader.ReadLine() is { } line)
|
|
||||||
{
|
|
||||||
if (line.IsWhiteSpace())
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
yield return line;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static string TrimEx(this string? value)
|
|
||||||
{
|
|
||||||
return value == null ? string.Empty : value.Trim();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static string RemovePrefix(this string value, char prefix)
|
|
||||||
{
|
|
||||||
return value.StartsWith(prefix) ? value[1..] : value;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static string RemovePrefix(this string value, string prefix)
|
|
||||||
{
|
|
||||||
return value.StartsWith(prefix) ? value[prefix.Length..] : value;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static string UpperFirstChar(this string value)
|
|
||||||
{
|
|
||||||
if (string.IsNullOrEmpty(value))
|
|
||||||
{
|
|
||||||
return string.Empty;
|
|
||||||
}
|
|
||||||
|
|
||||||
return char.ToUpper(value.First()) + value[1..];
|
|
||||||
}
|
|
||||||
|
|
||||||
public static string AppendQuotes(this string value)
|
|
||||||
{
|
|
||||||
return string.IsNullOrEmpty(value) ? string.Empty : $"\"{value}\"";
|
|
||||||
}
|
|
||||||
|
|
||||||
public static int ToInt(this string? value, int defaultValue = 0)
|
|
||||||
{
|
|
||||||
return int.TryParse(value, out var result) ? result : defaultValue;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static string TrimEx(this string? value)
|
||||||
|
{
|
||||||
|
return value == null ? string.Empty : value.Trim();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string RemovePrefix(this string value, char prefix)
|
||||||
|
{
|
||||||
|
return value.StartsWith(prefix) ? value[1..] : value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string RemovePrefix(this string value, string prefix)
|
||||||
|
{
|
||||||
|
return value.StartsWith(prefix) ? value[prefix.Length..] : value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string UpperFirstChar(this string value)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(value))
|
||||||
|
{
|
||||||
|
return string.Empty;
|
||||||
|
}
|
||||||
|
|
||||||
|
return char.ToUpper(value.First()) + value[1..];
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string AppendQuotes(this string value)
|
||||||
|
{
|
||||||
|
return string.IsNullOrEmpty(value) ? string.Empty : $"\"{value}\"";
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int ToInt(this string? value, int defaultValue = 0)
|
||||||
|
{
|
||||||
|
return int.TryParse(value, out var result) ? result : defaultValue;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -2,73 +2,72 @@ using System.Security.Cryptography;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using Microsoft.Win32;
|
using Microsoft.Win32;
|
||||||
|
|
||||||
namespace ServiceLib.Common
|
namespace ServiceLib.Common;
|
||||||
|
|
||||||
|
internal static class WindowsUtils
|
||||||
{
|
{
|
||||||
internal static class WindowsUtils
|
private static readonly string _tag = "WindowsUtils";
|
||||||
|
|
||||||
|
public static string? RegReadValue(string path, string name, string def)
|
||||||
{
|
{
|
||||||
private static readonly string _tag = "WindowsUtils";
|
RegistryKey? regKey = null;
|
||||||
|
try
|
||||||
public static string? RegReadValue(string path, string name, string def)
|
|
||||||
{
|
{
|
||||||
RegistryKey? regKey = null;
|
regKey = Registry.CurrentUser.OpenSubKey(path, false);
|
||||||
try
|
var value = regKey?.GetValue(name) as string;
|
||||||
{
|
return value.IsNullOrEmpty() ? def : value;
|
||||||
regKey = Registry.CurrentUser.OpenSubKey(path, false);
|
|
||||||
var value = regKey?.GetValue(name) as string;
|
|
||||||
return value.IsNullOrEmpty() ? def : value;
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
Logging.SaveLog(_tag, ex);
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
regKey?.Close();
|
|
||||||
}
|
|
||||||
return def;
|
|
||||||
}
|
}
|
||||||
|
catch (Exception ex)
|
||||||
public static void RegWriteValue(string path, string name, object value)
|
|
||||||
{
|
{
|
||||||
RegistryKey? regKey = null;
|
Logging.SaveLog(_tag, ex);
|
||||||
try
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
regKey?.Close();
|
||||||
|
}
|
||||||
|
return def;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void RegWriteValue(string path, string name, object value)
|
||||||
|
{
|
||||||
|
RegistryKey? regKey = null;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
regKey = Registry.CurrentUser.CreateSubKey(path);
|
||||||
|
if (value.ToString().IsNullOrEmpty())
|
||||||
{
|
{
|
||||||
regKey = Registry.CurrentUser.CreateSubKey(path);
|
regKey?.DeleteValue(name, false);
|
||||||
if (value.ToString().IsNullOrEmpty())
|
|
||||||
{
|
|
||||||
regKey?.DeleteValue(name, false);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
regKey?.SetValue(name, value);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
else
|
||||||
{
|
{
|
||||||
Logging.SaveLog(_tag, ex);
|
regKey?.SetValue(name, value);
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
regKey?.Close();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
catch (Exception ex)
|
||||||
public static async Task RemoveTunDevice()
|
|
||||||
{
|
{
|
||||||
try
|
Logging.SaveLog(_tag, ex);
|
||||||
{
|
}
|
||||||
var sum = MD5.HashData(Encoding.UTF8.GetBytes("wintunsingbox_tun"));
|
finally
|
||||||
var guid = new Guid(sum);
|
{
|
||||||
var pnpUtilPath = @"C:\Windows\System32\pnputil.exe";
|
regKey?.Close();
|
||||||
var arg = $$""" /remove-device "SWD\Wintun\{{{guid}}}" """;
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Try to remove the device
|
public static async Task RemoveTunDevice()
|
||||||
_ = await Utils.GetCliWrapOutput(pnpUtilPath, arg);
|
{
|
||||||
}
|
try
|
||||||
catch (Exception ex)
|
{
|
||||||
{
|
var sum = MD5.HashData(Encoding.UTF8.GetBytes("wintunsingbox_tun"));
|
||||||
Logging.SaveLog(_tag, ex);
|
var guid = new Guid(sum);
|
||||||
}
|
var pnpUtilPath = @"C:\Windows\System32\pnputil.exe";
|
||||||
|
var arg = $$""" /remove-device "SWD\Wintun\{{{guid}}}" """;
|
||||||
|
|
||||||
|
// Try to remove the device
|
||||||
|
_ = await Utils.GetCliWrapOutput(pnpUtilPath, arg);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Logging.SaveLog(_tag, ex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,79 +2,78 @@ using YamlDotNet.Core;
|
||||||
using YamlDotNet.Serialization;
|
using YamlDotNet.Serialization;
|
||||||
using YamlDotNet.Serialization.NamingConventions;
|
using YamlDotNet.Serialization.NamingConventions;
|
||||||
|
|
||||||
namespace ServiceLib.Common
|
namespace ServiceLib.Common;
|
||||||
|
|
||||||
|
public class YamlUtils
|
||||||
{
|
{
|
||||||
public class YamlUtils
|
private static readonly string _tag = "YamlUtils";
|
||||||
|
|
||||||
|
#region YAML
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 反序列化成对象
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T"></typeparam>
|
||||||
|
/// <param name="str"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static T FromYaml<T>(string str)
|
||||||
{
|
{
|
||||||
private static readonly string _tag = "YamlUtils";
|
var deserializer = new DeserializerBuilder()
|
||||||
|
.WithNamingConvention(PascalCaseNamingConvention.Instance)
|
||||||
#region YAML
|
.Build();
|
||||||
|
try
|
||||||
/// <summary>
|
|
||||||
/// 反序列化成对象
|
|
||||||
/// </summary>
|
|
||||||
/// <typeparam name="T"></typeparam>
|
|
||||||
/// <param name="str"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
public static T FromYaml<T>(string str)
|
|
||||||
{
|
{
|
||||||
var deserializer = new DeserializerBuilder()
|
var obj = deserializer.Deserialize<T>(str);
|
||||||
.WithNamingConvention(PascalCaseNamingConvention.Instance)
|
return obj;
|
||||||
.Build();
|
|
||||||
try
|
|
||||||
{
|
|
||||||
var obj = deserializer.Deserialize<T>(str);
|
|
||||||
return obj;
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
Logging.SaveLog(_tag, ex);
|
|
||||||
return deserializer.Deserialize<T>("");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
catch (Exception ex)
|
||||||
/// <summary>
|
|
||||||
/// 序列化
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="obj"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
public static string ToYaml(object? obj)
|
|
||||||
{
|
{
|
||||||
var result = string.Empty;
|
Logging.SaveLog(_tag, ex);
|
||||||
if (obj == null)
|
return deserializer.Deserialize<T>("");
|
||||||
{
|
}
|
||||||
return result;
|
}
|
||||||
}
|
|
||||||
var serializer = new SerializerBuilder()
|
|
||||||
.WithNamingConvention(HyphenatedNamingConvention.Instance)
|
|
||||||
.Build();
|
|
||||||
|
|
||||||
try
|
/// <summary>
|
||||||
{
|
/// 序列化
|
||||||
result = serializer.Serialize(obj);
|
/// </summary>
|
||||||
}
|
/// <param name="obj"></param>
|
||||||
catch (Exception ex)
|
/// <returns></returns>
|
||||||
{
|
public static string ToYaml(object? obj)
|
||||||
Logging.SaveLog(_tag, ex);
|
{
|
||||||
}
|
var result = string.Empty;
|
||||||
|
if (obj == null)
|
||||||
|
{
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
var serializer = new SerializerBuilder()
|
||||||
|
.WithNamingConvention(HyphenatedNamingConvention.Instance)
|
||||||
|
.Build();
|
||||||
|
|
||||||
public static string? PreprocessYaml(string str)
|
try
|
||||||
{
|
{
|
||||||
try
|
result = serializer.Serialize(obj);
|
||||||
{
|
|
||||||
var mergingParser = new MergingParser(new Parser(new StringReader(str)));
|
|
||||||
var obj = new DeserializerBuilder().Build().Deserialize(mergingParser);
|
|
||||||
return ToYaml(obj);
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
Logging.SaveLog(_tag, ex);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
catch (Exception ex)
|
||||||
#endregion YAML
|
{
|
||||||
|
Logging.SaveLog(_tag, ex);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static string? PreprocessYaml(string str)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var mergingParser = new MergingParser(new Parser(new StringReader(str)));
|
||||||
|
var obj = new DeserializerBuilder().Build().Deserialize(mergingParser);
|
||||||
|
return ToYaml(obj);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Logging.SaveLog(_tag, ex);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion YAML
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,16 +1,15 @@
|
||||||
namespace ServiceLib.Enums
|
namespace ServiceLib.Enums;
|
||||||
|
|
||||||
|
public enum EConfigType
|
||||||
{
|
{
|
||||||
public enum EConfigType
|
VMess = 1,
|
||||||
{
|
Custom = 2,
|
||||||
VMess = 1,
|
Shadowsocks = 3,
|
||||||
Custom = 2,
|
SOCKS = 4,
|
||||||
Shadowsocks = 3,
|
VLESS = 5,
|
||||||
SOCKS = 4,
|
Trojan = 6,
|
||||||
VLESS = 5,
|
Hysteria2 = 7,
|
||||||
Trojan = 6,
|
TUIC = 8,
|
||||||
Hysteria2 = 7,
|
WireGuard = 9,
|
||||||
TUIC = 8,
|
HTTP = 10
|
||||||
WireGuard = 9,
|
}
|
||||||
HTTP = 10
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,19 +1,18 @@
|
||||||
namespace ServiceLib.Enums
|
namespace ServiceLib.Enums;
|
||||||
|
|
||||||
|
public enum ECoreType
|
||||||
{
|
{
|
||||||
public enum ECoreType
|
v2fly = 1,
|
||||||
{
|
Xray = 2,
|
||||||
v2fly = 1,
|
v2fly_v5 = 4,
|
||||||
Xray = 2,
|
mihomo = 13,
|
||||||
v2fly_v5 = 4,
|
hysteria = 21,
|
||||||
mihomo = 13,
|
naiveproxy = 22,
|
||||||
hysteria = 21,
|
tuic = 23,
|
||||||
naiveproxy = 22,
|
sing_box = 24,
|
||||||
tuic = 23,
|
juicity = 25,
|
||||||
sing_box = 24,
|
hysteria2 = 26,
|
||||||
juicity = 25,
|
brook = 27,
|
||||||
hysteria2 = 26,
|
overtls = 28,
|
||||||
brook = 27,
|
v2rayN = 99
|
||||||
overtls = 28,
|
|
||||||
v2rayN = 99
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +1,8 @@
|
||||||
namespace ServiceLib.Enums
|
namespace ServiceLib.Enums;
|
||||||
|
|
||||||
|
public enum EGirdOrientation
|
||||||
{
|
{
|
||||||
public enum EGirdOrientation
|
Horizontal,
|
||||||
{
|
Vertical,
|
||||||
Horizontal,
|
Tab,
|
||||||
Vertical,
|
}
|
||||||
Tab,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,11 +1,10 @@
|
||||||
namespace ServiceLib.Enums
|
namespace ServiceLib.Enums;
|
||||||
|
|
||||||
|
public enum EGlobalHotkey
|
||||||
{
|
{
|
||||||
public enum EGlobalHotkey
|
ShowForm = 0,
|
||||||
{
|
SystemProxyClear = 1,
|
||||||
ShowForm = 0,
|
SystemProxySet = 2,
|
||||||
SystemProxyClear = 1,
|
SystemProxyUnchanged = 3,
|
||||||
SystemProxySet = 2,
|
SystemProxyPac = 4,
|
||||||
SystemProxyUnchanged = 3,
|
}
|
||||||
SystemProxyPac = 4,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,14 +1,13 @@
|
||||||
namespace ServiceLib.Enums
|
namespace ServiceLib.Enums;
|
||||||
|
|
||||||
|
public enum EInboundProtocol
|
||||||
{
|
{
|
||||||
public enum EInboundProtocol
|
socks = 0,
|
||||||
{
|
socks2,
|
||||||
socks = 0,
|
socks3,
|
||||||
socks2,
|
pac,
|
||||||
socks3,
|
api,
|
||||||
pac,
|
api2,
|
||||||
api,
|
mixed,
|
||||||
api2,
|
speedtest = 21
|
||||||
mixed,
|
}
|
||||||
speedtest = 21
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,11 +1,10 @@
|
||||||
namespace ServiceLib.Enums
|
namespace ServiceLib.Enums;
|
||||||
|
|
||||||
|
public enum EMove
|
||||||
{
|
{
|
||||||
public enum EMove
|
Top = 1,
|
||||||
{
|
Up = 2,
|
||||||
Top = 1,
|
Down = 3,
|
||||||
Up = 2,
|
Bottom = 4,
|
||||||
Down = 3,
|
Position = 5
|
||||||
Bottom = 4,
|
}
|
||||||
Position = 5
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,11 +1,10 @@
|
||||||
namespace ServiceLib.Enums
|
namespace ServiceLib.Enums;
|
||||||
|
|
||||||
|
public enum EMsgCommand
|
||||||
{
|
{
|
||||||
public enum EMsgCommand
|
ClearMsg,
|
||||||
{
|
SendMsgView,
|
||||||
ClearMsg,
|
SendSnackMsg,
|
||||||
SendMsgView,
|
RefreshProfiles,
|
||||||
SendSnackMsg,
|
AppExit
|
||||||
RefreshProfiles,
|
|
||||||
AppExit
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
9
v2rayN/ServiceLib/Enums/EMultipleLoad.cs
Normal file
9
v2rayN/ServiceLib/Enums/EMultipleLoad.cs
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
namespace ServiceLib.Enums;
|
||||||
|
|
||||||
|
public enum EMultipleLoad
|
||||||
|
{
|
||||||
|
Random,
|
||||||
|
RoundRobin,
|
||||||
|
LeastPing,
|
||||||
|
LeastLoad
|
||||||
|
}
|
|
@ -1,9 +1,8 @@
|
||||||
namespace ServiceLib.Enums
|
namespace ServiceLib.Enums;
|
||||||
|
|
||||||
|
public enum EPresetType
|
||||||
{
|
{
|
||||||
public enum EPresetType
|
Default = 0,
|
||||||
{
|
Russia = 1,
|
||||||
Default = 0,
|
Iran = 2,
|
||||||
Russia = 1,
|
}
|
||||||
Iran = 2,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,10 +1,9 @@
|
||||||
namespace ServiceLib.Enums
|
namespace ServiceLib.Enums;
|
||||||
|
|
||||||
|
public enum ERuleMode
|
||||||
{
|
{
|
||||||
public enum ERuleMode
|
Rule = 0,
|
||||||
{
|
Global = 1,
|
||||||
Rule = 0,
|
Direct = 2,
|
||||||
Global = 1,
|
Unchanged = 3
|
||||||
Direct = 2,
|
}
|
||||||
Unchanged = 3
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,21 +1,20 @@
|
||||||
namespace ServiceLib.Enums
|
namespace ServiceLib.Enums;
|
||||||
{
|
|
||||||
public enum EServerColName
|
|
||||||
{
|
|
||||||
Def = 0,
|
|
||||||
ConfigType,
|
|
||||||
Remarks,
|
|
||||||
Address,
|
|
||||||
Port,
|
|
||||||
Network,
|
|
||||||
StreamSecurity,
|
|
||||||
SubRemarks,
|
|
||||||
DelayVal,
|
|
||||||
SpeedVal,
|
|
||||||
|
|
||||||
TodayDown,
|
public enum EServerColName
|
||||||
TodayUp,
|
{
|
||||||
TotalDown,
|
Def = 0,
|
||||||
TotalUp
|
ConfigType,
|
||||||
}
|
Remarks,
|
||||||
}
|
Address,
|
||||||
|
Port,
|
||||||
|
Network,
|
||||||
|
StreamSecurity,
|
||||||
|
SubRemarks,
|
||||||
|
DelayVal,
|
||||||
|
SpeedVal,
|
||||||
|
|
||||||
|
TodayDown,
|
||||||
|
TodayUp,
|
||||||
|
TotalDown,
|
||||||
|
TotalUp
|
||||||
|
}
|
||||||
|
|
|
@ -1,10 +1,9 @@
|
||||||
namespace ServiceLib.Enums
|
namespace ServiceLib.Enums;
|
||||||
|
|
||||||
|
public enum ESpeedActionType
|
||||||
{
|
{
|
||||||
public enum ESpeedActionType
|
Tcping,
|
||||||
{
|
Realping,
|
||||||
Tcping,
|
Speedtest,
|
||||||
Realping,
|
Mixedtest
|
||||||
Speedtest,
|
}
|
||||||
Mixedtest
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,10 +1,9 @@
|
||||||
namespace ServiceLib.Enums
|
namespace ServiceLib.Enums;
|
||||||
|
|
||||||
|
public enum ESysProxyType
|
||||||
{
|
{
|
||||||
public enum ESysProxyType
|
ForcedClear = 0,
|
||||||
{
|
ForcedChange = 1,
|
||||||
ForcedClear = 0,
|
Unchanged = 2,
|
||||||
ForcedChange = 1,
|
Pac = 3
|
||||||
Unchanged = 2,
|
}
|
||||||
Pac = 3
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,13 +1,12 @@
|
||||||
namespace ServiceLib.Enums
|
namespace ServiceLib.Enums;
|
||||||
|
|
||||||
|
public enum ETheme
|
||||||
{
|
{
|
||||||
public enum ETheme
|
FollowSystem,
|
||||||
{
|
Dark,
|
||||||
FollowSystem,
|
Light,
|
||||||
Dark,
|
Aquatic,
|
||||||
Light,
|
Desert,
|
||||||
Aquatic,
|
Dusk,
|
||||||
Desert,
|
NightSky
|
||||||
Dusk,
|
}
|
||||||
NightSky
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,15 +1,14 @@
|
||||||
namespace ServiceLib.Enums
|
namespace ServiceLib.Enums;
|
||||||
|
|
||||||
|
public enum ETransport
|
||||||
{
|
{
|
||||||
public enum ETransport
|
tcp,
|
||||||
{
|
kcp,
|
||||||
tcp,
|
ws,
|
||||||
kcp,
|
httpupgrade,
|
||||||
ws,
|
xhttp,
|
||||||
httpupgrade,
|
h2,
|
||||||
xhttp,
|
http,
|
||||||
h2,
|
quic,
|
||||||
http,
|
grpc
|
||||||
quic,
|
}
|
||||||
grpc
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,46 +1,45 @@
|
||||||
namespace ServiceLib.Enums
|
namespace ServiceLib.Enums;
|
||||||
|
|
||||||
|
public enum EViewAction
|
||||||
{
|
{
|
||||||
public enum EViewAction
|
CloseWindow,
|
||||||
{
|
ShowYesNo,
|
||||||
CloseWindow,
|
SaveFileDialog,
|
||||||
ShowYesNo,
|
AddBatchRoutingRulesYesNo,
|
||||||
SaveFileDialog,
|
AdjustMainLvColWidth,
|
||||||
AddBatchRoutingRulesYesNo,
|
SetClipboardData,
|
||||||
AdjustMainLvColWidth,
|
AddServerViaClipboard,
|
||||||
SetClipboardData,
|
ImportRulesFromClipboard,
|
||||||
AddServerViaClipboard,
|
ProfilesFocus,
|
||||||
ImportRulesFromClipboard,
|
ShareSub,
|
||||||
ProfilesFocus,
|
ShareServer,
|
||||||
ShareSub,
|
ShowHideWindow,
|
||||||
ShareServer,
|
ScanScreenTask,
|
||||||
ShowHideWindow,
|
ScanImageTask,
|
||||||
ScanScreenTask,
|
Shutdown,
|
||||||
ScanImageTask,
|
BrowseServer,
|
||||||
Shutdown,
|
ImportRulesFromFile,
|
||||||
BrowseServer,
|
InitSettingFont,
|
||||||
ImportRulesFromFile,
|
SubEditWindow,
|
||||||
InitSettingFont,
|
RoutingRuleSettingWindow,
|
||||||
SubEditWindow,
|
RoutingRuleDetailsWindow,
|
||||||
RoutingRuleSettingWindow,
|
AddServerWindow,
|
||||||
RoutingRuleDetailsWindow,
|
AddServer2Window,
|
||||||
AddServerWindow,
|
DNSSettingWindow,
|
||||||
AddServer2Window,
|
RoutingSettingWindow,
|
||||||
DNSSettingWindow,
|
OptionSettingWindow,
|
||||||
RoutingSettingWindow,
|
GlobalHotkeySettingWindow,
|
||||||
OptionSettingWindow,
|
SubSettingWindow,
|
||||||
GlobalHotkeySettingWindow,
|
DispatcherSpeedTest,
|
||||||
SubSettingWindow,
|
DispatcherRefreshConnections,
|
||||||
DispatcherSpeedTest,
|
DispatcherRefreshProxyGroups,
|
||||||
DispatcherRefreshConnections,
|
DispatcherProxiesDelayTest,
|
||||||
DispatcherRefreshProxyGroups,
|
DispatcherStatistics,
|
||||||
DispatcherProxiesDelayTest,
|
DispatcherServerAvailability,
|
||||||
DispatcherStatistics,
|
DispatcherReload,
|
||||||
DispatcherServerAvailability,
|
DispatcherRefreshServersBiz,
|
||||||
DispatcherReload,
|
DispatcherRefreshIcon,
|
||||||
DispatcherRefreshServersBiz,
|
DispatcherCheckUpdate,
|
||||||
DispatcherRefreshIcon,
|
DispatcherCheckUpdateFinished,
|
||||||
DispatcherCheckUpdate,
|
DispatcherShowMsg,
|
||||||
DispatcherCheckUpdateFinished,
|
}
|
||||||
DispatcherShowMsg,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,155 +1,155 @@
|
||||||
namespace ServiceLib
|
namespace ServiceLib;
|
||||||
|
|
||||||
|
public class Global
|
||||||
{
|
{
|
||||||
public class Global
|
#region const
|
||||||
{
|
|
||||||
#region const
|
|
||||||
|
|
||||||
public const string AppName = "v2rayN";
|
public const string AppName = "v2rayN";
|
||||||
public const string GithubUrl = "https://github.com";
|
public const string GithubUrl = "https://github.com";
|
||||||
public const string GithubApiUrl = "https://api.github.com/repos";
|
public const string GithubApiUrl = "https://api.github.com/repos";
|
||||||
public const string GeoUrl = "https://github.com/Loyalsoldier/v2ray-rules-dat/releases/latest/download/{0}.dat";
|
public const string GeoUrl = "https://github.com/Loyalsoldier/v2ray-rules-dat/releases/latest/download/{0}.dat";
|
||||||
public const string SpeedPingTestUrl = @"https://www.google.com/generate_204";
|
public const string SpeedPingTestUrl = @"https://www.google.com/generate_204";
|
||||||
public const string SingboxRulesetUrl = @"https://raw.githubusercontent.com/2dust/sing-box-rules/rule-set-{0}/{1}.srs";
|
public const string SingboxRulesetUrl = @"https://raw.githubusercontent.com/2dust/sing-box-rules/rule-set-{0}/{1}.srs";
|
||||||
public const string IPAPIUrl = "https://api.ip.sb/geoip";
|
public const string IPAPIUrl = "https://api.ip.sb/geoip";
|
||||||
|
|
||||||
public const string PromotionUrl = @"aHR0cHM6Ly85LjIzNDQ1Ni54eXovYWJjLmh0bWw=";
|
public const string PromotionUrl = @"aHR0cHM6Ly85LjIzNDQ1Ni54eXovYWJjLmh0bWw=";
|
||||||
public const string ConfigFileName = "guiNConfig.json";
|
public const string ConfigFileName = "guiNConfig.json";
|
||||||
public const string CoreConfigFileName = "config.json";
|
public const string CoreConfigFileName = "config.json";
|
||||||
public const string CorePreConfigFileName = "configPre.json";
|
public const string CorePreConfigFileName = "configPre.json";
|
||||||
public const string CoreSpeedtestConfigFileName = "configTest{0}.json";
|
public const string CoreSpeedtestConfigFileName = "configTest{0}.json";
|
||||||
public const string CoreMultipleLoadConfigFileName = "configMultipleLoad.json";
|
public const string CoreMultipleLoadConfigFileName = "configMultipleLoad.json";
|
||||||
public const string ClashMixinConfigFileName = "Mixin.yaml";
|
public const string ClashMixinConfigFileName = "Mixin.yaml";
|
||||||
|
|
||||||
public const string NamespaceSample = "ServiceLib.Sample.";
|
public const string NamespaceSample = "ServiceLib.Sample.";
|
||||||
public const string V2raySampleClient = NamespaceSample + "SampleClientConfig";
|
public const string V2raySampleClient = NamespaceSample + "SampleClientConfig";
|
||||||
public const string SingboxSampleClient = NamespaceSample + "SingboxSampleClientConfig";
|
public const string SingboxSampleClient = NamespaceSample + "SingboxSampleClientConfig";
|
||||||
public const string V2raySampleHttpRequestFileName = NamespaceSample + "SampleHttpRequest";
|
public const string V2raySampleHttpRequestFileName = NamespaceSample + "SampleHttpRequest";
|
||||||
public const string V2raySampleHttpResponseFileName = NamespaceSample + "SampleHttpResponse";
|
public const string V2raySampleHttpResponseFileName = NamespaceSample + "SampleHttpResponse";
|
||||||
public const string V2raySampleInbound = NamespaceSample + "SampleInbound";
|
public const string V2raySampleInbound = NamespaceSample + "SampleInbound";
|
||||||
public const string V2raySampleOutbound = NamespaceSample + "SampleOutbound";
|
public const string V2raySampleOutbound = NamespaceSample + "SampleOutbound";
|
||||||
public const string SingboxSampleOutbound = NamespaceSample + "SingboxSampleOutbound";
|
public const string SingboxSampleOutbound = NamespaceSample + "SingboxSampleOutbound";
|
||||||
public const string CustomRoutingFileName = NamespaceSample + "custom_routing_";
|
public const string CustomRoutingFileName = NamespaceSample + "custom_routing_";
|
||||||
public const string TunSingboxDNSFileName = NamespaceSample + "tun_singbox_dns";
|
public const string TunSingboxDNSFileName = NamespaceSample + "tun_singbox_dns";
|
||||||
public const string TunSingboxInboundFileName = NamespaceSample + "tun_singbox_inbound";
|
public const string TunSingboxInboundFileName = NamespaceSample + "tun_singbox_inbound";
|
||||||
public const string TunSingboxRulesFileName = NamespaceSample + "tun_singbox_rules";
|
public const string TunSingboxRulesFileName = NamespaceSample + "tun_singbox_rules";
|
||||||
public const string DNSV2rayNormalFileName = NamespaceSample + "dns_v2ray_normal";
|
public const string DNSV2rayNormalFileName = NamespaceSample + "dns_v2ray_normal";
|
||||||
public const string DNSSingboxNormalFileName = NamespaceSample + "dns_singbox_normal";
|
public const string DNSSingboxNormalFileName = NamespaceSample + "dns_singbox_normal";
|
||||||
public const string ClashMixinYaml = NamespaceSample + "clash_mixin_yaml";
|
public const string ClashMixinYaml = NamespaceSample + "clash_mixin_yaml";
|
||||||
public const string ClashTunYaml = NamespaceSample + "clash_tun_yaml";
|
public const string ClashTunYaml = NamespaceSample + "clash_tun_yaml";
|
||||||
public const string LinuxAutostartConfig = NamespaceSample + "linux_autostart_config";
|
public const string LinuxAutostartConfig = NamespaceSample + "linux_autostart_config";
|
||||||
public const string PacFileName = NamespaceSample + "pac";
|
public const string PacFileName = NamespaceSample + "pac";
|
||||||
public const string ProxySetOSXShellFileName = NamespaceSample + "proxy_set_osx_sh";
|
public const string ProxySetOSXShellFileName = NamespaceSample + "proxy_set_osx_sh";
|
||||||
public const string ProxySetLinuxShellFileName = NamespaceSample + "proxy_set_linux_sh";
|
public const string ProxySetLinuxShellFileName = NamespaceSample + "proxy_set_linux_sh";
|
||||||
|
|
||||||
public const string DefaultSecurity = "auto";
|
public const string DefaultSecurity = "auto";
|
||||||
public const string DefaultNetwork = "tcp";
|
public const string DefaultNetwork = "tcp";
|
||||||
public const string TcpHeaderHttp = "http";
|
public const string TcpHeaderHttp = "http";
|
||||||
public const string None = "none";
|
public const string None = "none";
|
||||||
public const string ProxyTag = "proxy";
|
public const string ProxyTag = "proxy";
|
||||||
public const string DirectTag = "direct";
|
public const string DirectTag = "direct";
|
||||||
public const string BlockTag = "block";
|
public const string BlockTag = "block";
|
||||||
public const string StreamSecurity = "tls";
|
public const string StreamSecurity = "tls";
|
||||||
public const string StreamSecurityReality = "reality";
|
public const string StreamSecurityReality = "reality";
|
||||||
public const string Loopback = "127.0.0.1";
|
public const string Loopback = "127.0.0.1";
|
||||||
public const string InboundAPIProtocol = "dokodemo-door";
|
public const string InboundAPIProtocol = "dokodemo-door";
|
||||||
public const string HttpProtocol = "http://";
|
public const string HttpProtocol = "http://";
|
||||||
public const string HttpsProtocol = "https://";
|
public const string HttpsProtocol = "https://";
|
||||||
public const string SocksProtocol = "socks://";
|
public const string SocksProtocol = "socks://";
|
||||||
public const string Socks5Protocol = "socks5://";
|
public const string Socks5Protocol = "socks5://";
|
||||||
|
|
||||||
public const string UserEMail = "t@t.tt";
|
public const string UserEMail = "t@t.tt";
|
||||||
public const string AutoRunRegPath = @"Software\Microsoft\Windows\CurrentVersion\Run";
|
public const string AutoRunRegPath = @"Software\Microsoft\Windows\CurrentVersion\Run";
|
||||||
public const string AutoRunName = "v2rayNAutoRun";
|
public const string AutoRunName = "v2rayNAutoRun";
|
||||||
public const string SystemProxyExceptionsWindows = "localhost;127.*;10.*;172.16.*;172.17.*;172.18.*;172.19.*;172.20.*;172.21.*;172.22.*;172.23.*;172.24.*;172.25.*;172.26.*;172.27.*;172.28.*;172.29.*;172.30.*;172.31.*;192.168.*";
|
public const string SystemProxyExceptionsWindows = "localhost;127.*;10.*;172.16.*;172.17.*;172.18.*;172.19.*;172.20.*;172.21.*;172.22.*;172.23.*;172.24.*;172.25.*;172.26.*;172.27.*;172.28.*;172.29.*;172.30.*;172.31.*;192.168.*";
|
||||||
public const string SystemProxyExceptionsLinux = "localhost,127.0.0.0/8,::1";
|
public const string SystemProxyExceptionsLinux = "localhost,127.0.0.0/8,::1";
|
||||||
public const string RoutingRuleComma = "<COMMA>";
|
public const string RoutingRuleComma = "<COMMA>";
|
||||||
public const string GrpcGunMode = "gun";
|
public const string GrpcGunMode = "gun";
|
||||||
public const string GrpcMultiMode = "multi";
|
public const string GrpcMultiMode = "multi";
|
||||||
public const int MaxPort = 65536;
|
public const int MaxPort = 65536;
|
||||||
public const int MinFontSize = 8;
|
public const int MinFontSize = 8;
|
||||||
public const string RebootAs = "rebootas";
|
public const string RebootAs = "rebootas";
|
||||||
public const string AvaAssets = "avares://v2rayN/Assets/";
|
public const string AvaAssets = "avares://v2rayN/Assets/";
|
||||||
public const string LocalAppData = "V2RAYN_LOCAL_APPLICATION_DATA_V2";
|
public const string LocalAppData = "V2RAYN_LOCAL_APPLICATION_DATA_V2";
|
||||||
public const string V2RayLocalAsset = "V2RAY_LOCATION_ASSET";
|
public const string V2RayLocalAsset = "V2RAY_LOCATION_ASSET";
|
||||||
public const string XrayLocalAsset = "XRAY_LOCATION_ASSET";
|
public const string XrayLocalAsset = "XRAY_LOCATION_ASSET";
|
||||||
public const string XrayLocalCert = "XRAY_LOCATION_CERT";
|
public const string XrayLocalCert = "XRAY_LOCATION_CERT";
|
||||||
public const int SpeedTestPageSize = 1000;
|
public const int SpeedTestPageSize = 1000;
|
||||||
public const string LinuxBash = "/bin/bash";
|
public const string LinuxBash = "/bin/bash";
|
||||||
|
|
||||||
public static readonly List<string> IEProxyProtocols =
|
public static readonly List<string> IEProxyProtocols =
|
||||||
[
|
[
|
||||||
"{ip}:{http_port}",
|
"{ip}:{http_port}",
|
||||||
"socks={ip}:{socks_port}",
|
"socks={ip}:{socks_port}",
|
||||||
"http={ip}:{http_port};https={ip}:{http_port};ftp={ip}:{http_port};socks={ip}:{socks_port}",
|
"http={ip}:{http_port};https={ip}:{http_port};ftp={ip}:{http_port};socks={ip}:{socks_port}",
|
||||||
"http=http://{ip}:{http_port};https=http://{ip}:{http_port}",
|
"http=http://{ip}:{http_port};https=http://{ip}:{http_port}",
|
||||||
""
|
""
|
||||||
];
|
];
|
||||||
|
|
||||||
public static readonly List<string> SubConvertUrls =
|
public static readonly List<string> SubConvertUrls =
|
||||||
[
|
[
|
||||||
@"https://sub.xeton.dev/sub?url={0}",
|
@"https://sub.xeton.dev/sub?url={0}",
|
||||||
@"https://api.dler.io/sub?url={0}",
|
@"https://api.dler.io/sub?url={0}",
|
||||||
@"http://127.0.0.1:25500/sub?url={0}",
|
@"http://127.0.0.1:25500/sub?url={0}",
|
||||||
""
|
""
|
||||||
];
|
];
|
||||||
|
|
||||||
public static readonly List<string> SubConvertConfig =
|
public static readonly List<string> SubConvertConfig =
|
||||||
[@"https://raw.githubusercontent.com/ACL4SSR/ACL4SSR/master/Clash/config/ACL4SSR_Online.ini"];
|
[@"https://raw.githubusercontent.com/ACL4SSR/ACL4SSR/master/Clash/config/ACL4SSR_Online.ini"];
|
||||||
|
|
||||||
public static readonly List<string> SubConvertTargets =
|
public static readonly List<string> SubConvertTargets =
|
||||||
[
|
[
|
||||||
"",
|
"",
|
||||||
"mixed",
|
"mixed",
|
||||||
"v2ray",
|
"v2ray",
|
||||||
"clash",
|
"clash",
|
||||||
"ss"
|
"ss"
|
||||||
];
|
];
|
||||||
|
|
||||||
public static readonly List<string> SpeedTestUrls =
|
public static readonly List<string> SpeedTestUrls =
|
||||||
[
|
[
|
||||||
@"https://cachefly.cachefly.net/50mb.test",
|
@"https://cachefly.cachefly.net/50mb.test",
|
||||||
@"https://speed.cloudflare.com/__down?bytes=10000000",
|
@"https://speed.cloudflare.com/__down?bytes=10000000",
|
||||||
@"https://speed.cloudflare.com/__down?bytes=50000000",
|
@"https://speed.cloudflare.com/__down?bytes=50000000",
|
||||||
@"https://speed.cloudflare.com/__down?bytes=100000000",
|
@"https://speed.cloudflare.com/__down?bytes=100000000",
|
||||||
];
|
];
|
||||||
|
|
||||||
public static readonly List<string> SpeedPingTestUrls =
|
public static readonly List<string> SpeedPingTestUrls =
|
||||||
[
|
[
|
||||||
@"https://www.google.com/generate_204",
|
@"https://www.google.com/generate_204",
|
||||||
@"https://www.gstatic.com/generate_204",
|
@"https://www.gstatic.com/generate_204",
|
||||||
@"https://www.apple.com/library/test/success.html",
|
@"https://www.apple.com/library/test/success.html",
|
||||||
@"http://www.msftconnecttest.com/connecttest.txt"
|
@"http://www.msftconnecttest.com/connecttest.txt"
|
||||||
];
|
];
|
||||||
|
|
||||||
public static readonly List<string> GeoFilesSources =
|
public static readonly List<string> GeoFilesSources =
|
||||||
[
|
[
|
||||||
"",
|
"",
|
||||||
@"https://github.com/runetfreedom/russia-v2ray-rules-dat/releases/latest/download/{0}.dat",
|
@"https://github.com/runetfreedom/russia-v2ray-rules-dat/releases/latest/download/{0}.dat",
|
||||||
@"https://cdn.jsdelivr.net/gh/chocolate4u/Iran-v2ray-rules@release/{0}.dat"
|
@"https://cdn.jsdelivr.net/gh/chocolate4u/Iran-v2ray-rules@release/{0}.dat"
|
||||||
];
|
];
|
||||||
|
|
||||||
public static readonly List<string> SingboxRulesetSources =
|
public static readonly List<string> SingboxRulesetSources =
|
||||||
[
|
[
|
||||||
"",
|
"",
|
||||||
@"https://cdn.jsdelivr.net/gh/runetfreedom/russia-v2ray-rules-dat@release/sing-box/rule-set-{0}/{1}.srs",
|
@"https://cdn.jsdelivr.net/gh/runetfreedom/russia-v2ray-rules-dat@release/sing-box/rule-set-{0}/{1}.srs",
|
||||||
@"https://cdn.jsdelivr.net/gh/chocolate4u/Iran-sing-box-rules@rule-set/{1}.srs"
|
@"https://cdn.jsdelivr.net/gh/chocolate4u/Iran-sing-box-rules@rule-set/{1}.srs"
|
||||||
];
|
];
|
||||||
|
|
||||||
public static readonly List<string> RoutingRulesSources =
|
public static readonly List<string> RoutingRulesSources =
|
||||||
[
|
[
|
||||||
"",
|
"",
|
||||||
@"https://cdn.jsdelivr.net/gh/runetfreedom/russia-v2ray-custom-routing-list@main/v2rayN/template.json",
|
@"https://cdn.jsdelivr.net/gh/runetfreedom/russia-v2ray-custom-routing-list@main/v2rayN/template.json",
|
||||||
@"https://cdn.jsdelivr.net/gh/Chocolate4U/Iran-v2ray-rules@main/v2rayN/template.json"
|
@"https://cdn.jsdelivr.net/gh/Chocolate4U/Iran-v2ray-rules@main/v2rayN/template.json"
|
||||||
];
|
];
|
||||||
|
|
||||||
public static readonly List<string> DNSTemplateSources =
|
public static readonly List<string> DNSTemplateSources =
|
||||||
[
|
[
|
||||||
"",
|
"",
|
||||||
@"https://cdn.jsdelivr.net/gh/runetfreedom/russia-v2ray-custom-routing-list@main/v2rayN/",
|
@"https://cdn.jsdelivr.net/gh/runetfreedom/russia-v2ray-custom-routing-list@main/v2rayN/",
|
||||||
@"https://cdn.jsdelivr.net/gh/Chocolate4U/Iran-v2ray-rules@main/v2rayN/"
|
@"https://cdn.jsdelivr.net/gh/Chocolate4U/Iran-v2ray-rules@main/v2rayN/"
|
||||||
];
|
];
|
||||||
|
|
||||||
public static readonly Dictionary<string, string> UserAgentTexts = new()
|
public static readonly Dictionary<string, string> UserAgentTexts = new()
|
||||||
{
|
{
|
||||||
{"chrome","Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.131 Safari/537.36" },
|
{"chrome","Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.131 Safari/537.36" },
|
||||||
{"firefox","Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:90.0) Gecko/20100101 Firefox/90.0" },
|
{"firefox","Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:90.0) Gecko/20100101 Firefox/90.0" },
|
||||||
|
@ -158,9 +158,9 @@ namespace ServiceLib
|
||||||
{"none",""}
|
{"none",""}
|
||||||
};
|
};
|
||||||
|
|
||||||
public const string Hysteria2ProtocolShare = "hy2://";
|
public const string Hysteria2ProtocolShare = "hy2://";
|
||||||
|
|
||||||
public static readonly Dictionary<EConfigType, string> ProtocolShares = new()
|
public static readonly Dictionary<EConfigType, string> ProtocolShares = new()
|
||||||
{
|
{
|
||||||
{ EConfigType.VMess, "vmess://" },
|
{ EConfigType.VMess, "vmess://" },
|
||||||
{ EConfigType.Shadowsocks, "ss://" },
|
{ EConfigType.Shadowsocks, "ss://" },
|
||||||
|
@ -172,7 +172,7 @@ namespace ServiceLib
|
||||||
{ EConfigType.WireGuard, "wireguard://" }
|
{ EConfigType.WireGuard, "wireguard://" }
|
||||||
};
|
};
|
||||||
|
|
||||||
public static readonly Dictionary<EConfigType, string> ProtocolTypes = new()
|
public static readonly Dictionary<EConfigType, string> ProtocolTypes = new()
|
||||||
{
|
{
|
||||||
{ EConfigType.VMess, "vmess" },
|
{ EConfigType.VMess, "vmess" },
|
||||||
{ EConfigType.Shadowsocks, "shadowsocks" },
|
{ EConfigType.Shadowsocks, "shadowsocks" },
|
||||||
|
@ -185,28 +185,28 @@ namespace ServiceLib
|
||||||
{ EConfigType.WireGuard, "wireguard" }
|
{ EConfigType.WireGuard, "wireguard" }
|
||||||
};
|
};
|
||||||
|
|
||||||
public static readonly List<string> VmessSecurities =
|
public static readonly List<string> VmessSecurities =
|
||||||
[
|
[
|
||||||
"aes-128-gcm",
|
"aes-128-gcm",
|
||||||
"chacha20-poly1305",
|
"chacha20-poly1305",
|
||||||
"auto",
|
"auto",
|
||||||
"none",
|
"none",
|
||||||
"zero"
|
"zero"
|
||||||
];
|
];
|
||||||
|
|
||||||
public static readonly List<string> SsSecurities =
|
public static readonly List<string> SsSecurities =
|
||||||
[
|
[
|
||||||
"aes-256-gcm",
|
"aes-256-gcm",
|
||||||
"aes-128-gcm",
|
"aes-128-gcm",
|
||||||
"chacha20-poly1305",
|
"chacha20-poly1305",
|
||||||
"chacha20-ietf-poly1305",
|
"chacha20-ietf-poly1305",
|
||||||
"none",
|
"none",
|
||||||
"plain"
|
"plain"
|
||||||
];
|
];
|
||||||
|
|
||||||
public static readonly List<string> SsSecuritiesInXray =
|
public static readonly List<string> SsSecuritiesInXray =
|
||||||
[
|
[
|
||||||
"aes-256-gcm",
|
"aes-256-gcm",
|
||||||
"aes-128-gcm",
|
"aes-128-gcm",
|
||||||
"chacha20-poly1305",
|
"chacha20-poly1305",
|
||||||
"chacha20-ietf-poly1305",
|
"chacha20-ietf-poly1305",
|
||||||
|
@ -217,11 +217,11 @@ namespace ServiceLib
|
||||||
"2022-blake3-aes-128-gcm",
|
"2022-blake3-aes-128-gcm",
|
||||||
"2022-blake3-aes-256-gcm",
|
"2022-blake3-aes-256-gcm",
|
||||||
"2022-blake3-chacha20-poly1305"
|
"2022-blake3-chacha20-poly1305"
|
||||||
];
|
];
|
||||||
|
|
||||||
public static readonly List<string> SsSecuritiesInSingbox =
|
public static readonly List<string> SsSecuritiesInSingbox =
|
||||||
[
|
[
|
||||||
"aes-256-gcm",
|
"aes-256-gcm",
|
||||||
"aes-192-gcm",
|
"aes-192-gcm",
|
||||||
"aes-128-gcm",
|
"aes-128-gcm",
|
||||||
"chacha20-ietf-poly1305",
|
"chacha20-ietf-poly1305",
|
||||||
|
@ -239,18 +239,18 @@ namespace ServiceLib
|
||||||
"rc4-md5",
|
"rc4-md5",
|
||||||
"chacha20-ietf",
|
"chacha20-ietf",
|
||||||
"xchacha20"
|
"xchacha20"
|
||||||
];
|
];
|
||||||
|
|
||||||
public static readonly List<string> Flows =
|
public static readonly List<string> Flows =
|
||||||
[
|
[
|
||||||
"",
|
"",
|
||||||
"xtls-rprx-vision",
|
"xtls-rprx-vision",
|
||||||
"xtls-rprx-vision-udp443"
|
"xtls-rprx-vision-udp443"
|
||||||
];
|
];
|
||||||
|
|
||||||
public static readonly List<string> Networks =
|
public static readonly List<string> Networks =
|
||||||
[
|
[
|
||||||
"tcp",
|
"tcp",
|
||||||
"kcp",
|
"kcp",
|
||||||
"ws",
|
"ws",
|
||||||
"httpupgrade",
|
"httpupgrade",
|
||||||
|
@ -258,50 +258,50 @@ namespace ServiceLib
|
||||||
"h2",
|
"h2",
|
||||||
"quic",
|
"quic",
|
||||||
"grpc"
|
"grpc"
|
||||||
];
|
];
|
||||||
|
|
||||||
public static readonly List<string> KcpHeaderTypes =
|
public static readonly List<string> KcpHeaderTypes =
|
||||||
[
|
[
|
||||||
"srtp",
|
"srtp",
|
||||||
"utp",
|
"utp",
|
||||||
"wechat-video",
|
"wechat-video",
|
||||||
"dtls",
|
"dtls",
|
||||||
"wireguard",
|
"wireguard",
|
||||||
"dns"
|
"dns"
|
||||||
];
|
];
|
||||||
|
|
||||||
public static readonly List<string> CoreTypes =
|
public static readonly List<string> CoreTypes =
|
||||||
[
|
[
|
||||||
"Xray",
|
"Xray",
|
||||||
"sing_box"
|
"sing_box"
|
||||||
];
|
];
|
||||||
|
|
||||||
public static readonly List<string> DomainStrategies =
|
public static readonly List<string> DomainStrategies =
|
||||||
[
|
[
|
||||||
"AsIs",
|
"AsIs",
|
||||||
"IPIfNonMatch",
|
"IPIfNonMatch",
|
||||||
"IPOnDemand"
|
"IPOnDemand"
|
||||||
];
|
];
|
||||||
|
|
||||||
public static readonly List<string> DomainStrategies4Singbox =
|
public static readonly List<string> DomainStrategies4Singbox =
|
||||||
[
|
[
|
||||||
"ipv4_only",
|
"ipv4_only",
|
||||||
"ipv6_only",
|
"ipv6_only",
|
||||||
"prefer_ipv4",
|
"prefer_ipv4",
|
||||||
"prefer_ipv6",
|
"prefer_ipv6",
|
||||||
""
|
""
|
||||||
];
|
];
|
||||||
|
|
||||||
public static readonly List<string> DomainMatchers =
|
public static readonly List<string> DomainMatchers =
|
||||||
[
|
[
|
||||||
"linear",
|
"linear",
|
||||||
"mph",
|
"mph",
|
||||||
""
|
""
|
||||||
];
|
];
|
||||||
|
|
||||||
public static readonly List<string> Fingerprints =
|
public static readonly List<string> Fingerprints =
|
||||||
[
|
[
|
||||||
"chrome",
|
"chrome",
|
||||||
"firefox",
|
"firefox",
|
||||||
"safari",
|
"safari",
|
||||||
"ios",
|
"ios",
|
||||||
|
@ -312,174 +312,174 @@ namespace ServiceLib
|
||||||
"random",
|
"random",
|
||||||
"randomized",
|
"randomized",
|
||||||
""
|
""
|
||||||
];
|
];
|
||||||
|
|
||||||
public static readonly List<string> UserAgent =
|
public static readonly List<string> UserAgent =
|
||||||
[
|
[
|
||||||
"chrome",
|
"chrome",
|
||||||
"firefox",
|
"firefox",
|
||||||
"safari",
|
"safari",
|
||||||
"edge",
|
"edge",
|
||||||
"none"
|
"none"
|
||||||
];
|
];
|
||||||
|
|
||||||
public static readonly List<string> XhttpMode =
|
public static readonly List<string> XhttpMode =
|
||||||
[
|
[
|
||||||
"auto",
|
"auto",
|
||||||
"packet-up",
|
"packet-up",
|
||||||
"stream-up",
|
"stream-up",
|
||||||
"stream-one"
|
"stream-one"
|
||||||
];
|
];
|
||||||
|
|
||||||
public static readonly List<string> AllowInsecure =
|
public static readonly List<string> AllowInsecure =
|
||||||
[
|
[
|
||||||
"true",
|
"true",
|
||||||
"false",
|
"false",
|
||||||
""
|
""
|
||||||
];
|
];
|
||||||
|
|
||||||
public static readonly List<string> DomainStrategy4Freedoms =
|
public static readonly List<string> DomainStrategy4Freedoms =
|
||||||
[
|
[
|
||||||
"AsIs",
|
"AsIs",
|
||||||
"UseIP",
|
"UseIP",
|
||||||
"UseIPv4",
|
"UseIPv4",
|
||||||
"UseIPv6",
|
"UseIPv6",
|
||||||
""
|
""
|
||||||
];
|
];
|
||||||
|
|
||||||
public static readonly List<string> SingboxDomainStrategy4Out =
|
public static readonly List<string> SingboxDomainStrategy4Out =
|
||||||
[
|
[
|
||||||
"ipv4_only",
|
"ipv4_only",
|
||||||
"prefer_ipv4",
|
"prefer_ipv4",
|
||||||
"prefer_ipv6",
|
"prefer_ipv6",
|
||||||
"ipv6_only",
|
"ipv6_only",
|
||||||
""
|
""
|
||||||
];
|
];
|
||||||
|
|
||||||
public static readonly List<string> DomainDNSAddress =
|
public static readonly List<string> DomainDNSAddress =
|
||||||
[
|
[
|
||||||
"223.5.5.5",
|
"223.5.5.5",
|
||||||
"223.6.6.6",
|
"223.6.6.6",
|
||||||
"localhost"
|
"localhost"
|
||||||
];
|
];
|
||||||
|
|
||||||
public static readonly List<string> SingboxDomainDNSAddress =
|
public static readonly List<string> SingboxDomainDNSAddress =
|
||||||
[
|
[
|
||||||
"223.5.5.5",
|
"223.5.5.5",
|
||||||
"223.6.6.6",
|
"223.6.6.6",
|
||||||
"dhcp://auto"
|
"dhcp://auto"
|
||||||
];
|
];
|
||||||
|
|
||||||
public static readonly List<string> Languages =
|
public static readonly List<string> Languages =
|
||||||
[
|
[
|
||||||
"zh-Hans",
|
"zh-Hans",
|
||||||
"zh-Hant",
|
"zh-Hant",
|
||||||
"en",
|
"en",
|
||||||
"fa-Ir",
|
"fa-Ir",
|
||||||
"ru",
|
"ru",
|
||||||
"hu"
|
"hu"
|
||||||
];
|
];
|
||||||
|
|
||||||
public static readonly List<string> Alpns =
|
public static readonly List<string> Alpns =
|
||||||
[
|
[
|
||||||
"h3",
|
"h3",
|
||||||
"h2",
|
"h2",
|
||||||
"http/1.1",
|
"http/1.1",
|
||||||
"h3,h2",
|
"h3,h2",
|
||||||
"h2,http/1.1",
|
"h2,http/1.1",
|
||||||
"h3,h2,http/1.1",
|
"h3,h2,http/1.1",
|
||||||
""
|
""
|
||||||
];
|
];
|
||||||
|
|
||||||
public static readonly List<string> LogLevels =
|
public static readonly List<string> LogLevels =
|
||||||
[
|
[
|
||||||
"debug",
|
"debug",
|
||||||
"info",
|
"info",
|
||||||
"warning",
|
"warning",
|
||||||
"error",
|
"error",
|
||||||
"none"
|
"none"
|
||||||
];
|
];
|
||||||
|
|
||||||
public static readonly List<string> InboundTags =
|
public static readonly List<string> InboundTags =
|
||||||
[
|
[
|
||||||
"socks",
|
"socks",
|
||||||
"socks2",
|
"socks2",
|
||||||
"socks3"
|
"socks3"
|
||||||
];
|
];
|
||||||
|
|
||||||
public static readonly List<string> RuleProtocols =
|
public static readonly List<string> RuleProtocols =
|
||||||
[
|
[
|
||||||
"http",
|
"http",
|
||||||
"tls",
|
"tls",
|
||||||
"bittorrent"
|
"bittorrent"
|
||||||
];
|
];
|
||||||
|
|
||||||
public static readonly List<string> RuleNetworks =
|
public static readonly List<string> RuleNetworks =
|
||||||
[
|
[
|
||||||
"",
|
"",
|
||||||
"tcp",
|
"tcp",
|
||||||
"udp",
|
"udp",
|
||||||
"tcp,udp"
|
"tcp,udp"
|
||||||
];
|
];
|
||||||
|
|
||||||
public static readonly List<string> destOverrideProtocols =
|
public static readonly List<string> destOverrideProtocols =
|
||||||
[
|
[
|
||||||
"http",
|
"http",
|
||||||
"tls",
|
"tls",
|
||||||
"quic",
|
"quic",
|
||||||
"fakedns",
|
"fakedns",
|
||||||
"fakedns+others"
|
"fakedns+others"
|
||||||
];
|
];
|
||||||
|
|
||||||
public static readonly List<int> TunMtus =
|
public static readonly List<int> TunMtus =
|
||||||
[
|
[
|
||||||
1280,
|
1280,
|
||||||
1408,
|
1408,
|
||||||
1500,
|
1500,
|
||||||
9000
|
9000
|
||||||
];
|
];
|
||||||
|
|
||||||
public static readonly List<string> TunStacks =
|
public static readonly List<string> TunStacks =
|
||||||
[
|
[
|
||||||
"gvisor",
|
"gvisor",
|
||||||
"system",
|
"system",
|
||||||
"mixed"
|
"mixed"
|
||||||
];
|
];
|
||||||
|
|
||||||
public static readonly List<string> PresetMsgFilters =
|
public static readonly List<string> PresetMsgFilters =
|
||||||
[
|
[
|
||||||
"proxy",
|
"proxy",
|
||||||
"direct",
|
"direct",
|
||||||
"block",
|
"block",
|
||||||
""
|
""
|
||||||
];
|
];
|
||||||
|
|
||||||
public static readonly List<string> SingboxMuxs =
|
public static readonly List<string> SingboxMuxs =
|
||||||
[
|
[
|
||||||
"h2mux",
|
"h2mux",
|
||||||
"smux",
|
"smux",
|
||||||
"yamux",
|
"yamux",
|
||||||
""
|
""
|
||||||
];
|
];
|
||||||
|
|
||||||
public static readonly List<string> TuicCongestionControls =
|
public static readonly List<string> TuicCongestionControls =
|
||||||
[
|
[
|
||||||
"cubic",
|
"cubic",
|
||||||
"new_reno",
|
"new_reno",
|
||||||
"bbr"
|
"bbr"
|
||||||
];
|
];
|
||||||
|
|
||||||
public static readonly List<string> allowSelectType =
|
public static readonly List<string> allowSelectType =
|
||||||
[
|
[
|
||||||
"selector",
|
"selector",
|
||||||
"urltest",
|
"urltest",
|
||||||
"loadbalance",
|
"loadbalance",
|
||||||
"fallback"
|
"fallback"
|
||||||
];
|
];
|
||||||
|
|
||||||
public static readonly List<string> notAllowTestType =
|
public static readonly List<string> notAllowTestType =
|
||||||
[
|
[
|
||||||
"selector",
|
"selector",
|
||||||
"urltest",
|
"urltest",
|
||||||
"direct",
|
"direct",
|
||||||
"reject",
|
"reject",
|
||||||
|
@ -487,15 +487,15 @@ namespace ServiceLib
|
||||||
"pass",
|
"pass",
|
||||||
"loadbalance",
|
"loadbalance",
|
||||||
"fallback"
|
"fallback"
|
||||||
];
|
];
|
||||||
|
|
||||||
public static readonly List<string> proxyVehicleType =
|
public static readonly List<string> proxyVehicleType =
|
||||||
[
|
[
|
||||||
"file",
|
"file",
|
||||||
"http"
|
"http"
|
||||||
];
|
];
|
||||||
|
|
||||||
public static readonly Dictionary<ECoreType, string> CoreUrls = new()
|
public static readonly Dictionary<ECoreType, string> CoreUrls = new()
|
||||||
{
|
{
|
||||||
{ ECoreType.v2fly, "v2fly/v2ray-core" },
|
{ ECoreType.v2fly, "v2fly/v2ray-core" },
|
||||||
{ ECoreType.v2fly_v5, "v2fly/v2ray-core" },
|
{ ECoreType.v2fly_v5, "v2fly/v2ray-core" },
|
||||||
|
@ -512,13 +512,12 @@ namespace ServiceLib
|
||||||
{ ECoreType.v2rayN, "2dust/v2rayN" },
|
{ ECoreType.v2rayN, "2dust/v2rayN" },
|
||||||
};
|
};
|
||||||
|
|
||||||
public static readonly List<string> OtherGeoUrls =
|
public static readonly List<string> OtherGeoUrls =
|
||||||
[
|
[
|
||||||
@"https://raw.githubusercontent.com/Loyalsoldier/geoip/release/geoip-only-cn-private.dat",
|
@"https://raw.githubusercontent.com/Loyalsoldier/geoip/release/geoip-only-cn-private.dat",
|
||||||
@"https://raw.githubusercontent.com/Loyalsoldier/geoip/release/Country.mmdb",
|
@"https://raw.githubusercontent.com/Loyalsoldier/geoip/release/Country.mmdb",
|
||||||
@"https://github.com/MetaCubeX/meta-rules-dat/releases/download/latest/geoip.metadb"
|
@"https://github.com/MetaCubeX/meta-rules-dat/releases/download/latest/geoip.metadb"
|
||||||
];
|
];
|
||||||
|
|
||||||
#endregion const
|
#endregion const
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,244 +1,247 @@
|
||||||
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
|
get
|
||||||
|
|
||||||
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
|
_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);
|
||||||
|
|
||||||
|
//First determine the port value
|
||||||
|
_ = StatePort;
|
||||||
|
_ = StatePort2;
|
||||||
|
|
||||||
|
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
|
return await SQLiteHelper.Instance.TableAsync<ProfileItem>().ToListAsync();
|
||||||
{
|
|
||||||
_statePort2 ??= Utils.GetFreePort(GetLocalPort(EInboundProtocol.api2));
|
|
||||||
return _statePort2.Value + (_config.TunModeItem.EnableTun ? 1 : 0);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
else
|
||||||
public bool IsAdministrator
|
|
||||||
{
|
{
|
||||||
get
|
return await SQLiteHelper.Instance.TableAsync<ProfileItem>().Where(t => t.Subid == subid).ToListAsync();
|
||||||
{
|
|
||||||
_isAdministrator ??= Utils.IsAdministrator();
|
|
||||||
return _isAdministrator.Value;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#endregion Property
|
public async Task<List<string>?> ProfileItemIndexes(string subid)
|
||||||
|
{
|
||||||
|
return (await ProfileItems(subid))?.Select(t => t.IndexId)?.ToList();
|
||||||
|
}
|
||||||
|
|
||||||
#region Init
|
public async Task<List<ProfileItemModel>?> ProfileItems(string subid, string filter)
|
||||||
|
{
|
||||||
public bool InitApp()
|
var sql = @$"select a.*
|
||||||
{
|
|
||||||
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.*
|
|
||||||
,b.remarks subRemarks
|
,b.remarks subRemarks
|
||||||
from ProfileItem a
|
from ProfileItem a
|
||||||
left join SubItem b on a.subid = b.id
|
left join SubItem b on a.subid = b.id
|
||||||
where 1=1 ";
|
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())
|
sql += string.Format(" and (a.remarks like '%{0}%' or a.address like '%{0}%') ", filter);
|
||||||
{
|
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<ProfileItem?> GetProfileItem(string indexId)
|
return await SQLiteHelper.Instance.QueryAsync<ProfileItemModel>(sql);
|
||||||
{
|
|
||||||
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
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,223 +1,223 @@
|
||||||
using System.Security.Principal;
|
using System.Security.Principal;
|
||||||
using System.Text.RegularExpressions;
|
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";
|
if (Utils.IsWindows())
|
||||||
|
|
||||||
public static async Task<bool> UpdateTask(Config config)
|
|
||||||
{
|
{
|
||||||
if (Utils.IsWindows())
|
await ClearTaskWindows();
|
||||||
|
|
||||||
|
if (config.GuiItem.AutoRun)
|
||||||
{
|
{
|
||||||
await ClearTaskWindows();
|
await SetTaskWindows();
|
||||||
|
|
||||||
if (config.GuiItem.AutoRun)
|
|
||||||
{
|
|
||||||
await SetTaskWindows();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else if (Utils.IsLinux())
|
}
|
||||||
|
else if (Utils.IsLinux())
|
||||||
|
{
|
||||||
|
await ClearTaskLinux();
|
||||||
|
|
||||||
|
if (config.GuiItem.AutoRun)
|
||||||
{
|
{
|
||||||
await ClearTaskLinux();
|
await SetTaskLinux();
|
||||||
|
|
||||||
if (config.GuiItem.AutoRun)
|
|
||||||
{
|
|
||||||
await SetTaskLinux();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else if (Utils.IsOSX())
|
}
|
||||||
|
else if (Utils.IsOSX())
|
||||||
|
{
|
||||||
|
await ClearTaskOSX();
|
||||||
|
|
||||||
|
if (config.GuiItem.AutoRun)
|
||||||
{
|
{
|
||||||
await ClearTaskOSX();
|
await SetTaskOSX();
|
||||||
|
|
||||||
if (config.GuiItem.AutoRun)
|
|
||||||
{
|
|
||||||
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();
|
var autoRunName = GetAutoRunNameWindows();
|
||||||
WindowsUtils.RegWriteValue(Global.AutoRunRegPath, autoRunName, "");
|
var exePath = Utils.GetExePath();
|
||||||
if (Utils.IsAdministrator())
|
if (Utils.IsAdministrator())
|
||||||
{
|
{
|
||||||
AutoStartTaskService(autoRunName, "", "");
|
AutoStartTaskService(autoRunName, exePath, "");
|
||||||
}
|
}
|
||||||
|
else
|
||||||
await Task.CompletedTask;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static async Task SetTaskWindows()
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
{
|
||||||
var autoRunName = GetAutoRunNameWindows();
|
WindowsUtils.RegWriteValue(Global.AutoRunRegPath, autoRunName, exePath.AppendQuotes());
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
catch (Exception ex)
|
||||||
private static string GetHomePathLinux()
|
|
||||||
{
|
{
|
||||||
var homePath = Path.Combine(Utils.GetHomePath(), ".config", "autostart", $"{Global.AppName}.desktop");
|
Logging.SaveLog(_tag, ex);
|
||||||
Directory.CreateDirectory(Path.GetDirectoryName(homePath));
|
}
|
||||||
return homePath;
|
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
|
var logonUser = WindowsIdentity.GetCurrent().Name;
|
||||||
|
using var taskService = new Microsoft.Win32.TaskScheduler.TaskService();
|
||||||
#region macOS
|
var tasks = taskService.RootFolder.GetTasks(new Regex(taskName));
|
||||||
|
if (fileName.IsNullOrEmpty())
|
||||||
private static async Task ClearTaskOSX()
|
|
||||||
{
|
{
|
||||||
try
|
foreach (var t in tasks)
|
||||||
{
|
{
|
||||||
var launchAgentPath = GetLaunchAgentPathMacOS();
|
taskService.RootFolder.DeleteTask(t.Name);
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static async Task SetTaskOSX()
|
var task = taskService.NewTask();
|
||||||
{
|
task.RegistrationInfo.Description = description;
|
||||||
try
|
task.Settings.DisallowStartIfOnBatteries = false;
|
||||||
{
|
task.Settings.StopIfGoingOnBatteries = false;
|
||||||
var plistContent = GenerateLaunchAgentPlist();
|
task.Settings.RunOnlyIfIdle = false;
|
||||||
var launchAgentPath = GetLaunchAgentPathMacOS();
|
task.Settings.IdleSettings.StopOnIdleEnd = false;
|
||||||
await File.WriteAllTextAsync(launchAgentPath, plistContent);
|
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);
|
await Utils.GetCliWrapOutput(Global.LinuxBash, args);
|
||||||
}
|
|
||||||
catch (Exception ex)
|
File.Delete(launchAgentPath);
|
||||||
{
|
|
||||||
Logging.SaveLog(_tag, ex);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
catch (Exception ex)
|
||||||
private static string GetLaunchAgentPathMacOS()
|
|
||||||
{
|
{
|
||||||
var homePath = Environment.GetFolderPath(Environment.SpecialFolder.UserProfile);
|
Logging.SaveLog(_tag, ex);
|
||||||
var launchAgentPath = Path.Combine(homePath, "Library", "LaunchAgents", $"{Global.AppName}-LaunchAgent.plist");
|
|
||||||
Directory.CreateDirectory(Path.GetDirectoryName(launchAgentPath));
|
|
||||||
return launchAgentPath;
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private static string GenerateLaunchAgentPlist()
|
private static async Task SetTaskOSX()
|
||||||
|
{
|
||||||
|
try
|
||||||
{
|
{
|
||||||
var exePath = Utils.GetExePath();
|
var plistContent = GenerateLaunchAgentPlist();
|
||||||
var appName = Path.GetFileNameWithoutExtension(exePath);
|
var launchAgentPath = GetLaunchAgentPathMacOS();
|
||||||
return $@"<?xml version=""1.0"" encoding=""UTF-8""?>
|
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"">
|
<!DOCTYPE plist PUBLIC ""-//Apple//DTD PLIST 1.0//EN"" ""http://www.apple.com/DTDs/PropertyList-1.0.dtd"">
|
||||||
<plist version=""1.0"">
|
<plist version=""1.0"">
|
||||||
<dict>
|
<dict>
|
||||||
|
@ -235,8 +235,7 @@ namespace ServiceLib.Handler
|
||||||
<false/>
|
<false/>
|
||||||
</dict>
|
</dict>
|
||||||
</plist>";
|
</plist>";
|
||||||
}
|
|
||||||
|
|
||||||
#endregion macOS
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endregion macOS
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,188 +1,187 @@
|
||||||
using static ServiceLib.Models.ClashProxies;
|
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());
|
for (var i = 0; i < 3; i++)
|
||||||
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++)
|
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";
|
_proxies = clashProxies?.proxies;
|
||||||
var result = await HttpClientHelper.Instance.TryGetAsync(url);
|
return new Tuple<ClashProxies, ClashProviders>(clashProxies, clashProviders);
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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();
|
||||||
{
|
|
||||||
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(),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
lstProxy = new List<ClashProxyModel>();
|
||||||
if (lstProxy is not { Count: > 0 })
|
foreach (var kv in _proxies ?? [])
|
||||||
{
|
{
|
||||||
return;
|
if (Global.notAllowTestType.Contains(kv.Value.type?.ToLower()))
|
||||||
}
|
|
||||||
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()))
|
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
var name = it.Name;
|
lstProxy.Add(new ClashProxyModel()
|
||||||
var url = string.Format(urlBase, name);
|
|
||||||
tasks.Add(Task.Run(async () =>
|
|
||||||
{
|
{
|
||||||
var result = await HttpClientHelper.Instance.TryGetAsync(url);
|
Name = kv.Value.name,
|
||||||
updateFunc?.Invoke(it, result);
|
Type = kv.Value.type?.ToLower(),
|
||||||
}));
|
});
|
||||||
}
|
}
|
||||||
await Task.WhenAll(tasks);
|
}
|
||||||
await Task.Delay(1000);
|
|
||||||
updateFunc?.Invoke(null, "");
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<ProxiesItem>? GetClashProxyGroups()
|
if (lstProxy is not { Count: > 0 })
|
||||||
{
|
|
||||||
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)
|
|
||||||
{
|
{
|
||||||
return;
|
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 List<ProxiesItem>? GetClashProxyGroups()
|
||||||
}
|
{
|
||||||
|
try
|
||||||
public async Task ClashConfigReload(string filePath)
|
|
||||||
{
|
{
|
||||||
await ClashConnectionClose("");
|
var fileContent = ProfileContent;
|
||||||
try
|
if (fileContent is null || fileContent?.ContainsKey("proxy-groups") == false)
|
||||||
{
|
{
|
||||||
var url = $"{GetApiUrl()}/configs?force=true";
|
return null;
|
||||||
var headers = new Dictionary<string, string>();
|
|
||||||
headers.Add("path", filePath);
|
|
||||||
await HttpClientHelper.Instance.PutAsync(url, headers);
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
Logging.SaveLog(_tag, ex);
|
|
||||||
}
|
}
|
||||||
|
return JsonUtils.Deserialize<List<ProxiesItem>>(JsonUtils.Serialize(fileContent["proxy-groups"]));
|
||||||
}
|
}
|
||||||
|
catch (Exception ex)
|
||||||
public async Task<ClashConnections?> GetClashConnectionsAsync()
|
|
||||||
{
|
{
|
||||||
try
|
Logging.SaveLog(_tag, ex);
|
||||||
{
|
|
||||||
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;
|
return null;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public async Task ClashConnectionClose(string id)
|
public async Task ClashSetActiveProxy(string name, string nameNode)
|
||||||
|
{
|
||||||
|
try
|
||||||
{
|
{
|
||||||
try
|
var url = $"{GetApiUrl()}/proxies/{name}";
|
||||||
{
|
var headers = new Dictionary<string, string>();
|
||||||
var url = $"{GetApiUrl()}/connections/{id}";
|
headers.Add("name", nameNode);
|
||||||
await HttpClientHelper.Instance.DeleteAsync(url);
|
await HttpClientHelper.Instance.PutAsync(url, headers);
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
Logging.SaveLog(_tag, ex);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
catch (Exception ex)
|
||||||
private string GetApiUrl()
|
|
||||||
{
|
{
|
||||||
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
|
@ -1,156 +1,155 @@
|
||||||
namespace ServiceLib.Handler
|
namespace ServiceLib.Handler;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Core configuration file processing class
|
||||||
|
/// </summary>
|
||||||
|
public class CoreConfigHandler
|
||||||
{
|
{
|
||||||
/// <summary>
|
private static readonly string _tag = "CoreConfigHandler";
|
||||||
/// Core configuration file processing class
|
|
||||||
/// </summary>
|
public static async Task<RetResult> GenerateClientConfig(ProfileItem node, string? fileName)
|
||||||
public class CoreConfigHandler
|
|
||||||
{
|
{
|
||||||
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;
|
result = node.CoreType switch
|
||||||
var result = new RetResult();
|
|
||||||
|
|
||||||
if (node.ConfigType == EConfigType.Custom)
|
|
||||||
{
|
{
|
||||||
result = node.CoreType switch
|
ECoreType.mihomo => await new CoreConfigClashService(config).GenerateClientCustomConfig(node, fileName),
|
||||||
{
|
ECoreType.sing_box => await new CoreConfigSingboxService(config).GenerateClientCustomConfig(node, fileName),
|
||||||
ECoreType.mihomo => await new CoreConfigClashService(config).GenerateClientCustomConfig(node, fileName),
|
_ => await 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)
|
||||||
}
|
{
|
||||||
else if (AppHandler.Instance.GetCoreType(node, node.ConfigType) == ECoreType.sing_box)
|
result = await new CoreConfigSingboxService(config).GenerateClientConfigContent(node);
|
||||||
{
|
}
|
||||||
result = await new CoreConfigSingboxService(config).GenerateClientConfigContent(node);
|
else
|
||||||
}
|
{
|
||||||
else
|
result = await new CoreConfigV2rayService(config).GenerateClientConfigContent(node);
|
||||||
{
|
}
|
||||||
result = await new CoreConfigV2rayService(config).GenerateClientConfigContent(node);
|
if (result.Success != true)
|
||||||
}
|
{
|
||||||
if (result.Success != true)
|
|
||||||
{
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
if (fileName.IsNotEmpty() && result.Data != null)
|
|
||||||
{
|
|
||||||
await File.WriteAllTextAsync(fileName, result.Data.ToString());
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
if (fileName.IsNotEmpty() && result.Data != null)
|
||||||
private static async Task<RetResult> GenerateClientCustomConfig(ProfileItem node, string? fileName)
|
|
||||||
{
|
{
|
||||||
var ret = new RetResult();
|
await File.WriteAllTextAsync(fileName, result.Data.ToString());
|
||||||
try
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
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;
|
ret.Msg = ResUI.FailedGenDefaultConfiguration;
|
||||||
return ret;
|
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);
|
||||||
}
|
}
|
||||||
|
catch (Exception ex)
|
||||||
public static async Task<RetResult> GenerateClientSpeedtestConfig(Config config, string fileName, List<ServerTestItem> selecteds, ECoreType coreType)
|
|
||||||
{
|
{
|
||||||
var result = new RetResult();
|
Logging.SaveLog(_tag, ex);
|
||||||
if (coreType == ECoreType.sing_box)
|
ret.Msg = ResUI.FailedGenDefaultConfiguration;
|
||||||
{
|
return ret;
|
||||||
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)
|
|
||||||
{
|
|
||||||
var result = new RetResult();
|
|
||||||
if (coreType == ECoreType.sing_box)
|
|
||||||
{
|
|
||||||
result = await new CoreConfigSingboxService(config).GenerateClientMultipleLoadConfig(selecteds);
|
|
||||||
}
|
|
||||||
else if (coreType == ECoreType.Xray)
|
|
||||||
{
|
|
||||||
result = await new CoreConfigV2rayService(config).GenerateClientMultipleLoadConfig(selecteds);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (result.Success != true)
|
|
||||||
{
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
await File.WriteAllTextAsync(fileName, result.Data.ToString());
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,410 +1,409 @@
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
|
||||||
namespace ServiceLib.Handler
|
namespace ServiceLib.Handler;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Core process processing class
|
||||||
|
/// </summary>
|
||||||
|
public class CoreHandler
|
||||||
{
|
{
|
||||||
/// <summary>
|
private static readonly Lazy<CoreHandler> _instance = new(() => new());
|
||||||
/// Core process processing class
|
public static CoreHandler Instance => _instance.Value;
|
||||||
/// </summary>
|
private Config _config;
|
||||||
public class CoreHandler
|
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());
|
_config = config;
|
||||||
public static CoreHandler Instance => _instance.Value;
|
_updateFunc = updateFunc;
|
||||||
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)
|
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;
|
var fromPath = Utils.GetBaseDirectory("bin");
|
||||||
_updateFunc = updateFunc;
|
var toPath = Utils.GetBinPath("");
|
||||||
|
if (fromPath != toPath)
|
||||||
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");
|
FileManager.CopyDirectory(fromPath, toPath, true, false);
|
||||||
var toPath = Utils.GetBinPath("");
|
|
||||||
if (fromPath != toPath)
|
|
||||||
{
|
|
||||||
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();
|
if (it.CoreType == ECoreType.v2rayN)
|
||||||
foreach (var it in coreInfo)
|
|
||||||
{
|
{
|
||||||
if (it.CoreType == ECoreType.v2rayN)
|
if (Utils.UpgradeAppExists(out var upgradeFileName))
|
||||||
{
|
{
|
||||||
if (Utils.UpgradeAppExists(out var upgradeFileName))
|
await Utils.SetLinuxChmod(upgradeFileName);
|
||||||
{
|
|
||||||
await Utils.SetLinuxChmod(upgradeFileName);
|
|
||||||
}
|
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
|
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());
|
await Utils.SetLinuxChmod(exe);
|
||||||
if (File.Exists(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 fileName = Utils.GetBinConfigPath(Global.CoreConfigFileName);
|
||||||
var result = await CoreConfigHandler.GenerateClientConfig(node, fileName);
|
var result = await CoreConfigHandler.GenerateClientConfig(node, fileName);
|
||||||
if (result.Success != true)
|
if (result.Success != true)
|
||||||
{
|
{
|
||||||
UpdateFunc(true, result.Msg);
|
UpdateFunc(true, result.Msg);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
UpdateFunc(false, $"{node.GetSummary()}");
|
UpdateFunc(false, $"{node.GetSummary()}");
|
||||||
UpdateFunc(false, $"{Utils.GetRuntimeInfo()}");
|
UpdateFunc(false, $"{Utils.GetRuntimeInfo()}");
|
||||||
UpdateFunc(false, string.Format(ResUI.StartService, DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss")));
|
UpdateFunc(false, string.Format(ResUI.StartService, DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss")));
|
||||||
await CoreStop();
|
await CoreStop();
|
||||||
|
await Task.Delay(100);
|
||||||
|
|
||||||
|
if (Utils.IsWindows() && _config.TunModeItem.EnableTun)
|
||||||
|
{
|
||||||
await Task.Delay(100);
|
await Task.Delay(100);
|
||||||
|
await WindowsUtils.RemoveTunDevice();
|
||||||
|
}
|
||||||
|
|
||||||
if (Utils.IsWindows() && _config.TunModeItem.EnableTun)
|
await CoreStart(node);
|
||||||
{
|
await CoreStartPreService(node);
|
||||||
await Task.Delay(100);
|
if (_process != null)
|
||||||
await WindowsUtils.RemoveTunDevice();
|
{
|
||||||
}
|
UpdateFunc(true, $"{node.GetSummary()}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
await CoreStart(node);
|
public async Task<int> LoadCoreConfigSpeedtest(List<ServerTestItem> selecteds)
|
||||||
await CoreStartPreService(node);
|
{
|
||||||
|
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)
|
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;
|
||||||
}
|
}
|
||||||
|
catch (Exception ex)
|
||||||
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;
|
Logging.SaveLog(_tag, ex);
|
||||||
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)
|
#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);
|
return;
|
||||||
if (node is null)
|
}
|
||||||
{
|
_process = proc;
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
private async Task CoreStartPreService(ProfileItem node)
|
||||||
|
{
|
||||||
|
if (_process != null && !_process.HasExited)
|
||||||
|
{
|
||||||
var coreType = AppHandler.Instance.GetCoreType(node, node.ConfigType);
|
var coreType = AppHandler.Instance.GetCoreType(node, node.ConfigType);
|
||||||
var coreInfo = CoreInfoHandler.Instance.GetCoreInfo(coreType);
|
var itemSocks = await ConfigHandler.GetPreSocksItem(_config, node, coreType);
|
||||||
var proc = await RunProcess(coreInfo, fileName, true, false);
|
if (itemSocks != null)
|
||||||
if (proc is null)
|
|
||||||
{
|
{
|
||||||
return -1;
|
var preCoreType = itemSocks.CoreType ?? ECoreType.sing_box;
|
||||||
}
|
var fileName = Utils.GetBinConfigPath(Global.CorePreConfigFileName);
|
||||||
|
var result = await CoreConfigHandler.GenerateClientConfig(itemSocks, fileName);
|
||||||
return proc.Id;
|
if (result.Success)
|
||||||
}
|
|
||||||
|
|
||||||
public async Task CoreStop()
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
if (_process != null)
|
|
||||||
{
|
{
|
||||||
await ProcUtils.ProcessKill(_process, true);
|
var coreInfo = CoreInfoHandler.Instance.GetCoreInfo(preCoreType);
|
||||||
_process = null;
|
var proc = await RunProcess(coreInfo, Global.CorePreConfigFileName, true, true);
|
||||||
}
|
if (proc is 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);
|
return;
|
||||||
var proc = await RunProcess(coreInfo, Global.CorePreConfigFileName, true, true);
|
|
||||||
if (proc is null)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
_processPre = proc;
|
|
||||||
}
|
}
|
||||||
|
_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()
|
Process proc = new()
|
||||||
{
|
{
|
||||||
StartInfo = new()
|
StartInfo = new()
|
||||||
{
|
{
|
||||||
FileName = shFilePath,
|
FileName = fileName,
|
||||||
|
Arguments = string.Format(coreInfo.Arguments, coreInfo.AbsolutePath ? Utils.GetBinConfigPath(configPath).AppendQuotes() : configPath),
|
||||||
|
WorkingDirectory = Utils.GetBinConfigPath(),
|
||||||
UseShellExecute = false,
|
UseShellExecute = false,
|
||||||
|
RedirectStandardOutput = displayLog,
|
||||||
|
RedirectStandardError = displayLog,
|
||||||
CreateNoWindow = true,
|
CreateNoWindow = true,
|
||||||
StandardInputEncoding = Encoding.UTF8,
|
StandardOutputEncoding = displayLog ? Encoding.UTF8 : null,
|
||||||
RedirectStandardInput = true
|
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();
|
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);
|
||||||
var pwd = DesUtils.Decrypt(_config.TunModeItem.LinuxSudoPwd);
|
await proc.StandardInput.WriteLineAsync(pwd);
|
||||||
await Task.Delay(10);
|
await Task.Delay(10);
|
||||||
await proc.StandardInput.WriteLineAsync(pwd);
|
await proc.StandardInput.WriteLineAsync(pwd);
|
||||||
await Task.Delay(10);
|
}
|
||||||
await proc.StandardInput.WriteLineAsync(pwd);
|
if (isNeedSudo)
|
||||||
}
|
_linuxSudoPid = proc.Id;
|
||||||
catch (Exception)
|
|
||||||
{
|
if (displayLog)
|
||||||
// ignored
|
{
|
||||||
}
|
proc.BeginOutputReadLine();
|
||||||
|
proc.BeginErrorReadLine();
|
||||||
}
|
}
|
||||||
|
|
||||||
var timeout = new CancellationTokenSource(TimeSpan.FromSeconds(10));
|
await Task.Delay(500);
|
||||||
await proc.WaitForExitAsync(timeout.Token);
|
AppHandler.Instance.AddProcess(proc.Handle);
|
||||||
await Task.Delay(3000);
|
if (proc is null or { HasExited: true })
|
||||||
|
{
|
||||||
|
throw new Exception(ResUI.FailedToRunCore);
|
||||||
|
}
|
||||||
|
return proc;
|
||||||
}
|
}
|
||||||
|
catch (Exception ex)
|
||||||
private async Task<string> CreateLinuxShellFile(string cmdLine, string fileName)
|
|
||||||
{
|
{
|
||||||
//Shell scripts
|
Logging.SaveLog(_tag, ex);
|
||||||
var shFilePath = Utils.GetBinConfigPath(AppHandler.Instance.IsAdministrator ? "root_" + fileName : fileName);
|
UpdateFunc(mayNeedSudo, ex.Message);
|
||||||
File.Delete(shFilePath);
|
return null;
|
||||||
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());
|
#endregion Process
|
||||||
await Utils.SetLinuxChmod(shFilePath);
|
|
||||||
Logging.SaveLog(shFilePath);
|
|
||||||
|
|
||||||
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
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,65 +1,65 @@
|
||||||
namespace ServiceLib.Handler
|
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;
|
|
||||||
|
|
||||||
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();
|
InitCoreInfo();
|
||||||
}
|
}
|
||||||
|
return _coreInfo?.FirstOrDefault(t => t.CoreType == coreType);
|
||||||
|
}
|
||||||
|
|
||||||
public CoreInfo? GetCoreInfo(ECoreType coreType)
|
public List<CoreInfo> GetCoreInfo()
|
||||||
|
{
|
||||||
|
if (_coreInfo == null)
|
||||||
{
|
{
|
||||||
if (_coreInfo == null)
|
InitCoreInfo();
|
||||||
{
|
|
||||||
InitCoreInfo();
|
|
||||||
}
|
|
||||||
return _coreInfo?.FirstOrDefault(t => t.CoreType == coreType);
|
|
||||||
}
|
}
|
||||||
|
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 ?? [];
|
|
||||||
}
|
}
|
||||||
|
if (fileName.IsNullOrEmpty())
|
||||||
public string GetCoreExecFile(CoreInfo? coreInfo, out string msg)
|
|
||||||
{
|
{
|
||||||
var fileName = string.Empty;
|
msg = string.Format(ResUI.NotFoundCore, Utils.GetBinPath("", coreInfo?.CoreType.ToString()), coreInfo?.CoreExes?.LastOrDefault(), coreInfo?.Url);
|
||||||
msg = string.Empty;
|
Logging.SaveLog(msg);
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
return fileName;
|
||||||
|
}
|
||||||
|
|
||||||
private void InitCoreInfo()
|
private void InitCoreInfo()
|
||||||
{
|
{
|
||||||
var urlN = GetCoreUrl(ECoreType.v2rayN);
|
var urlN = GetCoreUrl(ECoreType.v2rayN);
|
||||||
var urlXray = GetCoreUrl(ECoreType.Xray);
|
var urlXray = GetCoreUrl(ECoreType.Xray);
|
||||||
var urlMihomo = GetCoreUrl(ECoreType.mihomo);
|
var urlMihomo = GetCoreUrl(ECoreType.mihomo);
|
||||||
var urlSingbox = GetCoreUrl(ECoreType.sing_box);
|
var urlSingbox = GetCoreUrl(ECoreType.sing_box);
|
||||||
|
|
||||||
_coreInfo =
|
_coreInfo =
|
||||||
[
|
[
|
||||||
new CoreInfo
|
new CoreInfo
|
||||||
{
|
{
|
||||||
CoreType = ECoreType.v2rayN,
|
CoreType = ECoreType.v2rayN,
|
||||||
Url = GetCoreUrl(ECoreType.v2rayN),
|
Url = GetCoreUrl(ECoreType.v2rayN),
|
||||||
|
@ -202,17 +202,16 @@ namespace ServiceLib.Handler
|
||||||
AbsolutePath = false,
|
AbsolutePath = false,
|
||||||
}
|
}
|
||||||
|
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
private static string PortableMode()
|
private static string PortableMode()
|
||||||
{
|
{
|
||||||
return $" -d {Utils.GetBinPath("").AppendQuotes()}";
|
return $" -d {Utils.GetBinPath("").AppendQuotes()}";
|
||||||
}
|
}
|
||||||
|
|
||||||
private static string GetCoreUrl(ECoreType eCoreType)
|
private static string GetCoreUrl(ECoreType eCoreType)
|
||||||
{
|
{
|
||||||
return $"{Global.GithubUrl}/{Global.CoreUrls[eCoreType]}/releases";
|
return $"{Global.GithubUrl}/{Global.CoreUrls[eCoreType]}/releases";
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,242 +1,241 @@
|
||||||
using System.Collections.Specialized;
|
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.StartsWith('[') && address.EndsWith(']') ? address : $"[{address}]";
|
return address; // 如果不是IPv6地址,直接返回原地址
|
||||||
}
|
}
|
||||||
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("type", item.Network.IsNotEmpty() ? item.Network : nameof(ETransport.tcp));
|
||||||
{
|
|
||||||
dicQuery.Add("security", item.StreamSecurity);
|
switch (item.Network)
|
||||||
}
|
{
|
||||||
else
|
case nameof(ETransport.tcp):
|
||||||
{
|
dicQuery.Add("headerType", item.HeaderType.IsNotEmpty() ? item.HeaderType : Global.None);
|
||||||
if (securityDef != null)
|
if (item.RequestHost.IsNotEmpty())
|
||||||
{
|
{
|
||||||
dicQuery.Add("security", securityDef);
|
dicQuery.Add("host", Utils.UrlEncode(item.RequestHost));
|
||||||
}
|
}
|
||||||
}
|
break;
|
||||||
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");
|
|
||||||
}
|
|
||||||
|
|
||||||
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.ws):
|
||||||
{
|
case nameof(ETransport.httpupgrade):
|
||||||
case nameof(ETransport.tcp):
|
if (item.RequestHost.IsNotEmpty())
|
||||||
dicQuery.Add("headerType", item.HeaderType.IsNotEmpty() ? item.HeaderType : Global.None);
|
{
|
||||||
if (item.RequestHost.IsNotEmpty())
|
dicQuery.Add("host", Utils.UrlEncode(item.RequestHost));
|
||||||
{
|
}
|
||||||
dicQuery.Add("host", Utils.UrlEncode(item.RequestHost));
|
if (item.Path.IsNotEmpty())
|
||||||
}
|
{
|
||||||
break;
|
dicQuery.Add("path", Utils.UrlEncode(item.Path));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
case nameof(ETransport.kcp):
|
case nameof(ETransport.xhttp):
|
||||||
dicQuery.Add("headerType", item.HeaderType.IsNotEmpty() ? item.HeaderType : Global.None);
|
if (item.RequestHost.IsNotEmpty())
|
||||||
if (item.Path.IsNotEmpty())
|
{
|
||||||
{
|
dicQuery.Add("host", Utils.UrlEncode(item.RequestHost));
|
||||||
dicQuery.Add("seed", Utils.UrlEncode(item.Path));
|
}
|
||||||
}
|
if (item.Path.IsNotEmpty())
|
||||||
break;
|
{
|
||||||
|
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.http):
|
||||||
case nameof(ETransport.httpupgrade):
|
case nameof(ETransport.h2):
|
||||||
if (item.RequestHost.IsNotEmpty())
|
dicQuery["type"] = nameof(ETransport.http);
|
||||||
{
|
if (item.RequestHost.IsNotEmpty())
|
||||||
dicQuery.Add("host", Utils.UrlEncode(item.RequestHost));
|
{
|
||||||
}
|
dicQuery.Add("host", Utils.UrlEncode(item.RequestHost));
|
||||||
if (item.Path.IsNotEmpty())
|
}
|
||||||
{
|
if (item.Path.IsNotEmpty())
|
||||||
dicQuery.Add("path", Utils.UrlEncode(item.Path));
|
{
|
||||||
}
|
dicQuery.Add("path", Utils.UrlEncode(item.Path));
|
||||||
break;
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
case nameof(ETransport.xhttp):
|
case nameof(ETransport.quic):
|
||||||
if (item.RequestHost.IsNotEmpty())
|
dicQuery.Add("headerType", item.HeaderType.IsNotEmpty() ? item.HeaderType : Global.None);
|
||||||
{
|
dicQuery.Add("quicSecurity", Utils.UrlEncode(item.RequestHost));
|
||||||
dicQuery.Add("host", Utils.UrlEncode(item.RequestHost));
|
dicQuery.Add("key", Utils.UrlEncode(item.Path));
|
||||||
}
|
break;
|
||||||
if (item.Path.IsNotEmpty())
|
|
||||||
{
|
case nameof(ETransport.grpc):
|
||||||
dicQuery.Add("path", Utils.UrlEncode(item.Path));
|
if (item.Path.IsNotEmpty())
|
||||||
}
|
{
|
||||||
if (item.HeaderType.IsNotEmpty() && Global.XhttpMode.Contains(item.HeaderType))
|
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));
|
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")
|
protected static string WriteAllText(string strData, string ext = "json")
|
||||||
{
|
{
|
||||||
var fileName = Utils.GetTempPath($"{Utils.GetGuid(false)}.{ext}");
|
var fileName = Utils.GetTempPath($"{Utils.GetGuid(false)}.{ext}");
|
||||||
File.WriteAllText(fileName, strData);
|
File.WriteAllText(fileName, strData);
|
||||||
return fileName;
|
return fileName;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected static string ToUri(EConfigType eConfigType, string address, object port, string userInfo, Dictionary<string, string>? dicQuery, string? remark)
|
protected static string ToUri(EConfigType eConfigType, string address, object port, string userInfo, Dictionary<string, string>? dicQuery, string? remark)
|
||||||
{
|
{
|
||||||
var query = dicQuery != null
|
var query = dicQuery != null
|
||||||
? ("?" + string.Join("&", dicQuery.Select(x => x.Key + "=" + x.Value).ToArray()))
|
? ("?" + string.Join("&", dicQuery.Select(x => x.Key + "=" + x.Value).ToArray()))
|
||||||
: string.Empty;
|
: string.Empty;
|
||||||
|
|
||||||
var url = $"{Utils.UrlEncode(userInfo)}@{GetIpv6(address)}:{port}";
|
var url = $"{Utils.UrlEncode(userInfo)}@{GetIpv6(address)}:{port}";
|
||||||
return $"{Global.ProtocolShares[eConfigType]}{url}{query}{remark}";
|
return $"{Global.ProtocolShares[eConfigType]}{url}{query}{remark}";
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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");
|
CoreType = ECoreType.mihomo,
|
||||||
|
Address = fileName,
|
||||||
var profileItem = new ProfileItem
|
Remarks = subRemarks ?? "clash_custom"
|
||||||
{
|
};
|
||||||
CoreType = ECoreType.mihomo,
|
return profileItem;
|
||||||
Address = fileName,
|
|
||||||
Remarks = subRemarks ?? "clash_custom"
|
|
||||||
};
|
|
||||||
return profileItem;
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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";
|
try
|
||||||
|
|
||||||
public static string? GetShareUri(ProfileItem item)
|
|
||||||
{
|
{
|
||||||
try
|
var url = item.ConfigType switch
|
||||||
{
|
{
|
||||||
var url = item.ConfigType switch
|
EConfigType.VMess => VmessFmt.ToUri(item),
|
||||||
{
|
EConfigType.Shadowsocks => ShadowsocksFmt.ToUri(item),
|
||||||
EConfigType.VMess => VmessFmt.ToUri(item),
|
EConfigType.SOCKS => SocksFmt.ToUri(item),
|
||||||
EConfigType.Shadowsocks => ShadowsocksFmt.ToUri(item),
|
EConfigType.Trojan => TrojanFmt.ToUri(item),
|
||||||
EConfigType.SOCKS => SocksFmt.ToUri(item),
|
EConfigType.VLESS => VLESSFmt.ToUri(item),
|
||||||
EConfigType.Trojan => TrojanFmt.ToUri(item),
|
EConfigType.Hysteria2 => Hysteria2Fmt.ToUri(item),
|
||||||
EConfigType.VLESS => VLESSFmt.ToUri(item),
|
EConfigType.TUIC => TuicFmt.ToUri(item),
|
||||||
EConfigType.Hysteria2 => Hysteria2Fmt.ToUri(item),
|
EConfigType.WireGuard => WireguardFmt.ToUri(item),
|
||||||
EConfigType.TUIC => TuicFmt.ToUri(item),
|
_ => null,
|
||||||
EConfigType.WireGuard => WireguardFmt.ToUri(item),
|
};
|
||||||
_ => null,
|
|
||||||
};
|
|
||||||
|
|
||||||
return url;
|
return url;
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
Logging.SaveLog(_tag, ex);
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
catch (Exception ex)
|
||||||
public static ProfileItem? ResolveConfig(string config, out string msg)
|
|
||||||
{
|
{
|
||||||
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();
|
msg = ResUI.FailedReadConfiguration;
|
||||||
if (str.IsNullOrEmpty())
|
return null;
|
||||||
{
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
|
||||||
|
if (str.StartsWith(Global.ProtocolShares[EConfigType.VMess]))
|
||||||
{
|
{
|
||||||
Logging.SaveLog(_tag, ex);
|
return VmessFmt.Resolve(str, out msg);
|
||||||
msg = ResUI.Incorrectconfiguration;
|
}
|
||||||
|
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;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Logging.SaveLog(_tag, ex);
|
||||||
|
msg = ResUI.Incorrectconfiguration;
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
ConfigType = EConfigType.Hysteria2
|
||||||
ProfileItem item = new()
|
};
|
||||||
|
|
||||||
|
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"
|
||||||
};
|
};
|
||||||
|
return profileItem;
|
||||||
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)
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ProfileItem? ResolveFull2(string strData, string? subRemarks)
|
||||||
|
{
|
||||||
|
if (Contains(strData, "server", "auth", "up", "down", "listen"))
|
||||||
{
|
{
|
||||||
if (item == null)
|
var fileName = WriteAllText(strData);
|
||||||
return null;
|
|
||||||
string url = string.Empty;
|
|
||||||
|
|
||||||
string remark = string.Empty;
|
var profileItem = new ProfileItem
|
||||||
if (item.Remarks.IsNotEmpty())
|
|
||||||
{
|
{
|
||||||
remark = "#" + Utils.UrlEncode(item.Remarks);
|
CoreType = ECoreType.hysteria2,
|
||||||
}
|
Address = fileName,
|
||||||
var dicQuery = new Dictionary<string, string>();
|
Remarks = subRemarks ?? "hysteria2_custom"
|
||||||
if (item.Sni.IsNotEmpty())
|
};
|
||||||
{
|
return profileItem;
|
||||||
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)
|
return null;
|
||||||
{
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
CoreType = ECoreType.naiveproxy,
|
||||||
|
Address = fileName,
|
||||||
var profileItem = new ProfileItem
|
Remarks = subRemarks ?? "naiveproxy_custom"
|
||||||
{
|
};
|
||||||
CoreType = ECoreType.naiveproxy,
|
return profileItem;
|
||||||
Address = fileName,
|
|
||||||
Remarks = subRemarks ?? "naiveproxy_custom"
|
|
||||||
};
|
|
||||||
return profileItem;
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,180 +1,179 @@
|
||||||
using System.Text.RegularExpressions;
|
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;
|
return null;
|
||||||
ProfileItem? item;
|
}
|
||||||
|
if (item.Address.Length == 0 || item.Port == 0 || item.Security.Length == 0 || item.Id.Length == 0)
|
||||||
item = ResolveSSLegacy(str) ?? ResolveSip002(str);
|
{
|
||||||
if (item == null)
|
return 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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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;
|
||||||
{
|
}
|
||||||
return null;
|
var remark = string.Empty;
|
||||||
}
|
if (item.Remarks.IsNotEmpty())
|
||||||
var remark = string.Empty;
|
{
|
||||||
if (item.Remarks.IsNotEmpty())
|
remark = "#" + Utils.UrlEncode(item.Remarks);
|
||||||
{
|
}
|
||||||
remark = "#" + Utils.UrlEncode(item.Remarks);
|
//url = string.Format("{0}:{1}@{2}:{3}",
|
||||||
}
|
// item.security,
|
||||||
//url = string.Format("{0}:{1}@{2}:{3}",
|
// item.id,
|
||||||
// item.security,
|
// item.address,
|
||||||
// item.id,
|
// item.port);
|
||||||
// item.address,
|
//url = Utile.Base64Encode(url);
|
||||||
// item.port);
|
//new Sip002
|
||||||
//url = Utile.Base64Encode(url);
|
var pw = Utils.Base64Encode($"{item.Security}:{item.Id}");
|
||||||
//new Sip002
|
return ToUri(EConfigType.Shadowsocks, item.Address, item.Port, pw, null, remark);
|
||||||
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);
|
ProfileItem item = new();
|
||||||
private static readonly Regex DetailsParser = new(@"^((?<method>.+?):(?<password>.*)@(?<hostname>.+?):(?<port>\d+?))$", RegexOptions.IgnoreCase | RegexOptions.Compiled);
|
var base64 = match.Groups["base64"].Value.TrimEnd('/');
|
||||||
|
var tag = match.Groups["tag"].Value;
|
||||||
private static ProfileItem? ResolveSSLegacy(string result)
|
if (tag.IsNotEmpty())
|
||||||
{
|
{
|
||||||
var match = UrlFinder.Match(result);
|
item.Remarks = Utils.UrlDecode(tag);
|
||||||
if (!match.Success)
|
}
|
||||||
{
|
Match details;
|
||||||
return null;
|
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();
|
private static ProfileItem? ResolveSip002(string result)
|
||||||
var base64 = match.Groups["base64"].Value.TrimEnd('/');
|
{
|
||||||
var tag = match.Groups["tag"].Value;
|
var parsedUrl = Utils.TryUri(result);
|
||||||
if (tag.IsNotEmpty())
|
if (parsedUrl == null)
|
||||||
{
|
{
|
||||||
item.Remarks = Utils.UrlDecode(tag);
|
return null;
|
||||||
}
|
|
||||||
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)
|
ProfileItem item = new()
|
||||||
{
|
{
|
||||||
var parsedUrl = Utils.TryUri(result);
|
Remarks = parsedUrl.GetComponents(UriComponents.Fragment, UriFormat.Unescaped),
|
||||||
if (parsedUrl == null)
|
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;
|
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),
|
obfsHost = obfsHost?.Replace("obfs-host=", "");
|
||||||
Address = parsedUrl.IdnHost,
|
item.Network = Global.DefaultNetwork;
|
||||||
Port = parsedUrl.Port,
|
item.HeaderType = Global.TcpHeaderHttp;
|
||||||
};
|
item.RequestHost = obfsHost ?? "";
|
||||||
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
|
else
|
||||||
{
|
{
|
||||||
// parse base64 UserInfo
|
return null;
|
||||||
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();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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 ssSIP008 = JsonUtils.Deserialize<SsSIP008>(result);
|
||||||
var lstSsServer = JsonUtils.Deserialize<List<SsServer>>(result);
|
if (ssSIP008?.servers?.Count > 0)
|
||||||
if (lstSsServer?.Count <= 0)
|
|
||||||
{
|
{
|
||||||
var ssSIP008 = JsonUtils.Deserialize<SsSIP008>(result);
|
lstSsServer = ssSIP008.servers;
|
||||||
if (ssSIP008?.servers?.Count > 0)
|
|
||||||
{
|
|
||||||
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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
return null;
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static ProfileItem? ResolveFull(string strData, string? subRemarks)
|
List<ProfileItem> lstResult = [];
|
||||||
|
foreach (var configObject in configObjects)
|
||||||
{
|
{
|
||||||
var config = JsonUtils.ParseJson(strData);
|
var objectString = JsonUtils.Serialize(configObject);
|
||||||
if (config?["inbounds"] == null
|
var profileIt = ResolveFull(objectString, subRemarks);
|
||||||
|| config["outbounds"] == null
|
if (profileIt != null)
|
||||||
|| config["route"] == null
|
|
||||||
|| config["dns"] == 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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
return null;
|
||||||
|
}
|
||||||
var item = ResolveSocksNew(str) ?? ResolveSocks(str);
|
if (item.Address.Length == 0 || item.Port == 0)
|
||||||
if (item == null)
|
{
|
||||||
{
|
return null;
|
||||||
return null;
|
|
||||||
}
|
|
||||||
if (item.Address.Length == 0 || item.Port == 0)
|
|
||||||
{
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
item.ConfigType = EConfigType.SOCKS;
|
|
||||||
|
|
||||||
return item;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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;
|
catch { }
|
||||||
if (item.Remarks.IsNotEmpty())
|
result = result[..indexRemark];
|
||||||
{
|
}
|
||||||
remark = "#" + Utils.UrlEncode(item.Remarks);
|
//part decode
|
||||||
}
|
var indexS = result.IndexOf("@");
|
||||||
//new
|
if (indexS > 0)
|
||||||
var pw = Utils.Base64Encode($"{item.Security}:{item.Id}");
|
{
|
||||||
return ToUri(EConfigType.SOCKS, item.Address, item.Port, pw, null, remark);
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
result = Utils.Base64Decode(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static ProfileItem? ResolveSocks(string result)
|
var arr1 = result.Split('@');
|
||||||
|
if (arr1.Length != 2)
|
||||||
{
|
{
|
||||||
ProfileItem item = new()
|
return null;
|
||||||
{
|
}
|
||||||
ConfigType = EConfigType.SOCKS
|
var arr21 = arr1.First().Split(':');
|
||||||
};
|
var indexPort = arr1.Last().LastIndexOf(":");
|
||||||
result = result[Global.ProtocolShares[EConfigType.SOCKS].Length..];
|
if (arr21.Length != 2 || indexPort < 0)
|
||||||
//remark
|
{
|
||||||
var indexRemark = result.IndexOf("#");
|
return null;
|
||||||
if (indexRemark > 0)
|
}
|
||||||
{
|
item.Address = arr1[1][..indexPort];
|
||||||
try
|
item.Port = arr1[1][(indexPort + 1)..].ToInt();
|
||||||
{
|
item.Security = arr21.First();
|
||||||
item.Remarks = Utils.UrlDecode(result.Substring(indexRemark + 1, result.Length - indexRemark - 1));
|
item.Id = arr21[1];
|
||||||
}
|
|
||||||
catch { }
|
|
||||||
result = result[..indexRemark];
|
|
||||||
}
|
|
||||||
//part decode
|
|
||||||
var indexS = result.IndexOf("@");
|
|
||||||
if (indexS > 0)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
result = Utils.Base64Decode(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
var arr1 = result.Split('@');
|
return item;
|
||||||
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;
|
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);
|
Remarks = parsedUrl.GetComponents(UriComponents.Fragment, UriFormat.Unescaped),
|
||||||
if (parsedUrl == null)
|
Address = parsedUrl.IdnHost,
|
||||||
{
|
Port = parsedUrl.Port,
|
||||||
return null;
|
};
|
||||||
}
|
|
||||||
|
|
||||||
ProfileItem item = new()
|
// parse base64 UserInfo
|
||||||
{
|
var rawUserInfo = Utils.UrlDecode(parsedUrl.UserInfo);
|
||||||
Remarks = parsedUrl.GetComponents(UriComponents.Fragment, UriFormat.Unescaped),
|
var userInfo = Utils.Base64Decode(rawUserInfo);
|
||||||
Address = parsedUrl.IdnHost,
|
var userInfoParts = userInfo.Split([':'], 2);
|
||||||
Port = parsedUrl.Port,
|
if (userInfoParts.Length == 2)
|
||||||
};
|
{
|
||||||
|
item.Security = userInfoParts.First();
|
||||||
// parse base64 UserInfo
|
item.Id = userInfoParts[1];
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return item;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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()
|
var url = Utils.TryUri(str);
|
||||||
{
|
if (url == null)
|
||||||
ConfigType = EConfigType.Trojan
|
{
|
||||||
};
|
return null;
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static string? ToUri(ProfileItem? item)
|
item.Address = url.IdnHost;
|
||||||
{
|
item.Port = url.Port;
|
||||||
if (item == null)
|
item.Remarks = url.GetComponents(UriComponents.Fragment, UriFormat.Unescaped);
|
||||||
{
|
item.Id = Utils.UrlDecode(url.UserInfo);
|
||||||
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);
|
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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()
|
var url = Utils.TryUri(str);
|
||||||
{
|
if (url == null)
|
||||||
ConfigType = EConfigType.TUIC
|
{
|
||||||
};
|
return null;
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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)
|
item.Id = userInfoParts.First();
|
||||||
{
|
item.Security = userInfoParts.Last();
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
return null;
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static ProfileItem? ResolveFull(string strData, string? subRemarks)
|
List<ProfileItem> lstResult = [];
|
||||||
|
foreach (var configObject in configObjects)
|
||||||
{
|
{
|
||||||
var config = JsonUtils.ParseJson(strData);
|
var objectString = JsonUtils.Serialize(configObject);
|
||||||
if (config?["inbounds"] == null
|
var profileIt = ResolveFull(objectString, subRemarks);
|
||||||
|| config["outbounds"] == null
|
if (profileIt != null)
|
||||||
|| config["routing"] == 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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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()
|
var url = Utils.TryUri(str);
|
||||||
{
|
if (url == null)
|
||||||
ConfigType = EConfigType.VLESS,
|
{
|
||||||
Security = Global.None
|
return null;
|
||||||
};
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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;
|
||||||
{
|
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
item = ResolveStdVmess(str);
|
||||||
ProfileItem? item;
|
}
|
||||||
if (str.IndexOf('?') > 0 && str.IndexOf('&') > 0)
|
else
|
||||||
{
|
{
|
||||||
item = ResolveStdVmess(str);
|
item = ResolveVmess(str, out msg);
|
||||||
}
|
}
|
||||||
else
|
return item;
|
||||||
{
|
}
|
||||||
item = ResolveVmess(str, out msg);
|
|
||||||
}
|
public static string? ToUri(ProfileItem? item)
|
||||||
return 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)
|
item.Network = vmessQRCode.net;
|
||||||
{
|
}
|
||||||
return null;
|
if (vmessQRCode.type.IsNotEmpty())
|
||||||
}
|
{
|
||||||
var vmessQRCode = new VmessQRCode
|
item.HeaderType = vmessQRCode.type;
|
||||||
{
|
|
||||||
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)
|
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;
|
ConfigType = EConfigType.VMess,
|
||||||
var item = new ProfileItem
|
Security = "auto"
|
||||||
{
|
};
|
||||||
ConfigType = EConfigType.VMess
|
|
||||||
};
|
|
||||||
|
|
||||||
result = result[Global.ProtocolShares[EConfigType.VMess].Length..];
|
var url = Utils.TryUri(str);
|
||||||
result = Utils.Base64Decode(result);
|
if (url == null)
|
||||||
|
{
|
||||||
var vmessQRCode = JsonUtils.Deserialize<VmessQRCode>(result);
|
return null;
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static ProfileItem? ResolveStdVmess(string str)
|
item.Address = url.IdnHost;
|
||||||
{
|
item.Port = url.Port;
|
||||||
var item = new ProfileItem
|
item.Remarks = url.GetComponents(UriComponents.Fragment, UriFormat.Unescaped);
|
||||||
{
|
item.Id = Utils.UrlDecode(url.UserInfo);
|
||||||
ConfigType = EConfigType.VMess,
|
|
||||||
Security = "auto"
|
|
||||||
};
|
|
||||||
|
|
||||||
var url = Utils.TryUri(str);
|
var query = Utils.ParseQueryString(url.Query);
|
||||||
if (url == null)
|
ResolveStdTransport(query, ref item);
|
||||||
{
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
item.Address = url.IdnHost;
|
return item;
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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()
|
var url = Utils.TryUri(str);
|
||||||
{
|
if (url == null)
|
||||||
ConfigType = EConfigType.WireGuard
|
{
|
||||||
};
|
return null;
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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;
|
||||||
{
|
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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());
|
if (content.IsNullOrEmpty())
|
||||||
public static NoticeHandler Instance => _instance.Value;
|
|
||||||
|
|
||||||
public void Enqueue(string? content)
|
|
||||||
{
|
{
|
||||||
if (content.IsNullOrEmpty())
|
return;
|
||||||
{
|
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -1,115 +1,114 @@
|
||||||
using System.Net.Sockets;
|
using System.Net.Sockets;
|
||||||
using System.Text;
|
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;
|
_needRestart = configPath != _configPath || httpPort != _httpPort || pacPort != _pacPort || !_isRunning;
|
||||||
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)
|
_configPath = configPath;
|
||||||
|
_httpPort = httpPort;
|
||||||
|
_pacPort = pacPort;
|
||||||
|
|
||||||
|
await InitText();
|
||||||
|
|
||||||
|
if (_needRestart)
|
||||||
{
|
{
|
||||||
_needRestart = configPath != _configPath || httpPort != _httpPort || pacPort != _pacPort || !_isRunning;
|
Stop();
|
||||||
|
RunListener();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
_configPath = configPath;
|
private static async Task InitText()
|
||||||
_httpPort = httpPort;
|
{
|
||||||
_pacPort = pacPort;
|
var path = Path.Combine(_configPath, "pac.txt");
|
||||||
|
|
||||||
await InitText();
|
// Delete the old pac file
|
||||||
|
if (File.Exists(path) && Utils.GetFileHash(path).Equals("b590c07280f058ef05d5394aa2f927fe"))
|
||||||
if (_needRestart)
|
{
|
||||||
{
|
File.Delete(path);
|
||||||
Stop();
|
|
||||||
RunListener();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static async Task InitText()
|
if (!File.Exists(path))
|
||||||
{
|
{
|
||||||
var path = Path.Combine(_configPath, "pac.txt");
|
var pac = EmbedUtils.GetEmbedText(Global.PacFileName);
|
||||||
|
await File.AppendAllTextAsync(path, pac);
|
||||||
// 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());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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);
|
while (_isRunning)
|
||||||
_isRunning = true;
|
|
||||||
_tcpListener.Start();
|
|
||||||
Task.Factory.StartNew(async () =>
|
|
||||||
{
|
{
|
||||||
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();
|
var client = await _tcpListener.AcceptTcpClientAsync();
|
||||||
await Task.Run(() => WriteContent(client));
|
await Task.Run(() => WriteContent(client));
|
||||||
}
|
|
||||||
catch
|
|
||||||
{
|
|
||||||
// ignored
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}, TaskCreationOptions.LongRunning);
|
catch
|
||||||
}
|
{
|
||||||
|
// ignored
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, TaskCreationOptions.LongRunning);
|
||||||
|
}
|
||||||
|
|
||||||
private static void WriteContent(TcpClient client)
|
private static void WriteContent(TcpClient client)
|
||||||
{
|
{
|
||||||
var stream = client.GetStream();
|
var stream = client.GetStream();
|
||||||
stream.Write(_writeContent, 0, _writeContent.Length);
|
stream.Write(_writeContent, 0, _writeContent.Length);
|
||||||
stream.Flush();
|
stream.Flush();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Stop()
|
public static void Stop()
|
||||||
|
{
|
||||||
|
if (_tcpListener == null)
|
||||||
{
|
{
|
||||||
if (_tcpListener == null)
|
return;
|
||||||
{
|
}
|
||||||
return;
|
try
|
||||||
}
|
{
|
||||||
try
|
_isRunning = false;
|
||||||
{
|
_tcpListener.Stop();
|
||||||
_isRunning = false;
|
_tcpListener = null;
|
||||||
_tcpListener.Stop();
|
}
|
||||||
_tcpListener = null;
|
catch
|
||||||
}
|
{
|
||||||
catch
|
// ignored
|
||||||
{
|
|
||||||
// ignored
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,181 +2,180 @@ using System.Collections.Concurrent;
|
||||||
|
|
||||||
//using System.Reactive.Linq;
|
//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());
|
//Init();
|
||||||
private ConcurrentBag<ProfileExItem> _lstProfileEx = [];
|
}
|
||||||
private readonly Queue<string> _queIndexIds = new();
|
|
||||||
public static ProfileExHandler Instance => _instance.Value;
|
|
||||||
private static readonly string _tag = "ProfileExHandler";
|
|
||||||
|
|
||||||
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()
|
for (var i = 0; i < cnt; i++)
|
||||||
{
|
|
||||||
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))
|
|
||||||
{
|
{
|
||||||
_queIndexIds.Enqueue(indexId);
|
var id = _queIndexIds.Dequeue();
|
||||||
}
|
var item = lstExists.FirstOrDefault(t => t.IndexId == id);
|
||||||
}
|
var itemNew = _lstProfileEx?.FirstOrDefault(t => t.IndexId == id);
|
||||||
|
if (itemNew is null)
|
||||||
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();
|
continue;
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
try
|
if (item is not null)
|
||||||
{
|
{
|
||||||
if (lstInserts.Count > 0)
|
lstUpdates.Add(itemNew);
|
||||||
{
|
|
||||||
await SQLiteHelper.Instance.InsertAllAsync(lstInserts);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (lstUpdates.Count > 0)
|
|
||||||
{
|
|
||||||
await SQLiteHelper.Instance.UpdateAllAsync(lstUpdates);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
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
|
try
|
||||||
{
|
{
|
||||||
await SaveQueueIndexIds();
|
if (lstInserts.Count > 0)
|
||||||
|
{
|
||||||
|
await SQLiteHelper.Instance.InsertAllAsync(lstInserts);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (lstUpdates.Count > 0)
|
||||||
|
{
|
||||||
|
await SQLiteHelper.Instance.UpdateAllAsync(lstUpdates);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Logging.SaveLog(_tag, 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;
|
private ProfileExItem GetProfileExItem(string? indexId)
|
||||||
IndexIdEnqueue(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();
|
||||||
}
|
}
|
||||||
|
catch (Exception ex)
|
||||||
public void SetTestSpeed(string indexId, decimal speed)
|
|
||||||
{
|
{
|
||||||
var profileEx = GetProfileExItem(indexId);
|
Logging.SaveLog(_tag, ex);
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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());
|
_config = config;
|
||||||
public static StatisticsHandler Instance => instance.Value;
|
_updateFunc = updateFunc;
|
||||||
|
if (config.GuiItem.EnableStatistics || _config.GuiItem.DisplayRealTimeSpeed)
|
||||||
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;
|
await InitData();
|
||||||
_updateFunc = updateFunc;
|
|
||||||
if (config.GuiItem.EnableStatistics || _config.GuiItem.DisplayRealTimeSpeed)
|
|
||||||
{
|
|
||||||
await InitData();
|
|
||||||
|
|
||||||
_statisticsXray = new StatisticsXrayService(config, UpdateServerStatHandler);
|
_statisticsXray = new StatisticsXrayService(config, UpdateServerStatHandler);
|
||||||
_statisticsSingbox = new StatisticsSingboxService(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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
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];
|
var contents = EmbedUtils.GetEmbedText(Global.ProxySetLinuxShellFileName);
|
||||||
await ExecCmd(args);
|
await File.AppendAllTextAsync(fileName, contents);
|
||||||
|
|
||||||
|
await Utils.SetLinuxChmod(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static async Task UnsetProxy()
|
await Utils.GetCliWrapOutput(fileName, args);
|
||||||
{
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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";
|
List<string> args = ["set", host, port.ToString()];
|
||||||
|
if (exceptions.IsNotEmpty())
|
||||||
public static async Task SetProxy(string host, int port, string exceptions)
|
|
||||||
{
|
{
|
||||||
List<string> args = ["set", host, port.ToString()];
|
args.AddRange(exceptions.Split(','));
|
||||||
if (exceptions.IsNotEmpty())
|
|
||||||
{
|
|
||||||
args.AddRange(exceptions.Split(','));
|
|
||||||
}
|
|
||||||
|
|
||||||
await ExecCmd(args);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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"];
|
var contents = EmbedUtils.GetEmbedText(Global.ProxySetOSXShellFileName);
|
||||||
await ExecCmd(args);
|
await File.AppendAllTextAsync(fileName, contents);
|
||||||
|
|
||||||
|
await Utils.SetLinuxChmod(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static async Task ExecCmd(List<string> args)
|
await Utils.GetCliWrapOutput(fileName, 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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,360 +1,359 @@
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
using static ServiceLib.Handler.SysProxy.ProxySettingWindows.InternetConnectionOption;
|
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";
|
if (type == 1)
|
||||||
|
|
||||||
private static bool SetProxyFallback(string? strProxy, string? exceptions, int type)
|
|
||||||
{
|
{
|
||||||
if (type == 1)
|
WindowsUtils.RegWriteValue(_regPath, "ProxyEnable", 0);
|
||||||
{
|
WindowsUtils.RegWriteValue(_regPath, "ProxyServer", string.Empty);
|
||||||
WindowsUtils.RegWriteValue(_regPath, "ProxyEnable", 0);
|
WindowsUtils.RegWriteValue(_regPath, "ProxyOverride", string.Empty);
|
||||||
WindowsUtils.RegWriteValue(_regPath, "ProxyServer", string.Empty);
|
WindowsUtils.RegWriteValue(_regPath, "AutoConfigURL", 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;
|
|
||||||
}
|
}
|
||||||
|
if (type == 2)
|
||||||
/// <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);
|
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)
|
||||||
/// <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
|
WindowsUtils.RegWriteValue(_regPath, "ProxyEnable", 0);
|
||||||
{
|
WindowsUtils.RegWriteValue(_regPath, "ProxyServer", string.Empty);
|
||||||
// set proxy for LAN
|
WindowsUtils.RegWriteValue(_regPath, "ProxyOverride", string.Empty);
|
||||||
var result = SetConnectionProxy(null, strProxy, exceptions, type);
|
WindowsUtils.RegWriteValue(_regPath, "AutoConfigURL", strProxy ?? string.Empty);
|
||||||
// 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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
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();
|
// set proxy for LAN
|
||||||
|
var result = SetConnectionProxy(null, strProxy, exceptions, type);
|
||||||
var optionCount = 1;
|
// set proxy for dial up connections
|
||||||
if (type == 1) // No proxy
|
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
|
return result;
|
||||||
{
|
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
catch
|
||||||
/// <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;
|
_ = SetProxyFallback(strProxy, exceptions, type);
|
||||||
// attempt to query with 1 entry buffer
|
return false;
|
||||||
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
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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;
|
type = ESysProxyType.ForcedClear;
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void GetWindowsProxyString(Config config, int port, out string strProxy, out string strExceptions)
|
try
|
||||||
{
|
{
|
||||||
strExceptions = config.SystemProxyItem.SystemProxyExceptions.Replace(" ", "");
|
var port = AppHandler.Instance.GetLocalPort(EInboundProtocol.socks);
|
||||||
if (config.SystemProxyItem.NotProxyLocalAddress)
|
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 (type != ESysProxyType.Pac && Utils.IsWindows())
|
||||||
if (config.SystemProxyItem.SystemProxyAdvancedProtocol.IsNullOrEmpty())
|
|
||||||
{
|
{
|
||||||
strProxy = $"{Global.Loopback}:{port}";
|
PacHandler.Stop();
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
strProxy = config.SystemProxyItem.SystemProxyAdvancedProtocol
|
|
||||||
.Replace("{ip}", Global.Loopback)
|
|
||||||
.Replace("{http_port}", port.ToString())
|
|
||||||
.Replace("{socks_port}", port.ToString());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
catch (Exception ex)
|
||||||
private static async Task SetWindowsProxyPac(int port)
|
|
||||||
{
|
{
|
||||||
var portPac = AppHandler.Instance.GetLocalPort(EInboundProtocol.pac);
|
Logging.SaveLog(_tag, ex);
|
||||||
await PacHandler.Start(Utils.GetConfigPath(), port, portPac);
|
}
|
||||||
var strProxy = $"{Global.HttpProtocol}{Global.Loopback}:{portPac}/pac?t={DateTime.Now.Ticks}";
|
return true;
|
||||||
ProxySettingWindows.SetProxy(strProxy, "", 4);
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -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());
|
Task.Run(() => ScheduledTasks(config, updateFunc));
|
||||||
public static TaskHandler Instance => _instance.Value;
|
}
|
||||||
|
|
||||||
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)
|
//Execute once 1 minute
|
||||||
{
|
await UpdateTaskRunSubscription(config, updateFunc);
|
||||||
Logging.SaveLog("Setup Scheduled Tasks");
|
|
||||||
|
|
||||||
var numOfExecuted = 1;
|
//Execute once 20 minute
|
||||||
while (true)
|
if (numOfExecuted % 20 == 0)
|
||||||
{
|
{
|
||||||
//1 minute
|
//Logging.SaveLog("Execute save config");
|
||||||
await Task.Delay(1000 * 60);
|
|
||||||
|
|
||||||
//Execute once 1 minute
|
await ConfigHandler.SaveConfig(config);
|
||||||
await UpdateTaskRunSubscription(config, updateFunc);
|
await ProfileExHandler.Instance.SaveTo();
|
||||||
|
|
||||||
//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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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();
|
var updateHandle = new UpdateService();
|
||||||
|
await updateHandle.UpdateGeoFileAll(config, (bool success, string msg) =>
|
||||||
foreach (var item in lstSubs)
|
|
||||||
{
|
{
|
||||||
await updateHandle.UpdateSubscriptionProcess(config, item.Id, true, (bool success, string msg) =>
|
updateFunc?.Invoke(false, 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);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,182 +1,181 @@
|
||||||
using System.Net;
|
using System.Net;
|
||||||
using WebDav;
|
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());
|
_config = AppHandler.Instance.Config;
|
||||||
public static WebDavHandler Instance => _instance.Value;
|
}
|
||||||
|
|
||||||
private readonly Config? _config;
|
private async Task<bool> GetClient()
|
||||||
private WebDavClient? _client;
|
{
|
||||||
private string? _lastDescription;
|
try
|
||||||
private string _webDir = Global.AppName + "_backup";
|
|
||||||
private readonly string _webFileName = "backup.zip";
|
|
||||||
private readonly string _tag = "WebDav--";
|
|
||||||
|
|
||||||
public WebDavHandler()
|
|
||||||
{
|
{
|
||||||
_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);
|
||||||
}
|
}
|
||||||
|
catch (Exception ex)
|
||||||
private async Task<bool> GetClient()
|
|
||||||
{
|
{
|
||||||
try
|
SaveLog(ex);
|
||||||
{
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
return false;
|
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;
|
return false;
|
||||||
}
|
}
|
||||||
|
try
|
||||||
public async Task<bool> PutFile(string fileName)
|
|
||||||
{
|
{
|
||||||
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;
|
return true;
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
SaveLog(result2.Description);
|
||||||
{
|
}
|
||||||
SaveLog(ex);
|
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;
|
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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,11 +1,10 @@
|
||||||
namespace ServiceLib.Models
|
namespace ServiceLib.Models;
|
||||||
|
|
||||||
|
public class CheckUpdateModel
|
||||||
{
|
{
|
||||||
public class CheckUpdateModel
|
public bool? IsSelected { get; set; }
|
||||||
{
|
public string? CoreType { get; set; }
|
||||||
public bool? IsSelected { get; set; }
|
public string? Remarks { get; set; }
|
||||||
public string? CoreType { get; set; }
|
public string? FileName { get; set; }
|
||||||
public string? Remarks { get; set; }
|
public bool? IsFinished { get; set; }
|
||||||
public string? FileName { get; set; }
|
}
|
||||||
public bool? IsFinished { get; set; }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,17 +1,16 @@
|
||||||
namespace ServiceLib.Models
|
namespace ServiceLib.Models;
|
||||||
|
|
||||||
|
public class ClashConnectionModel
|
||||||
{
|
{
|
||||||
public class ClashConnectionModel
|
public string? Id { get; set; }
|
||||||
{
|
public string? Network { get; set; }
|
||||||
public string? Id { get; set; }
|
public string? Type { get; set; }
|
||||||
public string? Network { get; set; }
|
public string? Host { get; set; }
|
||||||
public string? Type { get; set; }
|
public ulong Upload { get; set; }
|
||||||
public string? Host { get; set; }
|
public ulong Download { get; set; }
|
||||||
public ulong Upload { get; set; }
|
public string? UploadTraffic { get; set; }
|
||||||
public ulong Download { get; set; }
|
public string? DownloadTraffic { get; set; }
|
||||||
public string? UploadTraffic { get; set; }
|
public double Time { get; set; }
|
||||||
public string? DownloadTraffic { get; set; }
|
public string? Elapsed { get; set; }
|
||||||
public double Time { get; set; }
|
public string? Chain { get; set; }
|
||||||
public string? Elapsed { get; set; }
|
}
|
||||||
public string? Chain { get; set; }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,37 +1,36 @@
|
||||||
namespace ServiceLib.Models
|
namespace ServiceLib.Models;
|
||||||
|
|
||||||
|
public class ClashConnections
|
||||||
{
|
{
|
||||||
public class ClashConnections
|
public ulong downloadTotal { get; set; }
|
||||||
{
|
public ulong uploadTotal { get; set; }
|
||||||
public ulong downloadTotal { get; set; }
|
public List<ConnectionItem>? connections { get; set; }
|
||||||
public ulong uploadTotal { get; set; }
|
}
|
||||||
public List<ConnectionItem>? connections { get; set; }
|
|
||||||
}
|
|
||||||
|
|
||||||
public class ConnectionItem
|
public class ConnectionItem
|
||||||
{
|
{
|
||||||
public string? id { get; set; }
|
public string? id { get; set; }
|
||||||
public MetadataItem? metadata { get; set; }
|
public MetadataItem? metadata { get; set; }
|
||||||
public ulong upload { get; set; }
|
public ulong upload { get; set; }
|
||||||
public ulong download { get; set; }
|
public ulong download { get; set; }
|
||||||
public DateTime start { get; set; }
|
public DateTime start { get; set; }
|
||||||
public List<string>? chains { get; set; }
|
public List<string>? chains { get; set; }
|
||||||
public string? rule { get; set; }
|
public string? rule { get; set; }
|
||||||
public string? rulePayload { get; set; }
|
public string? rulePayload { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public class MetadataItem
|
public class MetadataItem
|
||||||
{
|
{
|
||||||
public string? network { get; set; }
|
public string? network { get; set; }
|
||||||
public string? type { get; set; }
|
public string? type { get; set; }
|
||||||
public string? sourceIP { get; set; }
|
public string? sourceIP { get; set; }
|
||||||
public string? destinationIP { get; set; }
|
public string? destinationIP { get; set; }
|
||||||
public string? sourcePort { get; set; }
|
public string? sourcePort { get; set; }
|
||||||
public string? destinationPort { get; set; }
|
public string? destinationPort { get; set; }
|
||||||
public string? host { get; set; }
|
public string? host { get; set; }
|
||||||
public string? nsMode { get; set; }
|
public string? nsMode { get; set; }
|
||||||
public object? uid { get; set; }
|
public object? uid { get; set; }
|
||||||
public string? process { get; set; }
|
public string? process { get; set; }
|
||||||
public string? processPath { get; set; }
|
public string? processPath { get; set; }
|
||||||
public string? remoteDestination { get; set; }
|
public string? remoteDestination { get; set; }
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
|
@ -1,17 +1,16 @@
|
||||||
using static ServiceLib.Models.ClashProxies;
|
using static ServiceLib.Models.ClashProxies;
|
||||||
|
|
||||||
namespace ServiceLib.Models
|
namespace ServiceLib.Models;
|
||||||
|
|
||||||
|
public class ClashProviders
|
||||||
{
|
{
|
||||||
public class ClashProviders
|
public Dictionary<string, ProvidersItem>? providers { get; set; }
|
||||||
{
|
|
||||||
public Dictionary<string, ProvidersItem>? providers { get; set; }
|
|
||||||
|
|
||||||
public class ProvidersItem
|
public class ProvidersItem
|
||||||
{
|
{
|
||||||
public string? name { get; set; }
|
public string? name { get; set; }
|
||||||
public List<ProxiesItem>? proxies { get; set; }
|
public List<ProxiesItem>? proxies { get; set; }
|
||||||
public string? type { get; set; }
|
public string? type { get; set; }
|
||||||
public string? vehicleType { get; set; }
|
public string? vehicleType { get; set; }
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,24 +1,23 @@
|
||||||
namespace ServiceLib.Models
|
namespace ServiceLib.Models;
|
||||||
|
|
||||||
|
public class ClashProxies
|
||||||
{
|
{
|
||||||
public class ClashProxies
|
public Dictionary<string, ProxiesItem>? proxies { get; set; }
|
||||||
|
|
||||||
|
public class ProxiesItem
|
||||||
{
|
{
|
||||||
public Dictionary<string, ProxiesItem>? proxies { get; set; }
|
public List<string>? all { get; set; }
|
||||||
|
public List<HistoryItem>? history { get; set; }
|
||||||
public class ProxiesItem
|
public string? name { get; set; }
|
||||||
{
|
public string? type { get; set; }
|
||||||
public List<string>? all { get; set; }
|
public bool udp { get; set; }
|
||||||
public List<HistoryItem>? history { get; set; }
|
public string? now { get; set; }
|
||||||
public string? name { get; set; }
|
public int delay { get; set; }
|
||||||
public string? type { get; set; }
|
|
||||||
public bool udp { get; set; }
|
|
||||||
public string? now { get; set; }
|
|
||||||
public int delay { get; set; }
|
|
||||||
}
|
|
||||||
|
|
||||||
public class HistoryItem
|
|
||||||
{
|
|
||||||
public string? time { get; set; }
|
|
||||||
public int delay { get; set; }
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
public class HistoryItem
|
||||||
|
{
|
||||||
|
public string? time { get; set; }
|
||||||
|
public int delay { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -1,18 +1,17 @@
|
||||||
namespace ServiceLib.Models
|
namespace ServiceLib.Models;
|
||||||
|
|
||||||
|
[Serializable]
|
||||||
|
public class ClashProxyModel
|
||||||
{
|
{
|
||||||
[Serializable]
|
public string? Name { get; set; }
|
||||||
public class ClashProxyModel
|
|
||||||
{
|
|
||||||
public string? Name { get; set; }
|
|
||||||
|
|
||||||
public string? Type { get; set; }
|
public string? Type { get; set; }
|
||||||
|
|
||||||
public string? Now { get; set; }
|
public string? Now { get; set; }
|
||||||
|
|
||||||
public int Delay { get; set; }
|
public int Delay { get; set; }
|
||||||
|
|
||||||
public string? DelayName { get; set; }
|
public string? DelayName { get; set; }
|
||||||
|
|
||||||
public bool IsActive { get; set; }
|
public bool IsActive { get; set; }
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
|
@ -1,8 +1,7 @@
|
||||||
namespace ServiceLib.Models
|
namespace ServiceLib.Models;
|
||||||
|
|
||||||
|
public class CmdItem
|
||||||
{
|
{
|
||||||
public class CmdItem
|
public string? Cmd { get; set; }
|
||||||
{
|
public List<string>? Arguments { get; set; }
|
||||||
public string? Cmd { get; set; }
|
}
|
||||||
public List<string>? Arguments { get; set; }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,15 +1,14 @@
|
||||||
namespace ServiceLib.Models
|
namespace ServiceLib.Models;
|
||||||
{
|
|
||||||
public class ComboItem
|
|
||||||
{
|
|
||||||
public string? ID
|
|
||||||
{
|
|
||||||
get; set;
|
|
||||||
}
|
|
||||||
|
|
||||||
public string? Text
|
public class ComboItem
|
||||||
{
|
{
|
||||||
get; set;
|
public string? ID
|
||||||
}
|
{
|
||||||
|
get; set;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
public string? Text
|
||||||
|
{
|
||||||
|
get; set;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -1,57 +1,56 @@
|
||||||
namespace ServiceLib.Models
|
namespace ServiceLib.Models;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 本软件配置文件实体类
|
||||||
|
/// </summary>
|
||||||
|
[Serializable]
|
||||||
|
public class Config
|
||||||
{
|
{
|
||||||
/// <summary>
|
#region property
|
||||||
/// 本软件配置文件实体类
|
|
||||||
/// </summary>
|
public string IndexId { get; set; }
|
||||||
[Serializable]
|
public string SubIndexId { get; set; }
|
||||||
public class Config
|
|
||||||
|
public ECoreType RunningCoreType { get; set; }
|
||||||
|
|
||||||
|
public bool IsRunningCore(ECoreType type)
|
||||||
{
|
{
|
||||||
#region property
|
switch (type)
|
||||||
|
|
||||||
public string IndexId { get; set; }
|
|
||||||
public string SubIndexId { get; set; }
|
|
||||||
|
|
||||||
public ECoreType RunningCoreType { get; set; }
|
|
||||||
|
|
||||||
public bool IsRunningCore(ECoreType type)
|
|
||||||
{
|
{
|
||||||
switch (type)
|
case ECoreType.Xray when RunningCoreType is ECoreType.Xray or ECoreType.v2fly or ECoreType.v2fly_v5:
|
||||||
{
|
case ECoreType.sing_box when RunningCoreType is ECoreType.sing_box or ECoreType.mihomo:
|
||||||
case ECoreType.Xray when RunningCoreType is ECoreType.Xray or ECoreType.v2fly or ECoreType.v2fly_v5:
|
return true;
|
||||||
case ECoreType.sing_box when RunningCoreType is ECoreType.sing_box or ECoreType.mihomo:
|
|
||||||
return true;
|
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return false;
|
return false;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion property
|
|
||||||
|
|
||||||
#region other entities
|
|
||||||
|
|
||||||
public CoreBasicItem CoreBasicItem { get; set; }
|
|
||||||
public TunModeItem TunModeItem { get; set; }
|
|
||||||
public KcpItem KcpItem { get; set; }
|
|
||||||
public GrpcItem GrpcItem { get; set; }
|
|
||||||
public RoutingBasicItem RoutingBasicItem { get; set; }
|
|
||||||
public GUIItem GuiItem { get; set; }
|
|
||||||
public MsgUIItem MsgUIItem { get; set; }
|
|
||||||
public UIItem UiItem { get; set; }
|
|
||||||
public ConstItem ConstItem { get; set; }
|
|
||||||
public SpeedTestItem SpeedTestItem { get; set; }
|
|
||||||
public Mux4RayItem Mux4RayItem { get; set; }
|
|
||||||
public Mux4SboxItem Mux4SboxItem { get; set; }
|
|
||||||
public HysteriaItem HysteriaItem { get; set; }
|
|
||||||
public ClashUIItem ClashUIItem { get; set; }
|
|
||||||
public SystemProxyItem SystemProxyItem { get; set; }
|
|
||||||
public WebDavItem WebDavItem { get; set; }
|
|
||||||
public CheckUpdateItem CheckUpdateItem { get; set; }
|
|
||||||
public Fragment4RayItem? Fragment4RayItem { get; set; }
|
|
||||||
public List<InItem> Inbound { get; set; }
|
|
||||||
public List<KeyEventItem> GlobalHotkeys { get; set; }
|
|
||||||
public List<CoreTypeItem> CoreTypeItem { get; set; }
|
|
||||||
|
|
||||||
#endregion other entities
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
#endregion property
|
||||||
|
|
||||||
|
#region other entities
|
||||||
|
|
||||||
|
public CoreBasicItem CoreBasicItem { get; set; }
|
||||||
|
public TunModeItem TunModeItem { get; set; }
|
||||||
|
public KcpItem KcpItem { get; set; }
|
||||||
|
public GrpcItem GrpcItem { get; set; }
|
||||||
|
public RoutingBasicItem RoutingBasicItem { get; set; }
|
||||||
|
public GUIItem GuiItem { get; set; }
|
||||||
|
public MsgUIItem MsgUIItem { get; set; }
|
||||||
|
public UIItem UiItem { get; set; }
|
||||||
|
public ConstItem ConstItem { get; set; }
|
||||||
|
public SpeedTestItem SpeedTestItem { get; set; }
|
||||||
|
public Mux4RayItem Mux4RayItem { get; set; }
|
||||||
|
public Mux4SboxItem Mux4SboxItem { get; set; }
|
||||||
|
public HysteriaItem HysteriaItem { get; set; }
|
||||||
|
public ClashUIItem ClashUIItem { get; set; }
|
||||||
|
public SystemProxyItem SystemProxyItem { get; set; }
|
||||||
|
public WebDavItem WebDavItem { get; set; }
|
||||||
|
public CheckUpdateItem CheckUpdateItem { get; set; }
|
||||||
|
public Fragment4RayItem? Fragment4RayItem { get; set; }
|
||||||
|
public List<InItem> Inbound { get; set; }
|
||||||
|
public List<KeyEventItem> GlobalHotkeys { get; set; }
|
||||||
|
public List<CoreTypeItem> CoreTypeItem { get; set; }
|
||||||
|
|
||||||
|
#endregion other entities
|
||||||
|
}
|
||||||
|
|
|
@ -1,248 +1,247 @@
|
||||||
namespace ServiceLib.Models
|
namespace ServiceLib.Models;
|
||||||
|
|
||||||
|
[Serializable]
|
||||||
|
public class CoreBasicItem
|
||||||
{
|
{
|
||||||
[Serializable]
|
public bool LogEnabled { get; set; }
|
||||||
public class CoreBasicItem
|
|
||||||
{
|
|
||||||
public bool LogEnabled { get; set; }
|
|
||||||
|
|
||||||
public string Loglevel { get; set; }
|
public string Loglevel { get; set; }
|
||||||
|
|
||||||
public bool MuxEnabled { get; set; }
|
public bool MuxEnabled { get; set; }
|
||||||
|
|
||||||
public bool DefAllowInsecure { get; set; }
|
public bool DefAllowInsecure { get; set; }
|
||||||
|
|
||||||
public string DefFingerprint { get; set; }
|
public string DefFingerprint { get; set; }
|
||||||
|
|
||||||
public string DefUserAgent { get; set; }
|
public string DefUserAgent { get; set; }
|
||||||
|
|
||||||
public bool EnableFragment { get; set; }
|
public bool EnableFragment { get; set; }
|
||||||
|
|
||||||
public bool EnableCacheFile4Sbox { get; set; } = true;
|
public bool EnableCacheFile4Sbox { get; set; } = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
[Serializable]
|
[Serializable]
|
||||||
public class InItem
|
public class InItem
|
||||||
{
|
{
|
||||||
public int LocalPort { get; set; }
|
public int LocalPort { get; set; }
|
||||||
public string Protocol { get; set; }
|
public string Protocol { get; set; }
|
||||||
public bool UdpEnabled { get; set; }
|
public bool UdpEnabled { get; set; }
|
||||||
public bool SniffingEnabled { get; set; } = true;
|
public bool SniffingEnabled { get; set; } = true;
|
||||||
public List<string>? DestOverride { get; set; } = ["http", "tls"];
|
public List<string>? DestOverride { get; set; } = ["http", "tls"];
|
||||||
public bool RouteOnly { get; set; }
|
public bool RouteOnly { get; set; }
|
||||||
public bool AllowLANConn { get; set; }
|
public bool AllowLANConn { get; set; }
|
||||||
public bool NewPort4LAN { get; set; }
|
public bool NewPort4LAN { get; set; }
|
||||||
public string User { get; set; }
|
public string User { get; set; }
|
||||||
public string Pass { get; set; }
|
public string Pass { get; set; }
|
||||||
public bool SecondLocalPortEnabled { get; set; }
|
public bool SecondLocalPortEnabled { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
[Serializable]
|
[Serializable]
|
||||||
public class KcpItem
|
public class KcpItem
|
||||||
{
|
{
|
||||||
public int Mtu { get; set; }
|
public int Mtu { get; set; }
|
||||||
|
|
||||||
public int Tti { get; set; }
|
public int Tti { get; set; }
|
||||||
|
|
||||||
public int UplinkCapacity { get; set; }
|
public int UplinkCapacity { get; set; }
|
||||||
|
|
||||||
public int DownlinkCapacity { get; set; }
|
public int DownlinkCapacity { get; set; }
|
||||||
|
|
||||||
public bool Congestion { get; set; }
|
public bool Congestion { get; set; }
|
||||||
|
|
||||||
public int ReadBufferSize { get; set; }
|
public int ReadBufferSize { get; set; }
|
||||||
|
|
||||||
public int WriteBufferSize { get; set; }
|
public int WriteBufferSize { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
[Serializable]
|
[Serializable]
|
||||||
public class GrpcItem
|
public class GrpcItem
|
||||||
{
|
{
|
||||||
public int? IdleTimeout { get; set; }
|
public int? IdleTimeout { get; set; }
|
||||||
public int? HealthCheckTimeout { get; set; }
|
public int? HealthCheckTimeout { get; set; }
|
||||||
public bool? PermitWithoutStream { get; set; }
|
public bool? PermitWithoutStream { get; set; }
|
||||||
public int? InitialWindowsSize { get; set; }
|
public int? InitialWindowsSize { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
[Serializable]
|
[Serializable]
|
||||||
public class GUIItem
|
public class GUIItem
|
||||||
{
|
{
|
||||||
public bool AutoRun { get; set; }
|
public bool AutoRun { get; set; }
|
||||||
public bool EnableStatistics { get; set; }
|
public bool EnableStatistics { get; set; }
|
||||||
public bool DisplayRealTimeSpeed { get; set; }
|
public bool DisplayRealTimeSpeed { get; set; }
|
||||||
public bool KeepOlderDedupl { get; set; }
|
public bool KeepOlderDedupl { get; set; }
|
||||||
public int AutoUpdateInterval { get; set; }
|
public int AutoUpdateInterval { get; set; }
|
||||||
public bool EnableSecurityProtocolTls13 { get; set; }
|
public bool EnableSecurityProtocolTls13 { get; set; }
|
||||||
public int TrayMenuServersLimit { get; set; } = 20;
|
public int TrayMenuServersLimit { get; set; } = 20;
|
||||||
public bool EnableHWA { get; set; } = false;
|
public bool EnableHWA { get; set; } = false;
|
||||||
public bool EnableLog { get; set; } = true;
|
public bool EnableLog { get; set; } = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
[Serializable]
|
[Serializable]
|
||||||
public class MsgUIItem
|
public class MsgUIItem
|
||||||
{
|
{
|
||||||
public string? MainMsgFilter { get; set; }
|
public string? MainMsgFilter { get; set; }
|
||||||
public bool? AutoRefresh { get; set; }
|
public bool? AutoRefresh { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
[Serializable]
|
[Serializable]
|
||||||
public class UIItem
|
public class UIItem
|
||||||
{
|
{
|
||||||
public bool EnableAutoAdjustMainLvColWidth { get; set; }
|
public bool EnableAutoAdjustMainLvColWidth { get; set; }
|
||||||
public bool EnableUpdateSubOnlyRemarksExist { get; set; }
|
public bool EnableUpdateSubOnlyRemarksExist { get; set; }
|
||||||
public double MainWidth { get; set; }
|
public double MainWidth { get; set; }
|
||||||
public double MainHeight { get; set; }
|
public double MainHeight { get; set; }
|
||||||
public double MainGirdHeight1 { get; set; }
|
public double MainGirdHeight1 { get; set; }
|
||||||
public double MainGirdHeight2 { get; set; }
|
public double MainGirdHeight2 { get; set; }
|
||||||
public EGirdOrientation MainGirdOrientation { get; set; } = EGirdOrientation.Vertical;
|
public EGirdOrientation MainGirdOrientation { get; set; } = EGirdOrientation.Vertical;
|
||||||
public string? ColorPrimaryName { get; set; }
|
public string? ColorPrimaryName { get; set; }
|
||||||
public string? CurrentTheme { get; set; }
|
public string? CurrentTheme { get; set; }
|
||||||
public string CurrentLanguage { get; set; }
|
public string CurrentLanguage { get; set; }
|
||||||
public string CurrentFontFamily { get; set; }
|
public string CurrentFontFamily { get; set; }
|
||||||
public int CurrentFontSize { get; set; }
|
public int CurrentFontSize { get; set; }
|
||||||
public bool EnableDragDropSort { get; set; }
|
public bool EnableDragDropSort { get; set; }
|
||||||
public bool DoubleClick2Activate { get; set; }
|
public bool DoubleClick2Activate { get; set; }
|
||||||
public bool AutoHideStartup { get; set; }
|
public bool AutoHideStartup { get; set; }
|
||||||
public bool Hide2TrayWhenClose { get; set; }
|
public bool Hide2TrayWhenClose { get; set; }
|
||||||
public List<ColumnItem> MainColumnItem { get; set; }
|
public List<ColumnItem> MainColumnItem { get; set; }
|
||||||
public bool ShowInTaskbar { get; set; }
|
public bool ShowInTaskbar { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
[Serializable]
|
[Serializable]
|
||||||
public class ConstItem
|
public class ConstItem
|
||||||
{
|
{
|
||||||
public string? SubConvertUrl { get; set; }
|
public string? SubConvertUrl { get; set; }
|
||||||
public string? GeoSourceUrl { get; set; }
|
public string? GeoSourceUrl { get; set; }
|
||||||
public string? SrsSourceUrl { get; set; }
|
public string? SrsSourceUrl { get; set; }
|
||||||
public string? RouteRulesTemplateSourceUrl { get; set; }
|
public string? RouteRulesTemplateSourceUrl { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
[Serializable]
|
[Serializable]
|
||||||
public class KeyEventItem
|
public class KeyEventItem
|
||||||
{
|
{
|
||||||
public EGlobalHotkey EGlobalHotkey { get; set; }
|
public EGlobalHotkey EGlobalHotkey { get; set; }
|
||||||
|
|
||||||
public bool Alt { get; set; }
|
public bool Alt { get; set; }
|
||||||
|
|
||||||
public bool Control { get; set; }
|
public bool Control { get; set; }
|
||||||
|
|
||||||
public bool Shift { get; set; }
|
public bool Shift { get; set; }
|
||||||
|
|
||||||
public int? KeyCode { get; set; }
|
public int? KeyCode { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
[Serializable]
|
[Serializable]
|
||||||
public class CoreTypeItem
|
public class CoreTypeItem
|
||||||
{
|
{
|
||||||
public EConfigType ConfigType { get; set; }
|
public EConfigType ConfigType { get; set; }
|
||||||
|
|
||||||
public ECoreType CoreType { get; set; }
|
public ECoreType CoreType { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
[Serializable]
|
[Serializable]
|
||||||
public class TunModeItem
|
public class TunModeItem
|
||||||
{
|
{
|
||||||
public bool EnableTun { get; set; }
|
public bool EnableTun { get; set; }
|
||||||
public bool StrictRoute { get; set; } = true;
|
public bool StrictRoute { get; set; } = true;
|
||||||
public string Stack { get; set; }
|
public string Stack { get; set; }
|
||||||
public int Mtu { get; set; }
|
public int Mtu { get; set; }
|
||||||
public bool EnableExInbound { get; set; }
|
public bool EnableExInbound { get; set; }
|
||||||
public bool EnableIPv6Address { get; set; }
|
public bool EnableIPv6Address { get; set; }
|
||||||
public string? LinuxSudoPwd { get; set; }
|
public string? LinuxSudoPwd { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
[Serializable]
|
[Serializable]
|
||||||
public class SpeedTestItem
|
public class SpeedTestItem
|
||||||
{
|
{
|
||||||
public int SpeedTestTimeout { get; set; }
|
public int SpeedTestTimeout { get; set; }
|
||||||
public string SpeedTestUrl { get; set; }
|
public string SpeedTestUrl { get; set; }
|
||||||
public string SpeedPingTestUrl { get; set; }
|
public string SpeedPingTestUrl { get; set; }
|
||||||
public int MixedConcurrencyCount { get; set; }
|
public int MixedConcurrencyCount { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
[Serializable]
|
[Serializable]
|
||||||
public class RoutingBasicItem
|
public class RoutingBasicItem
|
||||||
{
|
{
|
||||||
public string DomainStrategy { get; set; }
|
public string DomainStrategy { get; set; }
|
||||||
public string DomainStrategy4Singbox { get; set; }
|
public string DomainStrategy4Singbox { get; set; }
|
||||||
public string DomainMatcher { get; set; }
|
public string DomainMatcher { get; set; }
|
||||||
public string RoutingIndexId { get; set; }
|
public string RoutingIndexId { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
[Serializable]
|
[Serializable]
|
||||||
public class ColumnItem
|
public class ColumnItem
|
||||||
{
|
{
|
||||||
public string Name { get; set; }
|
public string Name { get; set; }
|
||||||
public int Width { get; set; }
|
public int Width { get; set; }
|
||||||
public int Index { get; set; }
|
public int Index { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
[Serializable]
|
[Serializable]
|
||||||
public class Mux4RayItem
|
public class Mux4RayItem
|
||||||
{
|
{
|
||||||
public int? Concurrency { get; set; }
|
public int? Concurrency { get; set; }
|
||||||
public int? XudpConcurrency { get; set; }
|
public int? XudpConcurrency { get; set; }
|
||||||
public string? XudpProxyUDP443 { get; set; }
|
public string? XudpProxyUDP443 { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
[Serializable]
|
[Serializable]
|
||||||
public class Mux4SboxItem
|
public class Mux4SboxItem
|
||||||
{
|
{
|
||||||
public string Protocol { get; set; }
|
public string Protocol { get; set; }
|
||||||
public int MaxConnections { get; set; }
|
public int MaxConnections { get; set; }
|
||||||
public bool? Padding { get; set; }
|
public bool? Padding { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
[Serializable]
|
[Serializable]
|
||||||
public class HysteriaItem
|
public class HysteriaItem
|
||||||
{
|
{
|
||||||
public int UpMbps { get; set; }
|
public int UpMbps { get; set; }
|
||||||
public int DownMbps { get; set; }
|
public int DownMbps { get; set; }
|
||||||
public int HopInterval { get; set; } = 30;
|
public int HopInterval { get; set; } = 30;
|
||||||
}
|
}
|
||||||
|
|
||||||
[Serializable]
|
[Serializable]
|
||||||
public class ClashUIItem
|
public class ClashUIItem
|
||||||
{
|
{
|
||||||
public ERuleMode RuleMode { get; set; }
|
public ERuleMode RuleMode { get; set; }
|
||||||
public bool EnableIPv6 { get; set; }
|
public bool EnableIPv6 { get; set; }
|
||||||
public bool EnableMixinContent { get; set; }
|
public bool EnableMixinContent { get; set; }
|
||||||
public int ProxiesSorting { get; set; }
|
public int ProxiesSorting { get; set; }
|
||||||
public bool ProxiesAutoRefresh { get; set; }
|
public bool ProxiesAutoRefresh { get; set; }
|
||||||
public int ProxiesAutoDelayTestInterval { get; set; } = 10;
|
public int ProxiesAutoDelayTestInterval { get; set; } = 10;
|
||||||
public bool ConnectionsAutoRefresh { get; set; }
|
public bool ConnectionsAutoRefresh { get; set; }
|
||||||
public int ConnectionsRefreshInterval { get; set; } = 2;
|
public int ConnectionsRefreshInterval { get; set; } = 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
[Serializable]
|
[Serializable]
|
||||||
public class SystemProxyItem
|
public class SystemProxyItem
|
||||||
{
|
{
|
||||||
public ESysProxyType SysProxyType { get; set; }
|
public ESysProxyType SysProxyType { get; set; }
|
||||||
public string SystemProxyExceptions { get; set; }
|
public string SystemProxyExceptions { get; set; }
|
||||||
public bool NotProxyLocalAddress { get; set; } = true;
|
public bool NotProxyLocalAddress { get; set; } = true;
|
||||||
public string SystemProxyAdvancedProtocol { get; set; }
|
public string SystemProxyAdvancedProtocol { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
[Serializable]
|
[Serializable]
|
||||||
public class WebDavItem
|
public class WebDavItem
|
||||||
{
|
{
|
||||||
public string? Url { get; set; }
|
public string? Url { get; set; }
|
||||||
public string? UserName { get; set; }
|
public string? UserName { get; set; }
|
||||||
public string? Password { get; set; }
|
public string? Password { get; set; }
|
||||||
public string? DirName { get; set; }
|
public string? DirName { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
[Serializable]
|
[Serializable]
|
||||||
public class CheckUpdateItem
|
public class CheckUpdateItem
|
||||||
{
|
{
|
||||||
public bool CheckPreReleaseUpdate { get; set; }
|
public bool CheckPreReleaseUpdate { get; set; }
|
||||||
public List<string>? SelectedCoreTypes { get; set; }
|
public List<string>? SelectedCoreTypes { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
[Serializable]
|
[Serializable]
|
||||||
public class Fragment4RayItem
|
public class Fragment4RayItem
|
||||||
{
|
{
|
||||||
public string? Packets { get; set; }
|
public string? Packets { get; set; }
|
||||||
public string? Length { get; set; }
|
public string? Length { get; set; }
|
||||||
public string? Interval { get; set; }
|
public string? Interval { get; set; }
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,21 +1,20 @@
|
||||||
namespace ServiceLib.Models
|
namespace ServiceLib.Models;
|
||||||
|
|
||||||
|
[Serializable]
|
||||||
|
public class CoreInfo
|
||||||
{
|
{
|
||||||
[Serializable]
|
public ECoreType CoreType { get; set; }
|
||||||
public class CoreInfo
|
public List<string>? CoreExes { get; set; }
|
||||||
{
|
public string? Arguments { get; set; }
|
||||||
public ECoreType CoreType { get; set; }
|
public string? Url { get; set; }
|
||||||
public List<string>? CoreExes { get; set; }
|
public string? ReleaseApiUrl { get; set; }
|
||||||
public string? Arguments { get; set; }
|
public string? DownloadUrlWin64 { get; set; }
|
||||||
public string? Url { get; set; }
|
public string? DownloadUrlWinArm64 { get; set; }
|
||||||
public string? ReleaseApiUrl { get; set; }
|
public string? DownloadUrlLinux64 { get; set; }
|
||||||
public string? DownloadUrlWin64 { get; set; }
|
public string? DownloadUrlLinuxArm64 { get; set; }
|
||||||
public string? DownloadUrlWinArm64 { get; set; }
|
public string? DownloadUrlOSX64 { get; set; }
|
||||||
public string? DownloadUrlLinux64 { get; set; }
|
public string? DownloadUrlOSXArm64 { get; set; }
|
||||||
public string? DownloadUrlLinuxArm64 { get; set; }
|
public string? Match { get; set; }
|
||||||
public string? DownloadUrlOSX64 { get; set; }
|
public string? VersionArg { get; set; }
|
||||||
public string? DownloadUrlOSXArm64 { get; set; }
|
public bool AbsolutePath { get; set; }
|
||||||
public string? Match { get; set; }
|
|
||||||
public string? VersionArg { get; set; }
|
|
||||||
public bool AbsolutePath { get; set; }
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,20 +1,19 @@
|
||||||
using SQLite;
|
using SQLite;
|
||||||
|
|
||||||
namespace ServiceLib.Models
|
namespace ServiceLib.Models;
|
||||||
|
|
||||||
|
[Serializable]
|
||||||
|
public class DNSItem
|
||||||
{
|
{
|
||||||
[Serializable]
|
[PrimaryKey]
|
||||||
public class DNSItem
|
public string Id { get; set; }
|
||||||
{
|
|
||||||
[PrimaryKey]
|
|
||||||
public string Id { get; set; }
|
|
||||||
|
|
||||||
public string Remarks { get; set; }
|
public string Remarks { get; set; }
|
||||||
public bool Enabled { get; set; } = true;
|
public bool Enabled { get; set; } = true;
|
||||||
public ECoreType CoreType { get; set; }
|
public ECoreType CoreType { get; set; }
|
||||||
public bool UseSystemHosts { get; set; }
|
public bool UseSystemHosts { get; set; }
|
||||||
public string? NormalDNS { get; set; }
|
public string? NormalDNS { get; set; }
|
||||||
public string? TunDNS { get; set; }
|
public string? TunDNS { get; set; }
|
||||||
public string? DomainStrategy4Freedom { get; set; }
|
public string? DomainStrategy4Freedom { get; set; }
|
||||||
public string? DomainDNSAddress { get; set; }
|
public string? DomainDNSAddress { get; set; }
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
|
@ -1,68 +1,67 @@
|
||||||
using System.Text.Json.Serialization;
|
using System.Text.Json.Serialization;
|
||||||
|
|
||||||
namespace ServiceLib.Models
|
namespace ServiceLib.Models;
|
||||||
|
|
||||||
|
public class GitHubReleaseAsset
|
||||||
{
|
{
|
||||||
public class GitHubReleaseAsset
|
[JsonPropertyName("url")] public string? Url { get; set; }
|
||||||
{
|
|
||||||
[JsonPropertyName("url")] public string? Url { get; set; }
|
|
||||||
|
|
||||||
[JsonPropertyName("id")] public int Id { get; set; }
|
[JsonPropertyName("id")] public int Id { get; set; }
|
||||||
|
|
||||||
[JsonPropertyName("node_id")] public string? NodeId { get; set; }
|
[JsonPropertyName("node_id")] public string? NodeId { get; set; }
|
||||||
|
|
||||||
[JsonPropertyName("name")] public string? Name { get; set; }
|
[JsonPropertyName("name")] public string? Name { get; set; }
|
||||||
|
|
||||||
[JsonPropertyName("label")] public object Label { get; set; }
|
[JsonPropertyName("label")] public object Label { get; set; }
|
||||||
|
|
||||||
[JsonPropertyName("content_type")] public string? ContentType { get; set; }
|
[JsonPropertyName("content_type")] public string? ContentType { get; set; }
|
||||||
|
|
||||||
[JsonPropertyName("state")] public string? State { get; set; }
|
[JsonPropertyName("state")] public string? State { get; set; }
|
||||||
|
|
||||||
[JsonPropertyName("size")] public int Size { get; set; }
|
[JsonPropertyName("size")] public int Size { get; set; }
|
||||||
|
|
||||||
[JsonPropertyName("download_count")] public int DownloadCount { get; set; }
|
[JsonPropertyName("download_count")] public int DownloadCount { get; set; }
|
||||||
|
|
||||||
[JsonPropertyName("created_at")] public DateTime CreatedAt { get; set; }
|
[JsonPropertyName("created_at")] public DateTime CreatedAt { get; set; }
|
||||||
|
|
||||||
[JsonPropertyName("updated_at")] public DateTime UpdatedAt { get; set; }
|
[JsonPropertyName("updated_at")] public DateTime UpdatedAt { get; set; }
|
||||||
|
|
||||||
[JsonPropertyName("browser_download_url")] public string? BrowserDownloadUrl { get; set; }
|
[JsonPropertyName("browser_download_url")] public string? BrowserDownloadUrl { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public class GitHubRelease
|
public class GitHubRelease
|
||||||
{
|
{
|
||||||
[JsonPropertyName("url")] public string? Url { get; set; }
|
[JsonPropertyName("url")] public string? Url { get; set; }
|
||||||
|
|
||||||
[JsonPropertyName("assets_url")] public string? AssetsUrl { get; set; }
|
[JsonPropertyName("assets_url")] public string? AssetsUrl { get; set; }
|
||||||
|
|
||||||
[JsonPropertyName("upload_url")] public string? UploadUrl { get; set; }
|
[JsonPropertyName("upload_url")] public string? UploadUrl { get; set; }
|
||||||
|
|
||||||
[JsonPropertyName("html_url")] public string? HtmlUrl { get; set; }
|
[JsonPropertyName("html_url")] public string? HtmlUrl { get; set; }
|
||||||
|
|
||||||
[JsonPropertyName("id")] public int Id { get; set; }
|
[JsonPropertyName("id")] public int Id { get; set; }
|
||||||
|
|
||||||
[JsonPropertyName("node_id")] public string? NodeId { get; set; }
|
[JsonPropertyName("node_id")] public string? NodeId { get; set; }
|
||||||
|
|
||||||
[JsonPropertyName("tag_name")] public string? TagName { get; set; }
|
[JsonPropertyName("tag_name")] public string? TagName { get; set; }
|
||||||
|
|
||||||
[JsonPropertyName("target_commitish")] public string? TargetCommitish { get; set; }
|
[JsonPropertyName("target_commitish")] public string? TargetCommitish { get; set; }
|
||||||
|
|
||||||
[JsonPropertyName("name")] public string? Name { get; set; }
|
[JsonPropertyName("name")] public string? Name { get; set; }
|
||||||
|
|
||||||
[JsonPropertyName("draft")] public bool Draft { get; set; }
|
[JsonPropertyName("draft")] public bool Draft { get; set; }
|
||||||
|
|
||||||
[JsonPropertyName("prerelease")] public bool Prerelease { get; set; }
|
[JsonPropertyName("prerelease")] public bool Prerelease { get; set; }
|
||||||
|
|
||||||
[JsonPropertyName("created_at")] public DateTime CreatedAt { get; set; }
|
[JsonPropertyName("created_at")] public DateTime CreatedAt { get; set; }
|
||||||
|
|
||||||
[JsonPropertyName("published_at")] public DateTime PublishedAt { get; set; }
|
[JsonPropertyName("published_at")] public DateTime PublishedAt { get; set; }
|
||||||
|
|
||||||
[JsonPropertyName("assets")] public List<GitHubReleaseAsset> Assets { get; set; }
|
[JsonPropertyName("assets")] public List<GitHubReleaseAsset> Assets { get; set; }
|
||||||
|
|
||||||
[JsonPropertyName("tarball_url")] public string? TarballUrl { get; set; }
|
[JsonPropertyName("tarball_url")] public string? TarballUrl { get; set; }
|
||||||
|
|
||||||
[JsonPropertyName("zipball_url")] public string? ZipballUrl { get; set; }
|
[JsonPropertyName("zipball_url")] public string? ZipballUrl { get; set; }
|
||||||
|
|
||||||
[JsonPropertyName("body")] public string? Body { get; set; }
|
[JsonPropertyName("body")] public string? Body { get; set; }
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
|
@ -1,13 +1,12 @@
|
||||||
namespace ServiceLib.Models
|
namespace ServiceLib.Models;
|
||||||
|
|
||||||
|
internal class IPAPIInfo
|
||||||
{
|
{
|
||||||
internal class IPAPIInfo
|
public string? ip { get; set; }
|
||||||
{
|
public string? city { get; set; }
|
||||||
public string? ip { get; set; }
|
public string? region { get; set; }
|
||||||
public string? city { get; set; }
|
public string? region_code { get; set; }
|
||||||
public string? region { get; set; }
|
public string? country { get; set; }
|
||||||
public string? region_code { get; set; }
|
public string? country_name { get; set; }
|
||||||
public string? country { get; set; }
|
public string? country_code { get; set; }
|
||||||
public string? country_name { get; set; }
|
}
|
||||||
public string? country_code { get; set; }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,16 +1,15 @@
|
||||||
using SQLite;
|
using SQLite;
|
||||||
|
|
||||||
namespace ServiceLib.Models
|
namespace ServiceLib.Models;
|
||||||
{
|
|
||||||
[Serializable]
|
|
||||||
public class ProfileExItem
|
|
||||||
{
|
|
||||||
[PrimaryKey]
|
|
||||||
public string IndexId { get; set; }
|
|
||||||
|
|
||||||
public int Delay { get; set; }
|
[Serializable]
|
||||||
public decimal Speed { get; set; }
|
public class ProfileExItem
|
||||||
public int Sort { get; set; }
|
{
|
||||||
public string? Message { get; set; }
|
[PrimaryKey]
|
||||||
}
|
public string IndexId { get; set; }
|
||||||
|
|
||||||
|
public int Delay { get; set; }
|
||||||
|
public decimal Speed { get; set; }
|
||||||
|
public int Sort { get; set; }
|
||||||
|
public string? Message { get; set; }
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,96 +1,96 @@
|
||||||
using SQLite;
|
using SQLite;
|
||||||
|
|
||||||
namespace ServiceLib.Models
|
namespace ServiceLib.Models;
|
||||||
|
|
||||||
|
[Serializable]
|
||||||
|
public class ProfileItem
|
||||||
{
|
{
|
||||||
[Serializable]
|
public ProfileItem()
|
||||||
public class ProfileItem
|
|
||||||
{
|
{
|
||||||
public ProfileItem()
|
IndexId = string.Empty;
|
||||||
{
|
ConfigType = EConfigType.VMess;
|
||||||
IndexId = string.Empty;
|
ConfigVersion = 2;
|
||||||
ConfigType = EConfigType.VMess;
|
Address = string.Empty;
|
||||||
ConfigVersion = 2;
|
Port = 0;
|
||||||
Address = string.Empty;
|
Id = string.Empty;
|
||||||
Port = 0;
|
AlterId = 0;
|
||||||
Id = string.Empty;
|
Security = string.Empty;
|
||||||
AlterId = 0;
|
Network = string.Empty;
|
||||||
Security = string.Empty;
|
Remarks = string.Empty;
|
||||||
Network = string.Empty;
|
HeaderType = string.Empty;
|
||||||
Remarks = string.Empty;
|
RequestHost = string.Empty;
|
||||||
HeaderType = string.Empty;
|
Path = string.Empty;
|
||||||
RequestHost = string.Empty;
|
StreamSecurity = string.Empty;
|
||||||
Path = string.Empty;
|
AllowInsecure = string.Empty;
|
||||||
StreamSecurity = string.Empty;
|
Subid = string.Empty;
|
||||||
AllowInsecure = string.Empty;
|
Flow = string.Empty;
|
||||||
Subid = string.Empty;
|
|
||||||
Flow = string.Empty;
|
|
||||||
}
|
|
||||||
|
|
||||||
#region function
|
|
||||||
|
|
||||||
public string GetSummary()
|
|
||||||
{
|
|
||||||
var summary = $"[{(ConfigType).ToString()}] ";
|
|
||||||
var arrAddr = Address.Split('.');
|
|
||||||
var addr = arrAddr.Length switch
|
|
||||||
{
|
|
||||||
> 2 => $"{arrAddr.First()}***{arrAddr.Last()}",
|
|
||||||
> 1 => $"***{arrAddr.Last()}",
|
|
||||||
_ => Address
|
|
||||||
};
|
|
||||||
summary += ConfigType switch
|
|
||||||
{
|
|
||||||
EConfigType.Custom => $"[{CoreType.ToString()}]{Remarks}",
|
|
||||||
_ => $"{Remarks}({addr}:{Port})"
|
|
||||||
};
|
|
||||||
return summary;
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<string>? GetAlpn()
|
|
||||||
{
|
|
||||||
return Alpn.IsNullOrEmpty() ? null : Utils.String2List(Alpn);
|
|
||||||
}
|
|
||||||
|
|
||||||
public string GetNetwork()
|
|
||||||
{
|
|
||||||
if (Network.IsNullOrEmpty() || !Global.Networks.Contains(Network))
|
|
||||||
{
|
|
||||||
return Global.DefaultNetwork;
|
|
||||||
}
|
|
||||||
return Network.TrimEx();
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion function
|
|
||||||
|
|
||||||
[PrimaryKey]
|
|
||||||
public string IndexId { get; set; }
|
|
||||||
public EConfigType ConfigType { get; set; }
|
|
||||||
public int ConfigVersion { get; set; }
|
|
||||||
public string Address { get; set; }
|
|
||||||
public int Port { get; set; }
|
|
||||||
public string Ports { get; set; }
|
|
||||||
public string Id { get; set; }
|
|
||||||
public int AlterId { get; set; }
|
|
||||||
public string Security { get; set; }
|
|
||||||
public string Network { get; set; }
|
|
||||||
public string Remarks { get; set; }
|
|
||||||
public string HeaderType { get; set; }
|
|
||||||
public string RequestHost { get; set; }
|
|
||||||
public string Path { get; set; }
|
|
||||||
public string StreamSecurity { get; set; }
|
|
||||||
public string AllowInsecure { get; set; }
|
|
||||||
public string Subid { get; set; }
|
|
||||||
public bool IsSub { get; set; } = true;
|
|
||||||
public string Flow { get; set; }
|
|
||||||
public string Sni { get; set; }
|
|
||||||
public string Alpn { get; set; } = string.Empty;
|
|
||||||
public ECoreType? CoreType { get; set; }
|
|
||||||
public int? PreSocksPort { get; set; }
|
|
||||||
public string Fingerprint { get; set; }
|
|
||||||
public bool DisplayLog { get; set; } = true;
|
|
||||||
public string PublicKey { get; set; }
|
|
||||||
public string ShortId { get; set; }
|
|
||||||
public string SpiderX { get; set; }
|
|
||||||
public string Extra { get; set; }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#region function
|
||||||
|
|
||||||
|
public string GetSummary()
|
||||||
|
{
|
||||||
|
var summary = $"[{(ConfigType).ToString()}] ";
|
||||||
|
var arrAddr = Address.Split('.');
|
||||||
|
var addr = arrAddr.Length switch
|
||||||
|
{
|
||||||
|
> 2 => $"{arrAddr.First()}***{arrAddr.Last()}",
|
||||||
|
> 1 => $"***{arrAddr.Last()}",
|
||||||
|
_ => Address
|
||||||
|
};
|
||||||
|
summary += ConfigType switch
|
||||||
|
{
|
||||||
|
EConfigType.Custom => $"[{CoreType.ToString()}]{Remarks}",
|
||||||
|
_ => $"{Remarks}({addr}:{Port})"
|
||||||
|
};
|
||||||
|
return summary;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<string>? GetAlpn()
|
||||||
|
{
|
||||||
|
return Alpn.IsNullOrEmpty() ? null : Utils.String2List(Alpn);
|
||||||
|
}
|
||||||
|
|
||||||
|
public string GetNetwork()
|
||||||
|
{
|
||||||
|
if (Network.IsNullOrEmpty() || !Global.Networks.Contains(Network))
|
||||||
|
{
|
||||||
|
return Global.DefaultNetwork;
|
||||||
|
}
|
||||||
|
return Network.TrimEx();
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion function
|
||||||
|
|
||||||
|
[PrimaryKey]
|
||||||
|
public string IndexId { get; set; }
|
||||||
|
|
||||||
|
public EConfigType ConfigType { get; set; }
|
||||||
|
public int ConfigVersion { get; set; }
|
||||||
|
public string Address { get; set; }
|
||||||
|
public int Port { get; set; }
|
||||||
|
public string Ports { get; set; }
|
||||||
|
public string Id { get; set; }
|
||||||
|
public int AlterId { get; set; }
|
||||||
|
public string Security { get; set; }
|
||||||
|
public string Network { get; set; }
|
||||||
|
public string Remarks { get; set; }
|
||||||
|
public string HeaderType { get; set; }
|
||||||
|
public string RequestHost { get; set; }
|
||||||
|
public string Path { get; set; }
|
||||||
|
public string StreamSecurity { get; set; }
|
||||||
|
public string AllowInsecure { get; set; }
|
||||||
|
public string Subid { get; set; }
|
||||||
|
public bool IsSub { get; set; } = true;
|
||||||
|
public string Flow { get; set; }
|
||||||
|
public string Sni { get; set; }
|
||||||
|
public string Alpn { get; set; } = string.Empty;
|
||||||
|
public ECoreType? CoreType { get; set; }
|
||||||
|
public int? PreSocksPort { get; set; }
|
||||||
|
public string Fingerprint { get; set; }
|
||||||
|
public bool DisplayLog { get; set; } = true;
|
||||||
|
public string PublicKey { get; set; }
|
||||||
|
public string ShortId { get; set; }
|
||||||
|
public string SpiderX { get; set; }
|
||||||
|
public string Extra { get; set; }
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,18 +1,17 @@
|
||||||
namespace ServiceLib.Models
|
namespace ServiceLib.Models;
|
||||||
|
|
||||||
|
[Serializable]
|
||||||
|
public class ProfileItemModel : ProfileItem
|
||||||
{
|
{
|
||||||
[Serializable]
|
public bool IsActive { get; set; }
|
||||||
public class ProfileItemModel : ProfileItem
|
public string SubRemarks { get; set; }
|
||||||
{
|
public int Delay { get; set; }
|
||||||
public bool IsActive { get; set; }
|
public decimal Speed { get; set; }
|
||||||
public string SubRemarks { get; set; }
|
public int Sort { get; set; }
|
||||||
public int Delay { get; set; }
|
public string DelayVal { get; set; }
|
||||||
public decimal Speed { get; set; }
|
public string SpeedVal { get; set; }
|
||||||
public int Sort { get; set; }
|
public string TodayUp { get; set; }
|
||||||
public string DelayVal { get; set; }
|
public string TodayDown { get; set; }
|
||||||
public string SpeedVal { get; set; }
|
public string TotalUp { get; set; }
|
||||||
public string TodayUp { get; set; }
|
public string TotalDown { get; set; }
|
||||||
public string TodayDown { get; set; }
|
}
|
||||||
public string TotalUp { get; set; }
|
|
||||||
public string TotalDown { get; set; }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,27 +1,26 @@
|
||||||
namespace ServiceLib.Models
|
namespace ServiceLib.Models;
|
||||||
|
|
||||||
|
public class RetResult
|
||||||
{
|
{
|
||||||
public class RetResult
|
public bool Success { get; set; }
|
||||||
|
public string? Msg { get; set; }
|
||||||
|
public object? Data { get; set; }
|
||||||
|
|
||||||
|
public RetResult(bool success = false)
|
||||||
{
|
{
|
||||||
public bool Success { get; set; }
|
Success = success;
|
||||||
public string? Msg { get; set; }
|
|
||||||
public object? Data { get; set; }
|
|
||||||
|
|
||||||
public RetResult(bool success = false)
|
|
||||||
{
|
|
||||||
Success = success;
|
|
||||||
}
|
|
||||||
|
|
||||||
public RetResult(bool success, string? msg)
|
|
||||||
{
|
|
||||||
Success = success;
|
|
||||||
Msg = msg;
|
|
||||||
}
|
|
||||||
|
|
||||||
public RetResult(bool success, string? msg, object? data)
|
|
||||||
{
|
|
||||||
Success = success;
|
|
||||||
Msg = msg;
|
|
||||||
Data = data;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
public RetResult(bool success, string? msg)
|
||||||
|
{
|
||||||
|
Success = success;
|
||||||
|
Msg = msg;
|
||||||
|
}
|
||||||
|
|
||||||
|
public RetResult(bool success, string? msg, object? data)
|
||||||
|
{
|
||||||
|
Success = success;
|
||||||
|
Msg = msg;
|
||||||
|
Data = data;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -1,23 +1,22 @@
|
||||||
using SQLite;
|
using SQLite;
|
||||||
|
|
||||||
namespace ServiceLib.Models
|
namespace ServiceLib.Models;
|
||||||
|
|
||||||
|
[Serializable]
|
||||||
|
public class RoutingItem
|
||||||
{
|
{
|
||||||
[Serializable]
|
[PrimaryKey]
|
||||||
public class RoutingItem
|
public string Id { get; set; }
|
||||||
{
|
|
||||||
[PrimaryKey]
|
|
||||||
public string Id { get; set; }
|
|
||||||
|
|
||||||
public string Remarks { get; set; }
|
public string Remarks { get; set; }
|
||||||
public string Url { get; set; }
|
public string Url { get; set; }
|
||||||
public string RuleSet { get; set; }
|
public string RuleSet { get; set; }
|
||||||
public int RuleNum { get; set; }
|
public int RuleNum { get; set; }
|
||||||
public bool Enabled { get; set; } = true;
|
public bool Enabled { get; set; } = true;
|
||||||
public bool Locked { get; set; }
|
public bool Locked { get; set; }
|
||||||
public string CustomIcon { get; set; }
|
public string CustomIcon { get; set; }
|
||||||
public string CustomRulesetPath4Singbox { get; set; }
|
public string CustomRulesetPath4Singbox { get; set; }
|
||||||
public string DomainStrategy { get; set; }
|
public string DomainStrategy { get; set; }
|
||||||
public string DomainStrategy4Singbox { get; set; }
|
public string DomainStrategy4Singbox { get; set; }
|
||||||
public int Sort { get; set; }
|
public int Sort { get; set; }
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
|
@ -1,8 +1,7 @@
|
||||||
namespace ServiceLib.Models
|
namespace ServiceLib.Models;
|
||||||
|
|
||||||
|
[Serializable]
|
||||||
|
public class RoutingItemModel : RoutingItem
|
||||||
{
|
{
|
||||||
[Serializable]
|
public bool IsActive { get; set; }
|
||||||
public class RoutingItemModel : RoutingItem
|
}
|
||||||
{
|
|
||||||
public bool IsActive { get; set; }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,9 +1,8 @@
|
||||||
namespace ServiceLib.Models
|
namespace ServiceLib.Models;
|
||||||
|
|
||||||
|
[Serializable]
|
||||||
|
public class RoutingTemplate
|
||||||
{
|
{
|
||||||
[Serializable]
|
public string Version { get; set; }
|
||||||
public class RoutingTemplate
|
public RoutingItem[] RoutingItems { get; set; }
|
||||||
{
|
}
|
||||||
public string Version { get; set; }
|
|
||||||
public RoutingItem[] RoutingItems { get; set; }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,19 +1,18 @@
|
||||||
namespace ServiceLib.Models
|
namespace ServiceLib.Models;
|
||||||
|
|
||||||
|
[Serializable]
|
||||||
|
public class RulesItem
|
||||||
{
|
{
|
||||||
[Serializable]
|
public string Id { get; set; }
|
||||||
public class RulesItem
|
public string? Type { get; set; }
|
||||||
{
|
public string? Port { get; set; }
|
||||||
public string Id { get; set; }
|
public string? Network { get; set; }
|
||||||
public string? Type { get; set; }
|
public List<string>? InboundTag { get; set; }
|
||||||
public string? Port { get; set; }
|
public string? OutboundTag { get; set; }
|
||||||
public string? Network { get; set; }
|
public List<string>? Ip { get; set; }
|
||||||
public List<string>? InboundTag { get; set; }
|
public List<string>? Domain { get; set; }
|
||||||
public string? OutboundTag { get; set; }
|
public List<string>? Protocol { get; set; }
|
||||||
public List<string>? Ip { get; set; }
|
public List<string>? Process { get; set; }
|
||||||
public List<string>? Domain { get; set; }
|
public bool Enabled { get; set; } = true;
|
||||||
public List<string>? Protocol { get; set; }
|
public string? Remarks { get; set; }
|
||||||
public List<string>? Process { get; set; }
|
}
|
||||||
public bool Enabled { get; set; } = true;
|
|
||||||
public string? Remarks { get; set; }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,11 +1,10 @@
|
||||||
namespace ServiceLib.Models
|
namespace ServiceLib.Models;
|
||||||
|
|
||||||
|
[Serializable]
|
||||||
|
public class RulesItemModel : RulesItem
|
||||||
{
|
{
|
||||||
[Serializable]
|
public string InboundTags { get; set; }
|
||||||
public class RulesItemModel : RulesItem
|
public string Ips { get; set; }
|
||||||
{
|
public string Domains { get; set; }
|
||||||
public string InboundTags { get; set; }
|
public string Protocols { get; set; }
|
||||||
public string Ips { get; set; }
|
}
|
||||||
public string Domains { get; set; }
|
|
||||||
public string Protocols { get; set; }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,22 +1,21 @@
|
||||||
namespace ServiceLib.Models
|
namespace ServiceLib.Models;
|
||||||
|
|
||||||
|
[Serializable]
|
||||||
|
public class ServerSpeedItem : ServerStatItem
|
||||||
{
|
{
|
||||||
[Serializable]
|
public long ProxyUp { get; set; }
|
||||||
public class ServerSpeedItem : ServerStatItem
|
|
||||||
{
|
|
||||||
public long ProxyUp { get; set; }
|
|
||||||
|
|
||||||
public long ProxyDown { get; set; }
|
public long ProxyDown { get; set; }
|
||||||
|
|
||||||
public long DirectUp { get; set; }
|
public long DirectUp { get; set; }
|
||||||
|
|
||||||
public long DirectDown { get; set; }
|
public long DirectDown { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
[Serializable]
|
[Serializable]
|
||||||
public class TrafficItem
|
public class TrafficItem
|
||||||
{
|
{
|
||||||
public ulong Up { get; set; }
|
public ulong Up { get; set; }
|
||||||
|
|
||||||
public ulong Down { get; set; }
|
public ulong Down { get; set; }
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
|
@ -1,21 +1,20 @@
|
||||||
using SQLite;
|
using SQLite;
|
||||||
|
|
||||||
namespace ServiceLib.Models
|
namespace ServiceLib.Models;
|
||||||
|
|
||||||
|
[Serializable]
|
||||||
|
public class ServerStatItem
|
||||||
{
|
{
|
||||||
[Serializable]
|
[PrimaryKey]
|
||||||
public class ServerStatItem
|
public string IndexId { get; set; }
|
||||||
{
|
|
||||||
[PrimaryKey]
|
|
||||||
public string IndexId { get; set; }
|
|
||||||
|
|
||||||
public long TotalUp { get; set; }
|
public long TotalUp { get; set; }
|
||||||
|
|
||||||
public long TotalDown { get; set; }
|
public long TotalDown { get; set; }
|
||||||
|
|
||||||
public long TodayUp { get; set; }
|
public long TodayUp { get; set; }
|
||||||
|
|
||||||
public long TodayDown { get; set; }
|
public long TodayDown { get; set; }
|
||||||
|
|
||||||
public long DateNow { get; set; }
|
public long DateNow { get; set; }
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
|
@ -1,13 +1,12 @@
|
||||||
namespace ServiceLib.Models
|
namespace ServiceLib.Models;
|
||||||
|
|
||||||
|
[Serializable]
|
||||||
|
public class ServerTestItem
|
||||||
{
|
{
|
||||||
[Serializable]
|
public string? IndexId { get; set; }
|
||||||
public class ServerTestItem
|
public string? Address { get; set; }
|
||||||
{
|
public int Port { get; set; }
|
||||||
public string? IndexId { get; set; }
|
public EConfigType ConfigType { get; set; }
|
||||||
public string? Address { get; set; }
|
public bool AllowTest { get; set; }
|
||||||
public int Port { get; set; }
|
public int QueueNum { get; set; }
|
||||||
public EConfigType ConfigType { get; set; }
|
|
||||||
public bool AllowTest { get; set; }
|
|
||||||
public int QueueNum { get; set; }
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,257 +1,256 @@
|
||||||
namespace ServiceLib.Models
|
namespace ServiceLib.Models;
|
||||||
|
|
||||||
|
public class SingboxConfig
|
||||||
{
|
{
|
||||||
public class SingboxConfig
|
public Log4Sbox log { get; set; }
|
||||||
{
|
public Dns4Sbox? dns { get; set; }
|
||||||
public Log4Sbox log { get; set; }
|
public List<Inbound4Sbox> inbounds { get; set; }
|
||||||
public Dns4Sbox? dns { get; set; }
|
public List<Outbound4Sbox> outbounds { get; set; }
|
||||||
public List<Inbound4Sbox> inbounds { get; set; }
|
public Route4Sbox route { get; set; }
|
||||||
public List<Outbound4Sbox> outbounds { get; set; }
|
public Experimental4Sbox? experimental { get; set; }
|
||||||
public Route4Sbox route { get; set; }
|
}
|
||||||
public Experimental4Sbox? experimental { get; set; }
|
|
||||||
}
|
public class Log4Sbox
|
||||||
|
{
|
||||||
public class Log4Sbox
|
public bool? disabled { get; set; }
|
||||||
{
|
public string level { get; set; }
|
||||||
public bool? disabled { get; set; }
|
public string output { get; set; }
|
||||||
public string level { get; set; }
|
public bool? timestamp { get; set; }
|
||||||
public string output { get; set; }
|
}
|
||||||
public bool? timestamp { get; set; }
|
|
||||||
}
|
public class Dns4Sbox
|
||||||
|
{
|
||||||
public class Dns4Sbox
|
public List<Server4Sbox> servers { get; set; }
|
||||||
{
|
public List<Rule4Sbox> rules { get; set; }
|
||||||
public List<Server4Sbox> servers { get; set; }
|
public string? final { get; set; }
|
||||||
public List<Rule4Sbox> rules { get; set; }
|
public string? strategy { get; set; }
|
||||||
public string? final { get; set; }
|
public bool? disable_cache { get; set; }
|
||||||
public string? strategy { get; set; }
|
public bool? disable_expire { get; set; }
|
||||||
public bool? disable_cache { get; set; }
|
public bool? independent_cache { get; set; }
|
||||||
public bool? disable_expire { get; set; }
|
public bool? reverse_mapping { get; set; }
|
||||||
public bool? independent_cache { get; set; }
|
public string? client_subnet { get; set; }
|
||||||
public bool? reverse_mapping { get; set; }
|
public Fakeip4Sbox? fakeip { get; set; }
|
||||||
public string? client_subnet { get; set; }
|
}
|
||||||
public Fakeip4Sbox? fakeip { get; set; }
|
|
||||||
}
|
public class Route4Sbox
|
||||||
|
{
|
||||||
public class Route4Sbox
|
public bool? auto_detect_interface { get; set; }
|
||||||
{
|
public List<Rule4Sbox> rules { get; set; }
|
||||||
public bool? auto_detect_interface { get; set; }
|
public List<Ruleset4Sbox>? rule_set { get; set; }
|
||||||
public List<Rule4Sbox> rules { get; set; }
|
}
|
||||||
public List<Ruleset4Sbox>? rule_set { get; set; }
|
|
||||||
}
|
[Serializable]
|
||||||
|
public class Rule4Sbox
|
||||||
[Serializable]
|
{
|
||||||
public class Rule4Sbox
|
public string? outbound { get; set; }
|
||||||
{
|
public string? server { get; set; }
|
||||||
public string? outbound { get; set; }
|
public bool? disable_cache { get; set; }
|
||||||
public string? server { get; set; }
|
public string? type { get; set; }
|
||||||
public bool? disable_cache { get; set; }
|
public string? mode { get; set; }
|
||||||
public string? type { get; set; }
|
public bool? ip_is_private { get; set; }
|
||||||
public string? mode { get; set; }
|
public string? client_subnet { get; set; }
|
||||||
public bool? ip_is_private { get; set; }
|
public bool? invert { get; set; }
|
||||||
public string? client_subnet { get; set; }
|
public string? clash_mode { get; set; }
|
||||||
public bool? invert { get; set; }
|
public List<string>? inbound { get; set; }
|
||||||
public string? clash_mode { get; set; }
|
public List<string>? protocol { get; set; }
|
||||||
public List<string>? inbound { get; set; }
|
public List<string>? network { get; set; }
|
||||||
public List<string>? protocol { get; set; }
|
public List<int>? port { get; set; }
|
||||||
public List<string>? network { get; set; }
|
public List<string>? port_range { get; set; }
|
||||||
public List<int>? port { get; set; }
|
public List<string>? geosite { get; set; }
|
||||||
public List<string>? port_range { get; set; }
|
public List<string>? domain { get; set; }
|
||||||
public List<string>? geosite { get; set; }
|
public List<string>? domain_suffix { get; set; }
|
||||||
public List<string>? domain { get; set; }
|
public List<string>? domain_keyword { get; set; }
|
||||||
public List<string>? domain_suffix { get; set; }
|
public List<string>? domain_regex { get; set; }
|
||||||
public List<string>? domain_keyword { get; set; }
|
public List<string>? geoip { get; set; }
|
||||||
public List<string>? domain_regex { get; set; }
|
public List<string>? ip_cidr { get; set; }
|
||||||
public List<string>? geoip { get; set; }
|
public List<string>? source_ip_cidr { get; set; }
|
||||||
public List<string>? ip_cidr { get; set; }
|
public List<string>? process_name { get; set; }
|
||||||
public List<string>? source_ip_cidr { get; set; }
|
public List<string>? rule_set { get; set; }
|
||||||
public List<string>? process_name { get; set; }
|
public List<Rule4Sbox>? rules { get; set; }
|
||||||
public List<string>? rule_set { get; set; }
|
}
|
||||||
public List<Rule4Sbox>? rules { get; set; }
|
|
||||||
}
|
[Serializable]
|
||||||
|
public class Inbound4Sbox
|
||||||
[Serializable]
|
{
|
||||||
public class Inbound4Sbox
|
public string type { get; set; }
|
||||||
{
|
public string tag { get; set; }
|
||||||
public string type { get; set; }
|
public string listen { get; set; }
|
||||||
public string tag { get; set; }
|
public int? listen_port { get; set; }
|
||||||
public string listen { get; set; }
|
public string? domain_strategy { get; set; }
|
||||||
public int? listen_port { get; set; }
|
public string interface_name { get; set; }
|
||||||
public string? domain_strategy { get; set; }
|
public List<string>? address { get; set; }
|
||||||
public string interface_name { get; set; }
|
public int? mtu { get; set; }
|
||||||
public List<string>? address { get; set; }
|
public bool? auto_route { get; set; }
|
||||||
public int? mtu { get; set; }
|
public bool? strict_route { get; set; }
|
||||||
public bool? auto_route { get; set; }
|
public bool? endpoint_independent_nat { get; set; }
|
||||||
public bool? strict_route { get; set; }
|
public string? stack { get; set; }
|
||||||
public bool? endpoint_independent_nat { get; set; }
|
public bool? sniff { get; set; }
|
||||||
public string? stack { get; set; }
|
public bool? sniff_override_destination { get; set; }
|
||||||
public bool? sniff { get; set; }
|
public List<User4Sbox> users { get; set; }
|
||||||
public bool? sniff_override_destination { get; set; }
|
}
|
||||||
public List<User4Sbox> users { get; set; }
|
|
||||||
}
|
public class User4Sbox
|
||||||
|
{
|
||||||
public class User4Sbox
|
public string username { get; set; }
|
||||||
{
|
public string password { get; set; }
|
||||||
public string username { get; set; }
|
}
|
||||||
public string password { get; set; }
|
|
||||||
}
|
public class Outbound4Sbox
|
||||||
|
{
|
||||||
public class Outbound4Sbox
|
public string type { get; set; }
|
||||||
{
|
public string tag { get; set; }
|
||||||
public string type { get; set; }
|
public string? server { get; set; }
|
||||||
public string tag { get; set; }
|
public int? server_port { get; set; }
|
||||||
public string? server { get; set; }
|
public List<string>? server_ports { get; set; }
|
||||||
public int? server_port { get; set; }
|
public string? uuid { get; set; }
|
||||||
public List<string>? server_ports { get; set; }
|
public string? security { get; set; }
|
||||||
public string? uuid { get; set; }
|
public int? alter_id { get; set; }
|
||||||
public string? security { get; set; }
|
public string? flow { get; set; }
|
||||||
public int? alter_id { get; set; }
|
public string? hop_interval { get; set; }
|
||||||
public string? flow { get; set; }
|
public int? up_mbps { get; set; }
|
||||||
public string? hop_interval { get; set; }
|
public int? down_mbps { get; set; }
|
||||||
public int? up_mbps { get; set; }
|
public string? auth_str { get; set; }
|
||||||
public int? down_mbps { get; set; }
|
public int? recv_window_conn { get; set; }
|
||||||
public string? auth_str { get; set; }
|
public int? recv_window { get; set; }
|
||||||
public int? recv_window_conn { get; set; }
|
public bool? disable_mtu_discovery { get; set; }
|
||||||
public int? recv_window { get; set; }
|
public string? detour { get; set; }
|
||||||
public bool? disable_mtu_discovery { get; set; }
|
public string? method { get; set; }
|
||||||
public string? detour { get; set; }
|
public string? username { get; set; }
|
||||||
public string? method { get; set; }
|
public string? password { get; set; }
|
||||||
public string? username { get; set; }
|
public string? congestion_control { get; set; }
|
||||||
public string? password { get; set; }
|
public string? version { get; set; }
|
||||||
public string? congestion_control { get; set; }
|
public string? network { get; set; }
|
||||||
public string? version { get; set; }
|
public string? packet_encoding { get; set; }
|
||||||
public string? network { get; set; }
|
public List<string>? local_address { get; set; }
|
||||||
public string? packet_encoding { get; set; }
|
public string? private_key { get; set; }
|
||||||
public List<string>? local_address { get; set; }
|
public string? peer_public_key { get; set; }
|
||||||
public string? private_key { get; set; }
|
public List<int>? reserved { get; set; }
|
||||||
public string? peer_public_key { get; set; }
|
public int? mtu { get; set; }
|
||||||
public List<int>? reserved { get; set; }
|
public string? plugin { get; set; }
|
||||||
public int? mtu { get; set; }
|
public string? plugin_opts { get; set; }
|
||||||
public string? plugin { get; set; }
|
public Tls4Sbox? tls { get; set; }
|
||||||
public string? plugin_opts { get; set; }
|
public Multiplex4Sbox? multiplex { get; set; }
|
||||||
public Tls4Sbox? tls { get; set; }
|
public Transport4Sbox? transport { get; set; }
|
||||||
public Multiplex4Sbox? multiplex { get; set; }
|
public HyObfs4Sbox? obfs { get; set; }
|
||||||
public Transport4Sbox? transport { get; set; }
|
public List<string>? outbounds { get; set; }
|
||||||
public HyObfs4Sbox? obfs { get; set; }
|
public bool? interrupt_exist_connections { get; set; }
|
||||||
public List<string>? outbounds { get; set; }
|
}
|
||||||
public bool? interrupt_exist_connections { get; set; }
|
|
||||||
}
|
public class Tls4Sbox
|
||||||
|
{
|
||||||
public class Tls4Sbox
|
public bool enabled { get; set; }
|
||||||
{
|
public string? server_name { get; set; }
|
||||||
public bool enabled { get; set; }
|
public bool? insecure { get; set; }
|
||||||
public string? server_name { get; set; }
|
public List<string>? alpn { get; set; }
|
||||||
public bool? insecure { get; set; }
|
public Utls4Sbox? utls { get; set; }
|
||||||
public List<string>? alpn { get; set; }
|
public Reality4Sbox? reality { get; set; }
|
||||||
public Utls4Sbox? utls { get; set; }
|
}
|
||||||
public Reality4Sbox? reality { get; set; }
|
|
||||||
}
|
public class Multiplex4Sbox
|
||||||
|
{
|
||||||
public class Multiplex4Sbox
|
public bool enabled { get; set; }
|
||||||
{
|
public string protocol { get; set; }
|
||||||
public bool enabled { get; set; }
|
public int max_connections { get; set; }
|
||||||
public string protocol { get; set; }
|
public bool? padding { get; set; }
|
||||||
public int max_connections { get; set; }
|
}
|
||||||
public bool? padding { get; set; }
|
|
||||||
}
|
public class Utls4Sbox
|
||||||
|
{
|
||||||
public class Utls4Sbox
|
public bool enabled { get; set; }
|
||||||
{
|
public string fingerprint { get; set; }
|
||||||
public bool enabled { get; set; }
|
}
|
||||||
public string fingerprint { get; set; }
|
|
||||||
}
|
public class Reality4Sbox
|
||||||
|
{
|
||||||
public class Reality4Sbox
|
public bool enabled { get; set; }
|
||||||
{
|
public string public_key { get; set; }
|
||||||
public bool enabled { get; set; }
|
public string short_id { get; set; }
|
||||||
public string public_key { get; set; }
|
}
|
||||||
public string short_id { get; set; }
|
|
||||||
}
|
public class Transport4Sbox
|
||||||
|
{
|
||||||
public class Transport4Sbox
|
public string? type { get; set; }
|
||||||
{
|
public object? host { get; set; }
|
||||||
public string? type { get; set; }
|
public string? path { get; set; }
|
||||||
public object? host { get; set; }
|
public Headers4Sbox? headers { get; set; }
|
||||||
public string? path { get; set; }
|
|
||||||
public Headers4Sbox? headers { get; set; }
|
public string? service_name { get; set; }
|
||||||
|
public string? idle_timeout { get; set; }
|
||||||
public string? service_name { get; set; }
|
public string? ping_timeout { get; set; }
|
||||||
public string? idle_timeout { get; set; }
|
public bool? permit_without_stream { get; set; }
|
||||||
public string? ping_timeout { get; set; }
|
}
|
||||||
public bool? permit_without_stream { get; set; }
|
|
||||||
}
|
public class Headers4Sbox
|
||||||
|
{
|
||||||
public class Headers4Sbox
|
public string? Host { get; set; }
|
||||||
{
|
}
|
||||||
public string? Host { get; set; }
|
|
||||||
}
|
public class HyObfs4Sbox
|
||||||
|
{
|
||||||
public class HyObfs4Sbox
|
public string? type { get; set; }
|
||||||
{
|
public string? password { get; set; }
|
||||||
public string? type { get; set; }
|
}
|
||||||
public string? password { get; set; }
|
|
||||||
}
|
public class Server4Sbox
|
||||||
|
{
|
||||||
public class Server4Sbox
|
public string? tag { get; set; }
|
||||||
{
|
public string? address { get; set; }
|
||||||
public string? tag { get; set; }
|
public string? address_resolver { get; set; }
|
||||||
public string? address { get; set; }
|
public string? address_strategy { get; set; }
|
||||||
public string? address_resolver { get; set; }
|
public string? strategy { get; set; }
|
||||||
public string? address_strategy { get; set; }
|
public string? detour { get; set; }
|
||||||
public string? strategy { get; set; }
|
public string? client_subnet { get; set; }
|
||||||
public string? detour { get; set; }
|
}
|
||||||
public string? client_subnet { get; set; }
|
|
||||||
}
|
public class Experimental4Sbox
|
||||||
|
{
|
||||||
public class Experimental4Sbox
|
public CacheFile4Sbox? cache_file { get; set; }
|
||||||
{
|
public V2ray_Api4Sbox? v2ray_api { get; set; }
|
||||||
public CacheFile4Sbox? cache_file { get; set; }
|
public Clash_Api4Sbox? clash_api { get; set; }
|
||||||
public V2ray_Api4Sbox? v2ray_api { get; set; }
|
}
|
||||||
public Clash_Api4Sbox? clash_api { get; set; }
|
|
||||||
}
|
public class V2ray_Api4Sbox
|
||||||
|
{
|
||||||
public class V2ray_Api4Sbox
|
public string listen { get; set; }
|
||||||
{
|
public Stats4Sbox stats { get; set; }
|
||||||
public string listen { get; set; }
|
}
|
||||||
public Stats4Sbox stats { get; set; }
|
|
||||||
}
|
public class Clash_Api4Sbox
|
||||||
|
{
|
||||||
public class Clash_Api4Sbox
|
public string? external_controller { get; set; }
|
||||||
{
|
public bool? store_selected { get; set; }
|
||||||
public string? external_controller { get; set; }
|
}
|
||||||
public bool? store_selected { get; set; }
|
|
||||||
}
|
public class Stats4Sbox
|
||||||
|
{
|
||||||
public class Stats4Sbox
|
public bool enabled { get; set; }
|
||||||
{
|
public List<string>? inbounds { get; set; }
|
||||||
public bool enabled { get; set; }
|
public List<string>? outbounds { get; set; }
|
||||||
public List<string>? inbounds { get; set; }
|
public List<string>? users { get; set; }
|
||||||
public List<string>? outbounds { get; set; }
|
}
|
||||||
public List<string>? users { get; set; }
|
|
||||||
}
|
public class Fakeip4Sbox
|
||||||
|
{
|
||||||
public class Fakeip4Sbox
|
public bool enabled { get; set; }
|
||||||
{
|
public string inet4_range { get; set; }
|
||||||
public bool enabled { get; set; }
|
public string inet6_range { get; set; }
|
||||||
public string inet4_range { get; set; }
|
}
|
||||||
public string inet6_range { get; set; }
|
|
||||||
}
|
public class CacheFile4Sbox
|
||||||
|
{
|
||||||
public class CacheFile4Sbox
|
public bool enabled { get; set; }
|
||||||
{
|
public string? path { get; set; }
|
||||||
public bool enabled { get; set; }
|
public string? cache_id { get; set; }
|
||||||
public string? path { get; set; }
|
public bool? store_fakeip { get; set; }
|
||||||
public string? cache_id { get; set; }
|
}
|
||||||
public bool? store_fakeip { get; set; }
|
|
||||||
}
|
public class Ruleset4Sbox
|
||||||
|
{
|
||||||
public class Ruleset4Sbox
|
public string? tag { get; set; }
|
||||||
{
|
public string? type { get; set; }
|
||||||
public string? tag { get; set; }
|
public string? format { get; set; }
|
||||||
public string? type { get; set; }
|
public string? path { get; set; }
|
||||||
public string? format { get; set; }
|
public string? url { get; set; }
|
||||||
public string? path { get; set; }
|
public string? download_detour { get; set; }
|
||||||
public string? url { get; set; }
|
public string? update_interval { get; set; }
|
||||||
public string? download_detour { get; set; }
|
|
||||||
public string? update_interval { get; set; }
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,12 +1,11 @@
|
||||||
namespace ServiceLib.Models
|
namespace ServiceLib.Models;
|
||||||
|
|
||||||
|
[Serializable]
|
||||||
|
public class SpeedTestResult
|
||||||
{
|
{
|
||||||
[Serializable]
|
public string? IndexId { get; set; }
|
||||||
public class SpeedTestResult
|
|
||||||
{
|
|
||||||
public string? IndexId { get; set; }
|
|
||||||
|
|
||||||
public string? Delay { get; set; }
|
public string? Delay { get; set; }
|
||||||
|
|
||||||
public string? Speed { get; set; }
|
public string? Speed { get; set; }
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
|
@ -1,18 +1,17 @@
|
||||||
namespace ServiceLib.Models
|
namespace ServiceLib.Models;
|
||||||
{
|
|
||||||
public class SsSIP008
|
|
||||||
{
|
|
||||||
public List<SsServer>? servers { get; set; }
|
|
||||||
}
|
|
||||||
|
|
||||||
[Serializable]
|
public class SsSIP008
|
||||||
public class SsServer
|
{
|
||||||
{
|
public List<SsServer>? servers { get; set; }
|
||||||
public string? remarks { get; set; }
|
}
|
||||||
public string? server { get; set; }
|
|
||||||
public string? server_port { get; set; }
|
[Serializable]
|
||||||
public string? method { get; set; }
|
public class SsServer
|
||||||
public string? password { get; set; }
|
{
|
||||||
public string? plugin { get; set; }
|
public string? remarks { get; set; }
|
||||||
}
|
public string? server { get; set; }
|
||||||
}
|
public string? server_port { get; set; }
|
||||||
|
public string? method { get; set; }
|
||||||
|
public string? password { get; set; }
|
||||||
|
public string? plugin { get; set; }
|
||||||
|
}
|
||||||
|
|
|
@ -1,39 +1,38 @@
|
||||||
using SQLite;
|
using SQLite;
|
||||||
|
|
||||||
namespace ServiceLib.Models
|
namespace ServiceLib.Models;
|
||||||
|
|
||||||
|
[Serializable]
|
||||||
|
public class SubItem
|
||||||
{
|
{
|
||||||
[Serializable]
|
[PrimaryKey]
|
||||||
public class SubItem
|
public string Id { get; set; }
|
||||||
{
|
|
||||||
[PrimaryKey]
|
|
||||||
public string Id { get; set; }
|
|
||||||
|
|
||||||
public string Remarks { get; set; }
|
public string Remarks { get; set; }
|
||||||
|
|
||||||
public string Url { get; set; }
|
public string Url { get; set; }
|
||||||
|
|
||||||
public string MoreUrl { get; set; }
|
public string MoreUrl { get; set; }
|
||||||
|
|
||||||
public bool Enabled { get; set; } = true;
|
public bool Enabled { get; set; } = true;
|
||||||
|
|
||||||
public string UserAgent { get; set; } = string.Empty;
|
public string UserAgent { get; set; } = string.Empty;
|
||||||
|
|
||||||
public int Sort { get; set; }
|
public int Sort { get; set; }
|
||||||
|
|
||||||
public string? Filter { get; set; }
|
public string? Filter { get; set; }
|
||||||
|
|
||||||
public int AutoUpdateInterval { get; set; }
|
public int AutoUpdateInterval { get; set; }
|
||||||
|
|
||||||
public long UpdateTime { get; set; }
|
public long UpdateTime { get; set; }
|
||||||
|
|
||||||
public string? ConvertTarget { get; set; }
|
public string? ConvertTarget { get; set; }
|
||||||
|
|
||||||
public string? PrevProfile { get; set; }
|
public string? PrevProfile { get; set; }
|
||||||
|
|
||||||
public string? NextProfile { get; set; }
|
public string? NextProfile { get; set; }
|
||||||
|
|
||||||
public int? PreSocksPort { get; set; }
|
public int? PreSocksPort { get; set; }
|
||||||
|
|
||||||
public string? Memo { get; set; }
|
public string? Memo { get; set; }
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
|
@ -1,395 +1,436 @@
|
||||||
using System.Text.Json.Serialization;
|
using System.Text.Json.Serialization;
|
||||||
|
|
||||||
namespace ServiceLib.Models
|
namespace ServiceLib.Models;
|
||||||
|
|
||||||
|
public class V2rayConfig
|
||||||
{
|
{
|
||||||
public class V2rayConfig
|
public Log4Ray log { get; set; }
|
||||||
{
|
public object dns { get; set; }
|
||||||
public Log4Ray log { get; set; }
|
public List<Inbounds4Ray> inbounds { get; set; }
|
||||||
public object dns { get; set; }
|
public List<Outbounds4Ray> outbounds { get; set; }
|
||||||
public List<Inbounds4Ray> inbounds { get; set; }
|
public Routing4Ray routing { get; set; }
|
||||||
public List<Outbounds4Ray> outbounds { get; set; }
|
public Metrics4Ray? metrics { get; set; }
|
||||||
public Routing4Ray routing { get; set; }
|
public Policy4Ray? policy { get; set; }
|
||||||
public Metrics4Ray? metrics { get; set; }
|
public Stats4Ray? stats { get; set; }
|
||||||
public Policy4Ray? policy { get; set; }
|
public Observatory4Ray? observatory { get; set; }
|
||||||
public Stats4Ray? stats { get; set; }
|
public BurstObservatory4Ray? burstObservatory { get; set; }
|
||||||
public string? remarks { get; set; }
|
public string? remarks { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public class Stats4Ray
|
public class Stats4Ray
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
public class Metrics4Ray
|
public class Metrics4Ray
|
||||||
{
|
{
|
||||||
public string tag { get; set; }
|
public string tag { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public class Policy4Ray
|
public class Policy4Ray
|
||||||
{
|
{
|
||||||
public SystemPolicy4Ray system { get; set; }
|
public SystemPolicy4Ray system { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public class SystemPolicy4Ray
|
public class SystemPolicy4Ray
|
||||||
{
|
{
|
||||||
public bool statsOutboundUplink { get; set; }
|
public bool statsOutboundUplink { get; set; }
|
||||||
public bool statsOutboundDownlink { get; set; }
|
public bool statsOutboundDownlink { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public class Log4Ray
|
public class Log4Ray
|
||||||
{
|
{
|
||||||
public string? access { get; set; }
|
public string? access { get; set; }
|
||||||
|
|
||||||
public string? error { get; set; }
|
public string? error { get; set; }
|
||||||
|
|
||||||
public string? loglevel { get; set; }
|
public string? loglevel { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public class Inbounds4Ray
|
public class Inbounds4Ray
|
||||||
{
|
{
|
||||||
public string tag { get; set; }
|
public string tag { get; set; }
|
||||||
|
|
||||||
public int port { get; set; }
|
public int port { get; set; }
|
||||||
|
|
||||||
public string listen { get; set; }
|
public string listen { get; set; }
|
||||||
|
|
||||||
public string protocol { get; set; }
|
public string protocol { get; set; }
|
||||||
|
|
||||||
public Sniffing4Ray sniffing { get; set; }
|
public Sniffing4Ray sniffing { get; set; }
|
||||||
|
|
||||||
public Inboundsettings4Ray settings { get; set; }
|
public Inboundsettings4Ray settings { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public class Inboundsettings4Ray
|
public class Inboundsettings4Ray
|
||||||
{
|
{
|
||||||
public string? auth { get; set; }
|
public string? auth { get; set; }
|
||||||
|
|
||||||
public bool? udp { get; set; }
|
public bool? udp { get; set; }
|
||||||
|
|
||||||
public string? ip { get; set; }
|
public string? ip { get; set; }
|
||||||
|
|
||||||
public string? address { get; set; }
|
public string? address { get; set; }
|
||||||
|
|
||||||
public List<UsersItem4Ray>? clients { get; set; }
|
public List<UsersItem4Ray>? clients { get; set; }
|
||||||
|
|
||||||
public string? decryption { get; set; }
|
public string? decryption { get; set; }
|
||||||
|
|
||||||
public bool? allowTransparent { get; set; }
|
public bool? allowTransparent { get; set; }
|
||||||
|
|
||||||
public List<AccountsItem4Ray>? accounts { get; set; }
|
public List<AccountsItem4Ray>? accounts { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public class UsersItem4Ray
|
public class UsersItem4Ray
|
||||||
{
|
{
|
||||||
public string? id { get; set; }
|
public string? id { get; set; }
|
||||||
|
|
||||||
public int? alterId { get; set; }
|
public int? alterId { get; set; }
|
||||||
|
|
||||||
public string? email { get; set; }
|
public string? email { get; set; }
|
||||||
|
|
||||||
public string? security { get; set; }
|
public string? security { get; set; }
|
||||||
|
|
||||||
public string? encryption { get; set; }
|
public string? encryption { get; set; }
|
||||||
|
|
||||||
public string? flow { get; set; }
|
public string? flow { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public class Sniffing4Ray
|
public class Sniffing4Ray
|
||||||
{
|
{
|
||||||
public bool enabled { get; set; }
|
public bool enabled { get; set; }
|
||||||
public List<string>? destOverride { get; set; }
|
public List<string>? destOverride { get; set; }
|
||||||
public bool routeOnly { get; set; }
|
public bool routeOnly { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public class Outbounds4Ray
|
public class Outbounds4Ray
|
||||||
{
|
{
|
||||||
public string tag { get; set; }
|
public string tag { get; set; }
|
||||||
|
|
||||||
public string protocol { get; set; }
|
public string protocol { get; set; }
|
||||||
|
|
||||||
public Outboundsettings4Ray settings { get; set; }
|
public Outboundsettings4Ray settings { get; set; }
|
||||||
|
|
||||||
public StreamSettings4Ray streamSettings { get; set; }
|
public StreamSettings4Ray streamSettings { get; set; }
|
||||||
|
|
||||||
public Mux4Ray mux { get; set; }
|
public Mux4Ray mux { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public class Outboundsettings4Ray
|
public class Outboundsettings4Ray
|
||||||
{
|
{
|
||||||
public List<VnextItem4Ray>? vnext { get; set; }
|
public List<VnextItem4Ray>? vnext { get; set; }
|
||||||
|
|
||||||
public List<ServersItem4Ray>? servers { get; set; }
|
public List<ServersItem4Ray>? servers { get; set; }
|
||||||
|
|
||||||
public Response4Ray? response { get; set; }
|
public Response4Ray? response { get; set; }
|
||||||
|
|
||||||
public string domainStrategy { get; set; }
|
public string domainStrategy { get; set; }
|
||||||
|
|
||||||
public int? userLevel { get; set; }
|
public int? userLevel { get; set; }
|
||||||
|
|
||||||
public FragmentItem4Ray? fragment { get; set; }
|
public FragmentItem4Ray? fragment { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public class VnextItem4Ray
|
public class VnextItem4Ray
|
||||||
{
|
{
|
||||||
public string address { get; set; }
|
public string address { get; set; }
|
||||||
|
|
||||||
public int port { get; set; }
|
public int port { get; set; }
|
||||||
|
|
||||||
public List<UsersItem4Ray> users { get; set; }
|
public List<UsersItem4Ray> users { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public class ServersItem4Ray
|
public class ServersItem4Ray
|
||||||
{
|
{
|
||||||
public string email { get; set; }
|
public string email { get; set; }
|
||||||
|
|
||||||
public string address { get; set; }
|
public string address { get; set; }
|
||||||
|
|
||||||
public string? method { get; set; }
|
public string? method { get; set; }
|
||||||
|
|
||||||
public bool? ota { get; set; }
|
public bool? ota { get; set; }
|
||||||
|
|
||||||
public string? password { get; set; }
|
public string? password { get; set; }
|
||||||
|
|
||||||
public int port { get; set; }
|
public int port { get; set; }
|
||||||
|
|
||||||
public int? level { get; set; }
|
public int? level { get; set; }
|
||||||
|
|
||||||
public string flow { get; set; }
|
public string flow { get; set; }
|
||||||
|
|
||||||
public List<SocksUsersItem4Ray> users { get; set; }
|
public List<SocksUsersItem4Ray> users { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public class SocksUsersItem4Ray
|
public class SocksUsersItem4Ray
|
||||||
{
|
{
|
||||||
public string user { get; set; }
|
public string user { get; set; }
|
||||||
|
|
||||||
public string pass { get; set; }
|
public string pass { get; set; }
|
||||||
|
|
||||||
public int? level { get; set; }
|
public int? level { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public class Mux4Ray
|
public class Mux4Ray
|
||||||
{
|
{
|
||||||
public bool enabled { get; set; }
|
public bool enabled { get; set; }
|
||||||
public int? concurrency { get; set; }
|
public int? concurrency { get; set; }
|
||||||
public int? xudpConcurrency { get; set; }
|
public int? xudpConcurrency { get; set; }
|
||||||
public string? xudpProxyUDP443 { get; set; }
|
public string? xudpProxyUDP443 { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public class Response4Ray
|
public class Response4Ray
|
||||||
{
|
{
|
||||||
public string type { get; set; }
|
public string type { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public class Dns4Ray
|
public class Dns4Ray
|
||||||
{
|
{
|
||||||
public List<string> servers { get; set; }
|
public List<string> servers { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public class DnsServer4Ray
|
public class DnsServer4Ray
|
||||||
{
|
{
|
||||||
public string? address { get; set; }
|
public string? address { get; set; }
|
||||||
public List<string>? domains { get; set; }
|
public List<string>? domains { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public class Routing4Ray
|
public class Routing4Ray
|
||||||
{
|
{
|
||||||
public string domainStrategy { get; set; }
|
public string domainStrategy { get; set; }
|
||||||
|
|
||||||
public string? domainMatcher { get; set; }
|
public string? domainMatcher { get; set; }
|
||||||
|
|
||||||
public List<RulesItem4Ray> rules { get; set; }
|
public List<RulesItem4Ray> rules { get; set; }
|
||||||
|
|
||||||
public List<BalancersItem4Ray>? balancers { get; set; }
|
public List<BalancersItem4Ray>? balancers { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
[Serializable]
|
[Serializable]
|
||||||
public class RulesItem4Ray
|
public class RulesItem4Ray
|
||||||
{
|
{
|
||||||
public string? type { get; set; }
|
public string? type { get; set; }
|
||||||
|
|
||||||
public string? port { get; set; }
|
public string? port { get; set; }
|
||||||
public string? network { get; set; }
|
public string? network { get; set; }
|
||||||
|
|
||||||
public List<string>? inboundTag { get; set; }
|
public List<string>? inboundTag { get; set; }
|
||||||
|
|
||||||
public string? outboundTag { get; set; }
|
public string? outboundTag { get; set; }
|
||||||
|
|
||||||
public string? balancerTag { get; set; }
|
public string? balancerTag { get; set; }
|
||||||
|
|
||||||
public List<string>? ip { get; set; }
|
public List<string>? ip { get; set; }
|
||||||
|
|
||||||
public List<string>? domain { get; set; }
|
public List<string>? domain { get; set; }
|
||||||
|
|
||||||
public List<string>? protocol { get; set; }
|
public List<string>? protocol { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public class BalancersItem4Ray
|
public class BalancersItem4Ray
|
||||||
{
|
{
|
||||||
public List<string>? selector { get; set; }
|
public List<string>? selector { get; set; }
|
||||||
public BalancersStrategy4Ray? strategy { get; set; }
|
public BalancersStrategy4Ray? strategy { get; set; }
|
||||||
public string? tag { get; set; }
|
public string? tag { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public class BalancersStrategy4Ray
|
public class BalancersStrategy4Ray
|
||||||
{
|
{
|
||||||
public string? type { get; set; }
|
public string? type { get; set; }
|
||||||
}
|
public BalancersStrategySettings4Ray? settings { get; set; }
|
||||||
|
}
|
||||||
public class StreamSettings4Ray
|
|
||||||
{
|
public class BalancersStrategySettings4Ray
|
||||||
public string network { get; set; }
|
{
|
||||||
|
public int? expected { get; set; }
|
||||||
public string security { get; set; }
|
public string? maxRTT { get; set; }
|
||||||
|
public float? tolerance { get; set; }
|
||||||
public TlsSettings4Ray? tlsSettings { get; set; }
|
public List<string>? baselines { get; set; }
|
||||||
|
public List<BalancersStrategySettingsCosts4Ray>? costs { get; set; }
|
||||||
public TcpSettings4Ray? tcpSettings { get; set; }
|
}
|
||||||
|
|
||||||
public KcpSettings4Ray? kcpSettings { get; set; }
|
public class BalancersStrategySettingsCosts4Ray
|
||||||
|
{
|
||||||
public WsSettings4Ray? wsSettings { get; set; }
|
public bool? regexp { get; set; }
|
||||||
|
public string? match { get; set; }
|
||||||
public HttpupgradeSettings4Ray? httpupgradeSettings { get; set; }
|
public float? value { get; set; }
|
||||||
|
}
|
||||||
public XhttpSettings4Ray? xhttpSettings { get; set; }
|
|
||||||
|
public class Observatory4Ray
|
||||||
public HttpSettings4Ray? httpSettings { get; set; }
|
{
|
||||||
|
public List<string>? subjectSelector { get; set; }
|
||||||
public QuicSettings4Ray? quicSettings { get; set; }
|
public string? probeUrl { get; set; }
|
||||||
|
public string? probeInterval { get; set; }
|
||||||
public TlsSettings4Ray? realitySettings { get; set; }
|
public bool? enableConcurrency { get; set; }
|
||||||
|
}
|
||||||
public GrpcSettings4Ray? grpcSettings { get; set; }
|
|
||||||
|
public class BurstObservatory4Ray
|
||||||
public Sockopt4Ray? sockopt { get; set; }
|
{
|
||||||
}
|
public List<string>? subjectSelector { get; set; }
|
||||||
|
public BurstObservatoryPingConfig4Ray? pingConfig { get; set; }
|
||||||
public class TlsSettings4Ray
|
}
|
||||||
{
|
|
||||||
public bool? allowInsecure { get; set; }
|
public class BurstObservatoryPingConfig4Ray
|
||||||
|
{
|
||||||
public string? serverName { get; set; }
|
public string? destination { get; set; }
|
||||||
|
public string? connectivity { get; set; }
|
||||||
public List<string>? alpn { get; set; }
|
public string? interval { get; set; }
|
||||||
|
public int? sampling { get; set; }
|
||||||
public string? fingerprint { get; set; }
|
public string? timeout { get; set; }
|
||||||
|
}
|
||||||
public bool? show { get; set; }
|
|
||||||
public string? publicKey { get; set; }
|
public class StreamSettings4Ray
|
||||||
public string? shortId { get; set; }
|
{
|
||||||
public string? spiderX { get; set; }
|
public string network { get; set; }
|
||||||
}
|
|
||||||
|
public string security { get; set; }
|
||||||
public class TcpSettings4Ray
|
|
||||||
{
|
public TlsSettings4Ray? tlsSettings { get; set; }
|
||||||
public Header4Ray header { get; set; }
|
|
||||||
}
|
public TcpSettings4Ray? tcpSettings { get; set; }
|
||||||
|
|
||||||
public class Header4Ray
|
public KcpSettings4Ray? kcpSettings { get; set; }
|
||||||
{
|
|
||||||
public string type { get; set; }
|
public WsSettings4Ray? wsSettings { get; set; }
|
||||||
|
|
||||||
public object request { get; set; }
|
public HttpupgradeSettings4Ray? httpupgradeSettings { get; set; }
|
||||||
|
|
||||||
public object response { get; set; }
|
public XhttpSettings4Ray? xhttpSettings { get; set; }
|
||||||
|
|
||||||
public string? domain { get; set; }
|
public HttpSettings4Ray? httpSettings { get; set; }
|
||||||
}
|
|
||||||
|
public QuicSettings4Ray? quicSettings { get; set; }
|
||||||
public class KcpSettings4Ray
|
|
||||||
{
|
public TlsSettings4Ray? realitySettings { get; set; }
|
||||||
public int mtu { get; set; }
|
|
||||||
|
public GrpcSettings4Ray? grpcSettings { get; set; }
|
||||||
public int tti { get; set; }
|
|
||||||
|
public Sockopt4Ray? sockopt { get; set; }
|
||||||
public int uplinkCapacity { get; set; }
|
}
|
||||||
|
|
||||||
public int downlinkCapacity { get; set; }
|
public class TlsSettings4Ray
|
||||||
|
{
|
||||||
public bool congestion { get; set; }
|
public bool? allowInsecure { get; set; }
|
||||||
|
|
||||||
public int readBufferSize { get; set; }
|
public string? serverName { get; set; }
|
||||||
|
|
||||||
public int writeBufferSize { get; set; }
|
public List<string>? alpn { get; set; }
|
||||||
|
|
||||||
public Header4Ray header { get; set; }
|
public string? fingerprint { get; set; }
|
||||||
|
|
||||||
public string seed { get; set; }
|
public bool? show { get; set; }
|
||||||
}
|
public string? publicKey { get; set; }
|
||||||
|
public string? shortId { get; set; }
|
||||||
public class WsSettings4Ray
|
public string? spiderX { get; set; }
|
||||||
{
|
}
|
||||||
public string? path { get; set; }
|
|
||||||
public string? host { get; set; }
|
public class TcpSettings4Ray
|
||||||
|
{
|
||||||
public Headers4Ray headers { get; set; }
|
public Header4Ray header { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public class Headers4Ray
|
public class Header4Ray
|
||||||
{
|
{
|
||||||
public string Host { get; set; }
|
public string type { get; set; }
|
||||||
|
|
||||||
[JsonPropertyName("User-Agent")]
|
public object request { get; set; }
|
||||||
public string UserAgent { get; set; }
|
|
||||||
}
|
public object response { get; set; }
|
||||||
|
|
||||||
public class HttpupgradeSettings4Ray
|
public string? domain { get; set; }
|
||||||
{
|
}
|
||||||
public string? path { get; set; }
|
|
||||||
|
public class KcpSettings4Ray
|
||||||
public string? host { get; set; }
|
{
|
||||||
}
|
public int mtu { get; set; }
|
||||||
|
|
||||||
public class XhttpSettings4Ray
|
public int tti { get; set; }
|
||||||
{
|
|
||||||
public string? path { get; set; }
|
public int uplinkCapacity { get; set; }
|
||||||
public string? host { get; set; }
|
|
||||||
public string? mode { get; set; }
|
public int downlinkCapacity { get; set; }
|
||||||
public object? extra { get; set; }
|
|
||||||
}
|
public bool congestion { get; set; }
|
||||||
|
|
||||||
public class HttpSettings4Ray
|
public int readBufferSize { get; set; }
|
||||||
{
|
|
||||||
public string? path { get; set; }
|
public int writeBufferSize { get; set; }
|
||||||
|
|
||||||
public List<string>? host { get; set; }
|
public Header4Ray header { get; set; }
|
||||||
}
|
|
||||||
|
public string seed { get; set; }
|
||||||
public class QuicSettings4Ray
|
}
|
||||||
{
|
|
||||||
public string security { get; set; }
|
public class WsSettings4Ray
|
||||||
|
{
|
||||||
public string key { get; set; }
|
public string? path { get; set; }
|
||||||
|
public string? host { get; set; }
|
||||||
public Header4Ray header { get; set; }
|
|
||||||
}
|
public Headers4Ray headers { get; set; }
|
||||||
|
}
|
||||||
public class GrpcSettings4Ray
|
|
||||||
{
|
public class Headers4Ray
|
||||||
public string? authority { get; set; }
|
{
|
||||||
public string? serviceName { get; set; }
|
public string Host { get; set; }
|
||||||
public bool multiMode { get; set; }
|
|
||||||
public int? idle_timeout { get; set; }
|
[JsonPropertyName("User-Agent")]
|
||||||
public int? health_check_timeout { get; set; }
|
public string UserAgent { get; set; }
|
||||||
public bool? permit_without_stream { get; set; }
|
}
|
||||||
public int? initial_windows_size { get; set; }
|
|
||||||
}
|
public class HttpupgradeSettings4Ray
|
||||||
|
{
|
||||||
public class AccountsItem4Ray
|
public string? path { get; set; }
|
||||||
{
|
|
||||||
public string user { get; set; }
|
public string? host { get; set; }
|
||||||
|
}
|
||||||
public string pass { get; set; }
|
|
||||||
}
|
public class XhttpSettings4Ray
|
||||||
|
{
|
||||||
public class Sockopt4Ray
|
public string? path { get; set; }
|
||||||
{
|
public string? host { get; set; }
|
||||||
public string? dialerProxy { get; set; }
|
public string? mode { get; set; }
|
||||||
}
|
public object? extra { get; set; }
|
||||||
|
}
|
||||||
public class FragmentItem4Ray
|
|
||||||
{
|
public class HttpSettings4Ray
|
||||||
public string? packets { get; set; }
|
{
|
||||||
public string? length { get; set; }
|
public string? path { get; set; }
|
||||||
public string? interval { get; set; }
|
|
||||||
}
|
public List<string>? host { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class QuicSettings4Ray
|
||||||
|
{
|
||||||
|
public string security { get; set; }
|
||||||
|
|
||||||
|
public string key { get; set; }
|
||||||
|
|
||||||
|
public Header4Ray header { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class GrpcSettings4Ray
|
||||||
|
{
|
||||||
|
public string? authority { get; set; }
|
||||||
|
public string? serviceName { get; set; }
|
||||||
|
public bool multiMode { get; set; }
|
||||||
|
public int? idle_timeout { get; set; }
|
||||||
|
public int? health_check_timeout { get; set; }
|
||||||
|
public bool? permit_without_stream { get; set; }
|
||||||
|
public int? initial_windows_size { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class AccountsItem4Ray
|
||||||
|
{
|
||||||
|
public string user { get; set; }
|
||||||
|
|
||||||
|
public string pass { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class Sockopt4Ray
|
||||||
|
{
|
||||||
|
public string? dialerProxy { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class FragmentItem4Ray
|
||||||
|
{
|
||||||
|
public string? packets { get; set; }
|
||||||
|
public string? length { get; set; }
|
||||||
|
public string? interval { get; set; }
|
||||||
}
|
}
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue