Compare commits
198 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ce22f34cd6 | ||
|
|
4c49e52e26 | ||
|
|
47318b5d70 | ||
|
|
d12297909c | ||
|
|
5fb4edae2d | ||
|
|
c4b490e46d | ||
|
|
45febe3fff | ||
|
|
689a81a985 | ||
|
|
28620b385a | ||
|
|
be13446e69 | ||
|
|
ee57d5b8e6 | ||
|
|
4eda3dd8fa | ||
|
|
911dc7f90e | ||
|
|
18005b96e8 | ||
|
|
a3e45d206e | ||
|
|
0accf262dc | ||
|
|
e0eb73bb0a | ||
|
|
258e822c13 | ||
|
|
4f05b93d63 | ||
|
|
bb661d4f50 | ||
|
|
201cfaa922 | ||
|
|
c339aa349c | ||
|
|
046421f345 | ||
|
|
3a2c9e7aaa | ||
|
|
0bb6e6bd86 | ||
|
|
693e8ab157 | ||
|
|
033c16c992 | ||
|
|
6ec61433fb | ||
|
|
072f773245 | ||
|
|
0086f65a96 | ||
|
|
281f14f47e | ||
|
|
9fd20ff001 | ||
|
|
7df90a6034 | ||
|
|
019869ec28 | ||
|
|
b7f4fd7469 | ||
|
|
1273d2aee1 | ||
|
|
88990b4828 | ||
|
|
2f02c2970c | ||
|
|
ade789c6d4 | ||
|
|
9738f90970 | ||
|
|
6ed0741339 | ||
|
|
e6b1e22245 | ||
|
|
6b922be0c6 | ||
|
|
6e35a260e8 | ||
|
|
1106fd8cf1 | ||
|
|
fb92b90d5c | ||
|
|
5effbee50b | ||
|
|
9bc50a9f34 | ||
|
|
2a5a339c27 | ||
|
|
78d182fff3 | ||
|
|
0efb0b5e3e | ||
|
|
a2e8755730 | ||
|
|
06ddedbc4c | ||
|
|
fa148cdf42 | ||
|
|
c1f71dee15 | ||
|
|
871cb81323 | ||
|
|
34f5c0f910 | ||
|
|
3fafc6de93 | ||
|
|
b013213745 | ||
|
|
40ea454a7c | ||
|
|
f0bac4b4c8 | ||
|
|
ffb38129e2 | ||
|
|
3c550c094a | ||
|
|
2d143687b8 | ||
|
|
1e7284f141 | ||
|
|
50bdf0927c | ||
|
|
10a60b26fa | ||
|
|
b3c2084b76 | ||
|
|
3bf2dc711d | ||
|
|
5a7836115e | ||
|
|
0da9cb45bd | ||
|
|
28aa954f8c | ||
|
|
4fc71fb77e | ||
|
|
5ea6b1e08a | ||
|
|
0cdfc97460 | ||
|
|
3dd54312e7 | ||
|
|
a866017b4c | ||
|
|
394b657fc9 | ||
|
|
50449df08d | ||
|
|
fe3836be14 | ||
|
|
055cd62dd8 | ||
|
|
4d1f7fa60c | ||
|
|
5c0fba8744 | ||
|
|
b74ddc0b43 | ||
|
|
d004c6860e | ||
|
|
fc3ba6c030 | ||
|
|
9c4dc185be | ||
|
|
2edbbc523a | ||
|
|
a5122b656d | ||
|
|
74f980aab1 | ||
|
|
35e5475255 | ||
|
|
fb649c04cf | ||
|
|
4ce7ca3c6f | ||
|
|
eebb6735aa | ||
|
|
e96c9abd69 | ||
|
|
fd7cf164ff | ||
|
|
24afe8bde4 | ||
|
|
9540669f56 | ||
|
|
c6caf29b5b | ||
|
|
2698137dea | ||
|
|
bdae08b13b | ||
|
|
019c69ecff | ||
|
|
6b99b7eec5 | ||
|
|
4eb443e547 | ||
|
|
e530789739 | ||
|
|
7618f9f7d4 | ||
|
|
d7bde77977 | ||
|
|
a0286ff810 | ||
|
|
b172b03927 | ||
|
|
a556bf9487 | ||
|
|
4f5362fdc4 | ||
|
|
176a91e7c5 | ||
|
|
3c45ef624a | ||
|
|
fea7c9fbd7 | ||
|
|
aa6b6e3849 | ||
|
|
f5956e7bf0 | ||
|
|
b2669103dc | ||
|
|
53e19ecb1d | ||
|
|
3e74bb65bd | ||
|
|
f60575b77c | ||
|
|
7a839063d0 | ||
|
|
4ccc7aa92d | ||
|
|
d5c6a42a9a | ||
|
|
3bdef4d6d8 | ||
|
|
f40eb724d7 | ||
|
|
4d84eede56 | ||
|
|
53a2fbd0ff | ||
|
|
409fe5290e | ||
|
|
75d86cf883 | ||
|
|
b33f536dbd | ||
|
|
1f77c56eaf | ||
|
|
fe895b1b27 | ||
|
|
20bb263b06 | ||
|
|
3ecbd3bc10 | ||
|
|
fe81b51dcb | ||
|
|
90ba80436d | ||
|
|
2bb5f6afc4 | ||
|
|
3971318ffb | ||
|
|
5fbeb4b0fb | ||
|
|
1b2b838bc0 | ||
|
|
8e28cc01b8 | ||
|
|
77a59e9107 | ||
|
|
1411643192 | ||
|
|
fde2a768cf | ||
|
|
b008a58cf8 | ||
|
|
8e02394ff4 | ||
|
|
60a75d9a31 | ||
|
|
24566901fb | ||
|
|
cc428618e5 | ||
|
|
4d330cedac | ||
|
|
2503583498 | ||
|
|
1b11916e1e | ||
|
|
3dfd557265 | ||
|
|
cd6bea28b6 | ||
|
|
054f0f2bc7 | ||
|
|
97347674e7 | ||
|
|
36d15852aa | ||
|
|
4813610492 | ||
|
|
243dbab06a | ||
|
|
073eaa9a26 | ||
|
|
cb1f936d05 | ||
|
|
a7f3a7b1a7 | ||
|
|
71eb5f0813 | ||
|
|
b4f50258a7 | ||
|
|
346a9c5fcc | ||
|
|
61635db5b5 | ||
|
|
4c0a59a715 | ||
|
|
aa829a66ea | ||
|
|
885f193a00 | ||
|
|
0a9bbf526d | ||
|
|
ff6716b39d | ||
|
|
8505f2db96 | ||
|
|
233d605256 | ||
|
|
c4e01d20a0 | ||
|
|
07156cb55c | ||
|
|
8361b4e4a0 | ||
|
|
bb90671979 | ||
|
|
beddc71ed8 | ||
|
|
d5f1cc99ac | ||
|
|
d03a86292e | ||
|
|
c061a24948 | ||
|
|
9c7446f820 | ||
|
|
8be1730719 | ||
|
|
7ceaf5c071 | ||
|
|
7901a59aa4 | ||
|
|
8343a1002f | ||
|
|
c83dce3cc0 | ||
|
|
14afeab2bb | ||
|
|
c22b57927c | ||
|
|
81b84d235c | ||
|
|
488e8aab00 | ||
|
|
fc43a9a726 | ||
|
|
31947fdcb3 | ||
|
|
34c7963d28 | ||
|
|
d91b0afb9a | ||
|
|
82eb3fd6bd | ||
|
|
3d3d3f83df | ||
|
|
6879c75bc8 |
10
.github/dependabot.yml
vendored
Normal file
10
.github/dependabot.yml
vendored
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
# Set update schedule for GitHub Actions
|
||||||
|
|
||||||
|
version: 2
|
||||||
|
updates:
|
||||||
|
|
||||||
|
- package-ecosystem: "github-actions"
|
||||||
|
directory: "/"
|
||||||
|
schedule:
|
||||||
|
# Check for updates to GitHub Actions every daily
|
||||||
|
interval: "daily"
|
||||||
@@ -5,8 +5,8 @@
|
|||||||
<TargetFramework>net8.0</TargetFramework>
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
<ImplicitUsings>enable</ImplicitUsings>
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
<Nullable>enable</Nullable>
|
<Nullable>enable</Nullable>
|
||||||
<Copyright>Copyright © 2019-2024 (GPLv3)</Copyright>
|
<Copyright>Copyright © 2017-2024 (GPLv3)</Copyright>
|
||||||
<FileVersion>1.2.0.0</FileVersion>
|
<FileVersion>1.3.0</FileVersion>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
22
v2rayN/AmazTool/Program.cs
Normal file
22
v2rayN/AmazTool/Program.cs
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
namespace AmazTool
|
||||||
|
{
|
||||||
|
internal static class Program
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 应用程序的主入口点。
|
||||||
|
/// </summary>
|
||||||
|
[STAThread]
|
||||||
|
private static void Main(string[] args)
|
||||||
|
{
|
||||||
|
if (args.Length == 0)
|
||||||
|
{
|
||||||
|
Console.WriteLine("Please run it from the main application.(请从主应用运行)");
|
||||||
|
Thread.Sleep(5000);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var fileName = Uri.UnescapeDataString(string.Join(" ", args));
|
||||||
|
UpgradeApp.Upgrade(fileName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -2,43 +2,31 @@
|
|||||||
using System.IO.Compression;
|
using System.IO.Compression;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
|
||||||
namespace v2rayUpgrade
|
namespace AmazTool
|
||||||
{
|
{
|
||||||
internal static class Program
|
internal class UpgradeApp
|
||||||
{
|
{
|
||||||
private static readonly string defaultFilename = "v2rayN.zip_temp";
|
public static void Upgrade(string fileName)
|
||||||
private static string? fileName;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 应用程序的主入口点。
|
|
||||||
/// </summary>
|
|
||||||
[STAThread]
|
|
||||||
private static void Main(string[] args)
|
|
||||||
{
|
{
|
||||||
if (args.Length > 0)
|
|
||||||
{
|
|
||||||
fileName = Uri.UnescapeDataString(string.Join(" ", args));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
fileName = defaultFilename;
|
|
||||||
}
|
|
||||||
Console.WriteLine(fileName);
|
Console.WriteLine(fileName);
|
||||||
Console.WriteLine("In progress, please wait...(正在进行中,请等待)");
|
Console.WriteLine("In progress, please wait...(正在进行中,请等待)");
|
||||||
|
|
||||||
Thread.Sleep(10000);
|
Thread.Sleep(9000);
|
||||||
|
|
||||||
|
if (!File.Exists(fileName))
|
||||||
|
{
|
||||||
|
Console.WriteLine("Upgrade Failed, File Not Exist(升级失败,文件不存在).");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Console.WriteLine("Try to end the process(尝试结束进程).");
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
Process[] existing = Process.GetProcessesByName("v2rayN");
|
var existing = Process.GetProcessesByName(V2rayN);
|
||||||
foreach (Process p in existing)
|
foreach (var pp in existing)
|
||||||
{
|
{
|
||||||
var path = p.MainModule?.FileName ?? "";
|
pp?.Kill();
|
||||||
if (path.StartsWith(GetPath("v2rayN")))
|
pp?.WaitForExit(1000);
|
||||||
{
|
|
||||||
p.Kill();
|
|
||||||
p.WaitForExit(100);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
@@ -48,25 +36,13 @@ namespace v2rayUpgrade
|
|||||||
"Close it manually, or the upgrade may fail.(请手动关闭正在运行的v2rayN,否则可能升级失败。\n\n" + ex.StackTrace);
|
"Close it manually, or the upgrade may fail.(请手动关闭正在运行的v2rayN,否则可能升级失败。\n\n" + ex.StackTrace);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!File.Exists(fileName))
|
Console.WriteLine("Start extracting files(开始解压文件).");
|
||||||
{
|
|
||||||
if (File.Exists(defaultFilename))
|
|
||||||
{
|
|
||||||
fileName = defaultFilename;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Console.WriteLine("Upgrade Failed, File Not Exist(升级失败,文件不存在).");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
StringBuilder sb = new();
|
StringBuilder sb = new();
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
string thisAppOldFile = $"{GetExePath()}.tmp";
|
string thisAppOldFile = $"{GetExePath()}.tmp";
|
||||||
File.Delete(thisAppOldFile);
|
File.Delete(thisAppOldFile);
|
||||||
string startKey = "v2rayN/";
|
string splitKey = "/";
|
||||||
|
|
||||||
using ZipArchive archive = ZipFile.OpenRead(fileName);
|
using ZipArchive archive = ZipFile.OpenRead(fileName);
|
||||||
foreach (ZipArchiveEntry entry in archive.Entries)
|
foreach (ZipArchiveEntry entry in archive.Entries)
|
||||||
@@ -77,11 +53,13 @@ namespace v2rayUpgrade
|
|||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
string fullName = entry.FullName;
|
|
||||||
if (fullName.StartsWith(startKey))
|
Console.WriteLine(entry.FullName);
|
||||||
{
|
|
||||||
fullName = fullName[startKey.Length..];
|
var lst = entry.FullName.Split(splitKey);
|
||||||
}
|
if (lst.Length == 1) continue;
|
||||||
|
string fullName = string.Join(splitKey, lst[1..lst.Length]);
|
||||||
|
|
||||||
if (string.Equals(GetExePath(), GetPath(fullName), StringComparison.OrdinalIgnoreCase))
|
if (string.Equals(GetExePath(), GetPath(fullName), StringComparison.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
File.Move(GetExePath(), thisAppOldFile);
|
File.Move(GetExePath(), thisAppOldFile);
|
||||||
@@ -90,6 +68,8 @@ namespace v2rayUpgrade
|
|||||||
string entryOutputPath = GetPath(fullName);
|
string entryOutputPath = GetPath(fullName);
|
||||||
Directory.CreateDirectory(Path.GetDirectoryName(entryOutputPath)!);
|
Directory.CreateDirectory(Path.GetDirectoryName(entryOutputPath)!);
|
||||||
entry.ExtractToFile(entryOutputPath, true);
|
entry.ExtractToFile(entryOutputPath, true);
|
||||||
|
|
||||||
|
Console.WriteLine(entryOutputPath);
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
@@ -100,29 +80,39 @@ namespace v2rayUpgrade
|
|||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Console.WriteLine("Upgrade Failed(升级失败)." + ex.StackTrace);
|
Console.WriteLine("Upgrade Failed(升级失败)." + ex.StackTrace);
|
||||||
return;
|
//return;
|
||||||
}
|
}
|
||||||
if (sb.Length > 0)
|
if (sb.Length > 0)
|
||||||
{
|
{
|
||||||
Console.WriteLine("Upgrade Failed,Hold ctrl + c to copy to clipboard.\n" +
|
Console.WriteLine("Upgrade Failed(升级失败)." + sb.ToString());
|
||||||
"(升级失败,按住ctrl+c可以复制到剪贴板)." + sb.ToString());
|
//return;
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Process.Start("v2rayN");
|
Console.WriteLine("Start v2rayN, please wait...(正在重启,请等待)");
|
||||||
|
Thread.Sleep(9000);
|
||||||
|
Process process = new()
|
||||||
|
{
|
||||||
|
StartInfo = new()
|
||||||
|
{
|
||||||
|
UseShellExecute = true,
|
||||||
|
FileName = V2rayN,
|
||||||
|
WorkingDirectory = StartupPath()
|
||||||
|
}
|
||||||
|
};
|
||||||
|
process.Start();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static string GetExePath()
|
private static string GetExePath()
|
||||||
{
|
{
|
||||||
return Environment.ProcessPath ?? string.Empty;
|
return Environment.ProcessPath ?? Process.GetCurrentProcess().MainModule?.FileName ?? string.Empty;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static string StartupPath()
|
private static string StartupPath()
|
||||||
{
|
{
|
||||||
return AppDomain.CurrentDomain.BaseDirectory;
|
return AppDomain.CurrentDomain.BaseDirectory;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static string GetPath(string fileName)
|
private static string GetPath(string fileName)
|
||||||
{
|
{
|
||||||
string startupPath = StartupPath();
|
string startupPath = StartupPath();
|
||||||
if (string.IsNullOrEmpty(fileName))
|
if (string.IsNullOrEmpty(fileName))
|
||||||
@@ -131,5 +121,7 @@ namespace v2rayUpgrade
|
|||||||
}
|
}
|
||||||
return Path.Combine(startupPath, fileName);
|
return Path.Combine(startupPath, fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static string V2rayN => "v2rayN";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,5 +1,4 @@
|
|||||||
using System;
|
using System.IO;
|
||||||
using System.IO;
|
|
||||||
using System.Net.Sockets;
|
using System.Net.Sockets;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
@@ -77,8 +76,9 @@ public class PacHandler
|
|||||||
stream.Flush();
|
stream.Flush();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch
|
||||||
{
|
{
|
||||||
|
// ignored
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, TaskCreationOptions.LongRunning);
|
}, TaskCreationOptions.LongRunning);
|
||||||
@@ -86,17 +86,16 @@ public class PacHandler
|
|||||||
|
|
||||||
public static void Stop()
|
public static void Stop()
|
||||||
{
|
{
|
||||||
if (_tcpListener != null)
|
if (_tcpListener == null) return;
|
||||||
|
try
|
||||||
{
|
{
|
||||||
try
|
_isRunning = false;
|
||||||
{
|
_tcpListener.Stop();
|
||||||
_isRunning = false;
|
_tcpListener = null;
|
||||||
_tcpListener.Stop();
|
}
|
||||||
_tcpListener = null;
|
catch
|
||||||
}
|
{
|
||||||
catch (Exception e)
|
// ignored
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -9,9 +9,9 @@
|
|||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Google.Protobuf" Version="3.28.0" />
|
<PackageReference Include="Google.Protobuf" Version="3.28.3" />
|
||||||
<PackageReference Include="Grpc.Net.Client" Version="2.65.0" />
|
<PackageReference Include="Grpc.Net.Client" Version="2.66.0" />
|
||||||
<PackageReference Include="Grpc.Tools" Version="2.66.0">
|
<PackageReference Include="Grpc.Tools" Version="2.67.0">
|
||||||
<PrivateAssets>all</PrivateAssets>
|
<PrivateAssets>all</PrivateAssets>
|
||||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
|
|||||||
@@ -6,6 +6,5 @@ namespace ServiceLib.Base
|
|||||||
{
|
{
|
||||||
protected static Config? _config;
|
protected static Config? _config;
|
||||||
protected Func<EViewAction, object?, Task<bool>>? _updateView;
|
protected Func<EViewAction, object?, Task<bool>>? _updateView;
|
||||||
protected NoticeHandler? _noticeHandler;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -18,7 +18,7 @@ namespace ServiceLib.Common
|
|||||||
Uri uri = new(url);
|
Uri uri = new(url);
|
||||||
//Authorization Header
|
//Authorization Header
|
||||||
var headers = new WebHeaderCollection();
|
var headers = new WebHeaderCollection();
|
||||||
if (!Utils.IsNullOrEmpty(uri.UserInfo))
|
if (Utils.IsNotEmpty(uri.UserInfo))
|
||||||
{
|
{
|
||||||
headers.Add(HttpRequestHeader.Authorization, "Basic " + Utils.Base64Encode(uri.UserInfo));
|
headers.Add(HttpRequestHeader.Authorization, "Basic " + Utils.Base64Encode(uri.UserInfo));
|
||||||
}
|
}
|
||||||
@@ -36,7 +36,7 @@ namespace ServiceLib.Common
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
using var downloader = new 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)
|
||||||
@@ -46,12 +46,12 @@ namespace ServiceLib.Common
|
|||||||
};
|
};
|
||||||
|
|
||||||
using var cts = new CancellationTokenSource();
|
using var cts = new CancellationTokenSource();
|
||||||
using var stream = await downloader.DownloadFileTaskAsync(address: url, cts.Token).WaitAsync(TimeSpan.FromSeconds(timeout), cts.Token);
|
await using var stream = await downloader.DownloadFileTaskAsync(address: url, cts.Token).WaitAsync(TimeSpan.FromSeconds(timeout), cts.Token);
|
||||||
using StreamReader reader = new(stream);
|
using StreamReader reader = new(stream);
|
||||||
|
|
||||||
downloadOpt = null;
|
downloadOpt = null;
|
||||||
|
|
||||||
return reader.ReadToEnd();
|
return await reader.ReadToEndAsync(cts.Token);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task DownloadDataAsync4Speed(IWebProxy webProxy, string url, IProgress<string> progress, int timeout)
|
public async Task DownloadDataAsync4Speed(IWebProxy webProxy, string url, IProgress<string> progress, int timeout)
|
||||||
@@ -72,11 +72,11 @@ namespace ServiceLib.Common
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
DateTime totalDatetime = DateTime.Now;
|
var totalDatetime = DateTime.Now;
|
||||||
int totalSecond = 0;
|
var totalSecond = 0;
|
||||||
var hasValue = false;
|
var hasValue = false;
|
||||||
double maxSpeed = 0;
|
double maxSpeed = 0;
|
||||||
using var downloader = new DownloadService(downloadOpt);
|
await using var downloader = new Downloader.DownloadService(downloadOpt);
|
||||||
//downloader.DownloadStarted += (sender, value) =>
|
//downloader.DownloadStarted += (sender, value) =>
|
||||||
//{
|
//{
|
||||||
// if (progress != null)
|
// if (progress != null)
|
||||||
@@ -86,7 +86,7 @@ namespace ServiceLib.Common
|
|||||||
//};
|
//};
|
||||||
downloader.DownloadProgressChanged += (sender, value) =>
|
downloader.DownloadProgressChanged += (sender, value) =>
|
||||||
{
|
{
|
||||||
TimeSpan ts = (DateTime.Now - totalDatetime);
|
var ts = (DateTime.Now - totalDatetime);
|
||||||
if (progress != null && ts.Seconds > totalSecond)
|
if (progress != null && ts.Seconds > totalSecond)
|
||||||
{
|
{
|
||||||
hasValue = true;
|
hasValue = true;
|
||||||
@@ -112,7 +112,7 @@ namespace ServiceLib.Common
|
|||||||
//progress.Report("......");
|
//progress.Report("......");
|
||||||
using var cts = new CancellationTokenSource();
|
using var cts = new CancellationTokenSource();
|
||||||
cts.CancelAfter(timeout * 1000);
|
cts.CancelAfter(timeout * 1000);
|
||||||
using var stream = await downloader.DownloadFileTaskAsync(address: url, cts.Token);
|
await using var stream = await downloader.DownloadFileTaskAsync(address: url, cts.Token);
|
||||||
|
|
||||||
downloadOpt = null;
|
downloadOpt = null;
|
||||||
}
|
}
|
||||||
@@ -145,7 +145,7 @@ namespace ServiceLib.Common
|
|||||||
|
|
||||||
var progressPercentage = 0;
|
var progressPercentage = 0;
|
||||||
var hasValue = false;
|
var hasValue = false;
|
||||||
using var downloader = new DownloadService(downloadOpt);
|
await using var downloader = new Downloader.DownloadService(downloadOpt);
|
||||||
downloader.DownloadStarted += (sender, value) =>
|
downloader.DownloadStarted += (sender, value) =>
|
||||||
{
|
{
|
||||||
progress?.Report(0);
|
progress?.Report(0);
|
||||||
@@ -176,7 +176,7 @@ namespace ServiceLib.Common
|
|||||||
};
|
};
|
||||||
|
|
||||||
using var cts = new CancellationTokenSource();
|
using var cts = new CancellationTokenSource();
|
||||||
await downloader.DownloadFileTaskAsync(url, fileName, cts.Token).WaitAsync(TimeSpan.FromSeconds(timeout), cts.Token);
|
await downloader.DownloadFileTaskAsync(url, fileName, cts.Token);
|
||||||
|
|
||||||
downloadOpt = null;
|
downloadOpt = null;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
using System.IO.Compression;
|
using System.Formats.Tar;
|
||||||
|
using System.IO.Compression;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
|
||||||
namespace ServiceLib.Common
|
namespace ServiceLib.Common
|
||||||
@@ -19,11 +20,11 @@ namespace ServiceLib.Common
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void UncompressedFile(string fileName, byte[] content)
|
public static void DecompressFile(string fileName, byte[] content)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
using FileStream fs = File.Create(fileName);
|
using var fs = File.Create(fileName);
|
||||||
using GZipStream input = new(new MemoryStream(content), CompressionMode.Decompress, false);
|
using GZipStream input = new(new MemoryStream(content), CompressionMode.Decompress, false);
|
||||||
input.CopyTo(fs);
|
input.CopyTo(fs);
|
||||||
}
|
}
|
||||||
@@ -33,13 +34,13 @@ namespace ServiceLib.Common
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void UncompressedFile(string fileName, string toPath, string? toName)
|
public static void DecompressFile(string fileName, string toPath, string? toName)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
FileInfo fileInfo = new(fileName);
|
FileInfo fileInfo = new(fileName);
|
||||||
using FileStream originalFileStream = fileInfo.OpenRead();
|
using var originalFileStream = fileInfo.OpenRead();
|
||||||
using FileStream decompressedFileStream = File.Create(toName != null ? Path.Combine(toPath, toName) : toPath);
|
using var decompressedFileStream = File.Create(toName != null ? Path.Combine(toPath, toName) : toPath);
|
||||||
using GZipStream decompressionStream = new(originalFileStream, CompressionMode.Decompress);
|
using GZipStream decompressionStream = new(originalFileStream, CompressionMode.Decompress);
|
||||||
decompressionStream.CopyTo(decompressedFileStream);
|
decompressionStream.CopyTo(decompressedFileStream);
|
||||||
}
|
}
|
||||||
@@ -49,12 +50,26 @@ namespace ServiceLib.Common
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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(ex.Message, ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static string NonExclusiveReadAllText(string path)
|
public static string NonExclusiveReadAllText(string path)
|
||||||
{
|
{
|
||||||
return NonExclusiveReadAllText(path, Encoding.Default);
|
return NonExclusiveReadAllText(path, Encoding.Default);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static string NonExclusiveReadAllText(string path, Encoding encoding)
|
private static string NonExclusiveReadAllText(string path, Encoding encoding)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@@ -73,8 +88,8 @@ namespace ServiceLib.Common
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
using ZipArchive archive = ZipFile.OpenRead(fileName);
|
using var archive = ZipFile.OpenRead(fileName);
|
||||||
foreach (ZipArchiveEntry entry in archive.Entries)
|
foreach (var entry in archive.Entries)
|
||||||
{
|
{
|
||||||
if (entry.Length == 0)
|
if (entry.Length == 0)
|
||||||
{
|
{
|
||||||
@@ -82,7 +97,7 @@ namespace ServiceLib.Common
|
|||||||
}
|
}
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (!Utils.IsNullOrEmpty(ignoredName) && entry.Name.Contains(ignoredName))
|
if (Utils.IsNotEmpty(ignoredName) && entry.Name.Contains(ignoredName))
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -102,11 +117,34 @@ namespace ServiceLib.Common
|
|||||||
return true;
|
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(ex.Message, ex);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static bool CreateFromDirectory(string sourceDirectoryName, string destinationArchiveFileName)
|
public static bool CreateFromDirectory(string sourceDirectoryName, string destinationArchiveFileName)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
ZipFile.CreateFromDirectory(sourceDirectoryName, destinationArchiveFileName);
|
if (File.Exists(destinationArchiveFileName))
|
||||||
|
{
|
||||||
|
File.Delete(destinationArchiveFileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
ZipFile.CreateFromDirectory(sourceDirectoryName, destinationArchiveFileName, CompressionLevel.SmallestSize, true);
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
@@ -115,6 +153,46 @@ namespace ServiceLib.Common
|
|||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void CopyDirectory(string sourceDir, string destinationDir, bool recursive, string? ignoredName)
|
||||||
|
{
|
||||||
|
// 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 (Utils.IsNotEmpty(ignoredName) && file.Name.Contains(ignoredName))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (file.Extension == file.Name)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
var targetFilePath = Path.Combine(destinationDir, file.Name);
|
||||||
|
file.CopyTo(targetFilePath, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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, ignoredName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
using System.Net.Http.Headers;
|
using System.Net.Http.Headers;
|
||||||
using System.Net.Mime;
|
using System.Net.Mime;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
|
||||||
@@ -22,12 +22,12 @@ namespace ServiceLib.Common
|
|||||||
|
|
||||||
public async Task<string?> TryGetAsync(string url)
|
public async Task<string?> TryGetAsync(string url)
|
||||||
{
|
{
|
||||||
if (string.IsNullOrEmpty(url))
|
if (Utils.IsNullOrEmpty(url))
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
HttpResponseMessage response = await httpClient.GetAsync(url);
|
var response = await httpClient.GetAsync(url);
|
||||||
return await response.Content.ReadAsStringAsync();
|
return await response.Content.ReadAsStringAsync();
|
||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
@@ -84,8 +84,8 @@ namespace ServiceLib.Common
|
|||||||
var total = response.Content.Headers.ContentLength ?? -1L;
|
var total = response.Content.Headers.ContentLength ?? -1L;
|
||||||
var canReportProgress = total != -1 && progress != null;
|
var canReportProgress = total != -1 && progress != null;
|
||||||
|
|
||||||
using var stream = await response.Content.ReadAsStreamAsync(token);
|
await using var stream = await response.Content.ReadAsStreamAsync(token);
|
||||||
using var file = File.Create(fileName);
|
await using var file = File.Create(fileName);
|
||||||
var totalRead = 0L;
|
var totalRead = 0L;
|
||||||
var buffer = new byte[1024 * 1024];
|
var buffer = new byte[1024 * 1024];
|
||||||
var progressPercentage = 0;
|
var progressPercentage = 0;
|
||||||
@@ -98,7 +98,7 @@ namespace ServiceLib.Common
|
|||||||
totalRead += read;
|
totalRead += read;
|
||||||
|
|
||||||
if (read == 0) break;
|
if (read == 0) break;
|
||||||
file.Write(buffer, 0, read);
|
await file.WriteAsync(buffer.AsMemory(0, read), token);
|
||||||
|
|
||||||
if (canReportProgress)
|
if (canReportProgress)
|
||||||
{
|
{
|
||||||
@@ -133,13 +133,13 @@ namespace ServiceLib.Common
|
|||||||
//var total = response.Content.Headers.ContentLength.HasValue ? response.Content.Headers.ContentLength.Value : -1L;
|
//var total = response.Content.Headers.ContentLength.HasValue ? response.Content.Headers.ContentLength.Value : -1L;
|
||||||
//var canReportProgress = total != -1 && progress != null;
|
//var canReportProgress = total != -1 && progress != null;
|
||||||
|
|
||||||
using var stream = await response.Content.ReadAsStreamAsync(token);
|
await using var stream = await response.Content.ReadAsStreamAsync(token);
|
||||||
var totalRead = 0L;
|
var totalRead = 0L;
|
||||||
var buffer = new byte[1024 * 64];
|
var buffer = new byte[1024 * 64];
|
||||||
var isMoreToRead = true;
|
var isMoreToRead = true;
|
||||||
string progressSpeed = string.Empty;
|
var progressSpeed = string.Empty;
|
||||||
DateTime totalDatetime = DateTime.Now;
|
var totalDatetime = DateTime.Now;
|
||||||
int totalSecond = 0;
|
var totalSecond = 0;
|
||||||
|
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
@@ -168,7 +168,7 @@ namespace ServiceLib.Common
|
|||||||
|
|
||||||
totalRead += read;
|
totalRead += read;
|
||||||
|
|
||||||
TimeSpan ts = (DateTime.Now - totalDatetime);
|
var ts = (DateTime.Now - totalDatetime);
|
||||||
if (progress != null && ts.Seconds > totalSecond)
|
if (progress != null && ts.Seconds > totalSecond)
|
||||||
{
|
{
|
||||||
totalSecond = ts.Seconds;
|
totalSecond = ts.Seconds;
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ namespace ServiceLib.Common
|
|||||||
* 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
|
||||||
*/
|
*/
|
||||||
|
|
||||||
public class Job : IDisposable
|
public sealed class Job : IDisposable
|
||||||
{
|
{
|
||||||
private IntPtr handle = IntPtr.Zero;
|
private IntPtr handle = IntPtr.Zero;
|
||||||
|
|
||||||
@@ -73,7 +73,7 @@ namespace ServiceLib.Common
|
|||||||
GC.SuppressFinalize(this);
|
GC.SuppressFinalize(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected virtual void Dispose(bool disposing)
|
private void Dispose(bool disposing)
|
||||||
{
|
{
|
||||||
if (disposed) return;
|
if (disposed) return;
|
||||||
disposed = true;
|
disposed = true;
|
||||||
|
|||||||
@@ -31,7 +31,11 @@ namespace ServiceLib.Common
|
|||||||
{
|
{
|
||||||
return default;
|
return default;
|
||||||
}
|
}
|
||||||
return JsonSerializer.Deserialize<T>(strJson);
|
var options = new JsonSerializerOptions
|
||||||
|
{
|
||||||
|
PropertyNameCaseInsensitive = true
|
||||||
|
};
|
||||||
|
return JsonSerializer.Deserialize<T>(strJson, options);
|
||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
{
|
{
|
||||||
@@ -69,7 +73,7 @@ namespace ServiceLib.Common
|
|||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public static string Serialize(object? obj, bool indented = true)
|
public static string Serialize(object? obj, bool indented = true)
|
||||||
{
|
{
|
||||||
string result = string.Empty;
|
var result = string.Empty;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (obj == null)
|
if (obj == null)
|
||||||
@@ -112,7 +116,7 @@ namespace ServiceLib.Common
|
|||||||
}
|
}
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
using FileStream file = File.Create(filePath);
|
using var file = File.Create(filePath);
|
||||||
|
|
||||||
var options = new JsonSerializerOptions
|
var options = new JsonSerializerOptions
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -37,40 +37,41 @@ namespace ServiceLib.Common
|
|||||||
foreach (var filePath in files)
|
foreach (var filePath in files)
|
||||||
{
|
{
|
||||||
var file = new FileInfo(filePath);
|
var file = new FileInfo(filePath);
|
||||||
if (file.CreationTime < now)
|
if (file.CreationTime >= now) continue;
|
||||||
|
try
|
||||||
{
|
{
|
||||||
try
|
file.Delete();
|
||||||
{
|
}
|
||||||
file.Delete();
|
catch
|
||||||
}
|
{
|
||||||
catch { }
|
// ignored
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch { }
|
catch
|
||||||
|
{
|
||||||
|
// ignored
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void SaveLog(string strContent)
|
public static void SaveLog(string strContent)
|
||||||
{
|
{
|
||||||
if (LogManager.IsLoggingEnabled())
|
if (!LogManager.IsLoggingEnabled()) return;
|
||||||
{
|
|
||||||
var logger = LogManager.GetLogger("Log1");
|
LogManager.GetLogger("Log1").Info(strContent);
|
||||||
logger.Info(strContent);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void SaveLog(string strTitle, Exception ex)
|
public static void SaveLog(string strTitle, Exception ex)
|
||||||
{
|
{
|
||||||
if (LogManager.IsLoggingEnabled())
|
if (!LogManager.IsLoggingEnabled()) return;
|
||||||
|
|
||||||
|
var logger = LogManager.GetLogger("Log2");
|
||||||
|
logger.Debug($"{strTitle},{ex.Message}");
|
||||||
|
logger.Debug(ex.StackTrace);
|
||||||
|
if (ex?.InnerException != null)
|
||||||
{
|
{
|
||||||
var logger = LogManager.GetLogger("Log2");
|
logger.Error(ex.InnerException);
|
||||||
logger.Debug($"{strTitle},{ex.Message}");
|
|
||||||
logger.Debug(ex.StackTrace);
|
|
||||||
if (ex?.InnerException != null)
|
|
||||||
{
|
|
||||||
logger.Error(ex.InnerException);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
using QRCoder;
|
using QRCoder;
|
||||||
|
using SkiaSharp;
|
||||||
|
using ZXing.SkiaSharp;
|
||||||
|
|
||||||
namespace ServiceLib.Common
|
namespace ServiceLib.Common
|
||||||
{
|
{
|
||||||
@@ -7,9 +9,82 @@ namespace ServiceLib.Common
|
|||||||
public static byte[]? GenQRCode(string? url)
|
public static byte[]? GenQRCode(string? url)
|
||||||
{
|
{
|
||||||
using QRCodeGenerator qrGenerator = new();
|
using QRCodeGenerator qrGenerator = new();
|
||||||
using QRCodeData qrCodeData = qrGenerator.CreateQrCode(url ?? string.Empty, QRCodeGenerator.ECCLevel.Q);
|
using var qrCodeData = qrGenerator.CreateQrCode(url ?? string.Empty, QRCodeGenerator.ECCLevel.Q);
|
||||||
using PngByteQRCode qrCode = new(qrCodeData);
|
using PngByteQRCode qrCode = new(qrCodeData);
|
||||||
return qrCode.GetGraphic(20);
|
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 && Utils.IsNotEmpty(result.Text))
|
||||||
|
{
|
||||||
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -17,7 +17,7 @@ namespace ServiceLib.Common
|
|||||||
|
|
||||||
private static IOrderedQueryable<T> _OrderBy<T>(IQueryable<T> query, string propertyName, bool isDesc)
|
private static IOrderedQueryable<T> _OrderBy<T>(IQueryable<T> query, string propertyName, bool isDesc)
|
||||||
{
|
{
|
||||||
string methodname = (isDesc) ? "OrderByDescendingInternal" : "OrderByInternal";
|
var methodname = (isDesc) ? "OrderByDescendingInternal" : "OrderByInternal";
|
||||||
|
|
||||||
var memberProp = typeof(T).GetProperty(propertyName);
|
var memberProp = typeof(T).GetProperty(propertyName);
|
||||||
|
|
||||||
|
|||||||
@@ -15,19 +15,27 @@
|
|||||||
this.version = $"{major}.{minor}.{patch}";
|
this.version = $"{major}.{minor}.{patch}";
|
||||||
}
|
}
|
||||||
|
|
||||||
public SemanticVersion(string version)
|
public SemanticVersion(string? version)
|
||||||
{
|
{
|
||||||
this.version = version.RemovePrefix('v');
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
string[] parts = this.version.Split('.');
|
if (version.IsNullOrEmpty())
|
||||||
|
{
|
||||||
|
this.major = 0;
|
||||||
|
this.minor = 0;
|
||||||
|
this.patch = 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.version = version.RemovePrefix('v');
|
||||||
|
|
||||||
|
var parts = this.version.Split('.');
|
||||||
if (parts.Length == 2)
|
if (parts.Length == 2)
|
||||||
{
|
{
|
||||||
this.major = int.Parse(parts[0]);
|
this.major = int.Parse(parts[0]);
|
||||||
this.minor = int.Parse(parts[1]);
|
this.minor = int.Parse(parts[1]);
|
||||||
this.patch = 0;
|
this.patch = 0;
|
||||||
}
|
}
|
||||||
else if (parts.Length == 3)
|
else if (parts.Length is 3 or 4)
|
||||||
{
|
{
|
||||||
this.major = int.Parse(parts[0]);
|
this.major = int.Parse(parts[0]);
|
||||||
this.minor = int.Parse(parts[1]);
|
this.minor = int.Parse(parts[1]);
|
||||||
@@ -43,7 +51,6 @@
|
|||||||
this.major = 0;
|
this.major = 0;
|
||||||
this.minor = 0;
|
this.minor = 0;
|
||||||
this.patch = 0;
|
this.patch = 0;
|
||||||
//this.version = "0.0.0";
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -10,8 +10,7 @@ namespace ServiceLib.Common
|
|||||||
private string _connstr;
|
private string _connstr;
|
||||||
private SQLiteConnection _db;
|
private SQLiteConnection _db;
|
||||||
private SQLiteAsyncConnection _dbAsync;
|
private SQLiteAsyncConnection _dbAsync;
|
||||||
private static readonly object objLock = new();
|
private readonly string _configDB = "guiNDB.db";
|
||||||
public readonly string _configDB = "guiNDB.db";
|
|
||||||
|
|
||||||
public SQLiteHelper()
|
public SQLiteHelper()
|
||||||
{
|
{
|
||||||
@@ -25,17 +24,9 @@ namespace ServiceLib.Common
|
|||||||
return _db.CreateTable<T>();
|
return _db.CreateTable<T>();
|
||||||
}
|
}
|
||||||
|
|
||||||
public int Insert(object model)
|
public async Task<int> InsertAllAsync(IEnumerable models)
|
||||||
{
|
{
|
||||||
return _db.Insert(model);
|
return await _dbAsync.InsertAllAsync(models);
|
||||||
}
|
|
||||||
|
|
||||||
public int InsertAll(IEnumerable models)
|
|
||||||
{
|
|
||||||
lock (objLock)
|
|
||||||
{
|
|
||||||
return _db.InsertAll(models);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<int> InsertAsync(object model)
|
public async Task<int> InsertAsync(object model)
|
||||||
@@ -43,46 +34,19 @@ namespace ServiceLib.Common
|
|||||||
return await _dbAsync.InsertAsync(model);
|
return await _dbAsync.InsertAsync(model);
|
||||||
}
|
}
|
||||||
|
|
||||||
public int Replace(object model)
|
|
||||||
{
|
|
||||||
lock (objLock)
|
|
||||||
{
|
|
||||||
return _db.InsertOrReplace(model);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task<int> ReplaceAsync(object model)
|
public async Task<int> ReplaceAsync(object model)
|
||||||
{
|
{
|
||||||
return await _dbAsync.InsertOrReplaceAsync(model);
|
return await _dbAsync.InsertOrReplaceAsync(model);
|
||||||
}
|
}
|
||||||
|
|
||||||
public int Update(object model)
|
|
||||||
{
|
|
||||||
lock (objLock)
|
|
||||||
{
|
|
||||||
return _db.Update(model);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task<int> UpdateAsync(object model)
|
public async Task<int> UpdateAsync(object model)
|
||||||
{
|
{
|
||||||
return await _dbAsync.UpdateAsync(model);
|
return await _dbAsync.UpdateAsync(model);
|
||||||
}
|
}
|
||||||
|
|
||||||
public int UpdateAll(IEnumerable models)
|
public async Task<int> UpdateAllAsync(IEnumerable models)
|
||||||
{
|
{
|
||||||
lock (objLock)
|
return await _dbAsync.UpdateAllAsync(models);
|
||||||
{
|
|
||||||
return _db.UpdateAll(models);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public int Delete(object model)
|
|
||||||
{
|
|
||||||
lock (objLock)
|
|
||||||
{
|
|
||||||
return _db.Delete(model);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<int> DeleteAsync(object model)
|
public async Task<int> DeleteAsync(object model)
|
||||||
@@ -90,19 +54,9 @@ namespace ServiceLib.Common
|
|||||||
return await _dbAsync.DeleteAsync(model);
|
return await _dbAsync.DeleteAsync(model);
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<T> Query<T>(string sql) where T : new()
|
public async Task<int> DeleteAllAsync<T>()
|
||||||
{
|
{
|
||||||
return _db.Query<T>(sql);
|
return await _dbAsync.DeleteAllAsync<T>();
|
||||||
}
|
|
||||||
|
|
||||||
public async Task<List<T>> QueryAsync<T>(string sql) where T : new()
|
|
||||||
{
|
|
||||||
return await _dbAsync.QueryAsync<T>(sql);
|
|
||||||
}
|
|
||||||
|
|
||||||
public int Execute(string sql)
|
|
||||||
{
|
|
||||||
return _db.Execute(sql);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<int> ExecuteAsync(string sql)
|
public async Task<int> ExecuteAsync(string sql)
|
||||||
@@ -110,9 +64,9 @@ namespace ServiceLib.Common
|
|||||||
return await _dbAsync.ExecuteAsync(sql);
|
return await _dbAsync.ExecuteAsync(sql);
|
||||||
}
|
}
|
||||||
|
|
||||||
public TableQuery<T> Table<T>() where T : new()
|
public async Task<List<T>> QueryAsync<T>(string sql) where T : new()
|
||||||
{
|
{
|
||||||
return _db.Table<T>();
|
return await _dbAsync.QueryAsync<T>(sql);
|
||||||
}
|
}
|
||||||
|
|
||||||
public AsyncTableQuery<T> TableAsync<T>() where T : new()
|
public AsyncTableQuery<T> TableAsync<T>() where T : new()
|
||||||
|
|||||||
@@ -14,27 +14,25 @@ namespace ServiceLib.Common
|
|||||||
return string.IsNullOrWhiteSpace(value);
|
return string.IsNullOrWhiteSpace(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static bool IsNotEmpty([NotNullWhen(false)] this string? 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()) return false;
|
if (s.IsNullOrEmpty()) return false;
|
||||||
return chars.Contains(s[0]);
|
return chars.Contains(s[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static bool IsWhiteSpace(this string value)
|
private static bool IsWhiteSpace(this string value)
|
||||||
{
|
{
|
||||||
foreach (char c in value)
|
return value.All(char.IsWhiteSpace);
|
||||||
{
|
|
||||||
if (char.IsWhiteSpace(c)) continue;
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static IEnumerable<string> NonWhiteSpaceLines(this TextReader reader)
|
public static IEnumerable<string> NonWhiteSpaceLines(this TextReader reader)
|
||||||
{
|
{
|
||||||
string? line;
|
while (reader.ReadLine() is { } line)
|
||||||
while ((line = reader.ReadLine()) != null)
|
|
||||||
{
|
{
|
||||||
if (line.IsWhiteSpace()) continue;
|
if (line.IsWhiteSpace()) continue;
|
||||||
yield return line;
|
yield return line;
|
||||||
@@ -48,26 +46,12 @@ namespace ServiceLib.Common
|
|||||||
|
|
||||||
public static string RemovePrefix(this string value, char prefix)
|
public static string RemovePrefix(this string value, char prefix)
|
||||||
{
|
{
|
||||||
if (value.StartsWith(prefix))
|
return value.StartsWith(prefix) ? value[1..] : value;
|
||||||
{
|
|
||||||
return value.Substring(1);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static string RemovePrefix(this string value, string prefix)
|
public static string RemovePrefix(this string value, string prefix)
|
||||||
{
|
{
|
||||||
if (value.StartsWith(prefix))
|
return value.StartsWith(prefix) ? value[prefix.Length..] : value;
|
||||||
{
|
|
||||||
return value.Substring(prefix.Length);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static string UpperFirstChar(this string value)
|
public static string UpperFirstChar(this string value)
|
||||||
@@ -77,17 +61,12 @@ namespace ServiceLib.Common
|
|||||||
return string.Empty;
|
return string.Empty;
|
||||||
}
|
}
|
||||||
|
|
||||||
return char.ToUpper(value[0]) + value.Substring(1);
|
return char.ToUpper(value[0]) + value[1..];
|
||||||
}
|
}
|
||||||
|
|
||||||
public static string AppendQuotes(this string value)
|
public static string AppendQuotes(this string value)
|
||||||
{
|
{
|
||||||
if (string.IsNullOrEmpty(value))
|
return string.IsNullOrEmpty(value) ? string.Empty : $"\"{value}\"";
|
||||||
{
|
|
||||||
return string.Empty;
|
|
||||||
}
|
|
||||||
|
|
||||||
return $"\"{value}\"";
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
File diff suppressed because it is too large
Load Diff
52
v2rayN/ServiceLib/Common/WindowsUtils.cs
Normal file
52
v2rayN/ServiceLib/Common/WindowsUtils.cs
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
using Microsoft.Win32;
|
||||||
|
|
||||||
|
namespace ServiceLib.Common
|
||||||
|
{
|
||||||
|
internal static class WindowsUtils
|
||||||
|
{
|
||||||
|
public static string? RegReadValue(string path, string name, string def)
|
||||||
|
{
|
||||||
|
RegistryKey? regKey = null;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
regKey = Registry.CurrentUser.OpenSubKey(path, false);
|
||||||
|
var value = regKey?.GetValue(name) as string;
|
||||||
|
return Utils.IsNullOrEmpty(value) ? def : value;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Logging.SaveLog(ex.Message, ex);
|
||||||
|
}
|
||||||
|
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 (Utils.IsNullOrEmpty(value.ToString()))
|
||||||
|
{
|
||||||
|
regKey?.DeleteValue(name, false);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
regKey?.SetValue(name, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Logging.SaveLog(ex.Message, ex);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
regKey?.Close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
using YamlDotNet.Serialization;
|
using YamlDotNet.Core;
|
||||||
|
using YamlDotNet.Serialization;
|
||||||
using YamlDotNet.Serialization.NamingConventions;
|
using YamlDotNet.Serialization.NamingConventions;
|
||||||
|
|
||||||
namespace ServiceLib.Common
|
namespace ServiceLib.Common
|
||||||
@@ -20,7 +21,7 @@ namespace ServiceLib.Common
|
|||||||
.Build();
|
.Build();
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
T obj = deserializer.Deserialize<T>(str);
|
var obj = deserializer.Deserialize<T>(str);
|
||||||
return obj;
|
return obj;
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
@@ -35,13 +36,17 @@ namespace ServiceLib.Common
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="obj"></param>
|
/// <param name="obj"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public static string ToYaml(Object obj)
|
public static string ToYaml(object? obj)
|
||||||
{
|
{
|
||||||
|
var result = string.Empty;
|
||||||
|
if (obj == null)
|
||||||
|
{
|
||||||
|
return result;
|
||||||
|
}
|
||||||
var serializer = new SerializerBuilder()
|
var serializer = new SerializerBuilder()
|
||||||
.WithNamingConvention(HyphenatedNamingConvention.Instance)
|
.WithNamingConvention(HyphenatedNamingConvention.Instance)
|
||||||
.Build();
|
.Build();
|
||||||
|
|
||||||
string result = string.Empty;
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
result = serializer.Serialize(obj);
|
result = serializer.Serialize(obj);
|
||||||
@@ -53,6 +58,24 @@ namespace ServiceLib.Common
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static string? PreprocessYaml(string str)
|
||||||
|
{
|
||||||
|
var deserializer = new DeserializerBuilder()
|
||||||
|
.WithNamingConvention(PascalCaseNamingConvention.Instance)
|
||||||
|
.Build();
|
||||||
|
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("PreprocessYaml", ex);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#endregion YAML
|
#endregion YAML
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -5,12 +5,12 @@
|
|||||||
VMess = 1,
|
VMess = 1,
|
||||||
Custom = 2,
|
Custom = 2,
|
||||||
Shadowsocks = 3,
|
Shadowsocks = 3,
|
||||||
Socks = 4,
|
SOCKS = 4,
|
||||||
VLESS = 5,
|
VLESS = 5,
|
||||||
Trojan = 6,
|
Trojan = 6,
|
||||||
Hysteria2 = 7,
|
Hysteria2 = 7,
|
||||||
Tuic = 8,
|
TUIC = 8,
|
||||||
Wireguard = 9,
|
WireGuard = 9,
|
||||||
Http = 10
|
HTTP = 10
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -4,11 +4,14 @@
|
|||||||
{
|
{
|
||||||
v2fly = 1,
|
v2fly = 1,
|
||||||
Xray = 2,
|
Xray = 2,
|
||||||
SagerNet = 3,
|
|
||||||
|
//SagerNet = 3,
|
||||||
v2fly_v5 = 4,
|
v2fly_v5 = 4,
|
||||||
clash = 11,
|
|
||||||
clash_meta = 12,
|
//clash = 11,
|
||||||
|
//clash_meta = 12,
|
||||||
mihomo = 13,
|
mihomo = 13,
|
||||||
|
|
||||||
hysteria = 21,
|
hysteria = 21,
|
||||||
naiveproxy = 22,
|
naiveproxy = 22,
|
||||||
tuic = 23,
|
tuic = 23,
|
||||||
|
|||||||
11
v2rayN/ServiceLib/Enums/EMsgCommand.cs
Normal file
11
v2rayN/ServiceLib/Enums/EMsgCommand.cs
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
namespace ServiceLib.Enums
|
||||||
|
{
|
||||||
|
public enum EMsgCommand
|
||||||
|
{
|
||||||
|
ClearMsg,
|
||||||
|
SendMsgView,
|
||||||
|
SendSnackMsg,
|
||||||
|
RefreshProfiles,
|
||||||
|
StopSpeedtest
|
||||||
|
}
|
||||||
|
}
|
||||||
8
v2rayN/ServiceLib/Enums/EPresetType.cs
Normal file
8
v2rayN/ServiceLib/Enums/EPresetType.cs
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
namespace ServiceLib.Enums
|
||||||
|
{
|
||||||
|
public enum EPresetType
|
||||||
|
{
|
||||||
|
Default = 0,
|
||||||
|
Russia = 1,
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -2,20 +2,20 @@
|
|||||||
{
|
{
|
||||||
public enum EServerColName
|
public enum EServerColName
|
||||||
{
|
{
|
||||||
def = 0,
|
Def = 0,
|
||||||
configType,
|
ConfigType,
|
||||||
remarks,
|
Remarks,
|
||||||
address,
|
Address,
|
||||||
port,
|
Port,
|
||||||
network,
|
Network,
|
||||||
streamSecurity,
|
StreamSecurity,
|
||||||
subRemarks,
|
SubRemarks,
|
||||||
delayVal,
|
DelayVal,
|
||||||
speedVal,
|
SpeedVal,
|
||||||
|
|
||||||
todayDown,
|
TodayDown,
|
||||||
todayUp,
|
TodayUp,
|
||||||
totalDown,
|
TotalDown,
|
||||||
totalUp
|
TotalUp
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -7,7 +7,6 @@
|
|||||||
SaveFileDialog,
|
SaveFileDialog,
|
||||||
AddBatchRoutingRulesYesNo,
|
AddBatchRoutingRulesYesNo,
|
||||||
AdjustMainLvColWidth,
|
AdjustMainLvColWidth,
|
||||||
UpdateSysProxy,
|
|
||||||
SetClipboardData,
|
SetClipboardData,
|
||||||
AddServerViaClipboard,
|
AddServerViaClipboard,
|
||||||
ImportRulesFromClipboard,
|
ImportRulesFromClipboard,
|
||||||
@@ -16,9 +15,11 @@
|
|||||||
ShareServer,
|
ShareServer,
|
||||||
ShowHideWindow,
|
ShowHideWindow,
|
||||||
ScanScreenTask,
|
ScanScreenTask,
|
||||||
|
ScanImageTask,
|
||||||
Shutdown,
|
Shutdown,
|
||||||
BrowseServer,
|
BrowseServer,
|
||||||
ImportRulesFromFile,
|
ImportRulesFromFile,
|
||||||
|
InitSettingFont,
|
||||||
SubEditWindow,
|
SubEditWindow,
|
||||||
RoutingRuleSettingWindow,
|
RoutingRuleSettingWindow,
|
||||||
RoutingRuleDetailsWindow,
|
RoutingRuleDetailsWindow,
|
||||||
@@ -39,6 +40,7 @@
|
|||||||
DispatcherRefreshServersBiz,
|
DispatcherRefreshServersBiz,
|
||||||
DispatcherRefreshIcon,
|
DispatcherRefreshIcon,
|
||||||
DispatcherCheckUpdate,
|
DispatcherCheckUpdate,
|
||||||
DispatcherCheckUpdateFinished,
|
DispatcherCheckUpdateFinished,
|
||||||
|
DispatcherShowMsg,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -9,10 +9,7 @@
|
|||||||
public const string GithubApiUrl = "https://api.github.com/repos";
|
public const string GithubApiUrl = "https://api.github.com/repos";
|
||||||
public const string V2flyCoreUrl = "https://github.com/v2fly/v2ray-core/releases";
|
public const string V2flyCoreUrl = "https://github.com/v2fly/v2ray-core/releases";
|
||||||
public const string XrayCoreUrl = "https://github.com/XTLS/Xray-core/releases";
|
public const string XrayCoreUrl = "https://github.com/XTLS/Xray-core/releases";
|
||||||
public const string SagerNetCoreUrl = "https://github.com/SagerNet/v2ray-core/releases";
|
|
||||||
public const string NUrl = @"https://github.com/2dust/v2rayN/releases";
|
public const string NUrl = @"https://github.com/2dust/v2rayN/releases";
|
||||||
public const string ClashCoreUrl = "https://github.com/Dreamacro/clash/releases";
|
|
||||||
public const string ClashMetaCoreUrl = "https://github.com/MetaCubeX/Clash.Meta/releases";
|
|
||||||
public const string MihomoCoreUrl = "https://github.com/MetaCubeX/mihomo/releases";
|
public const string MihomoCoreUrl = "https://github.com/MetaCubeX/mihomo/releases";
|
||||||
public const string HysteriaCoreUrl = "https://github.com/apernet/hysteria/releases";
|
public const string HysteriaCoreUrl = "https://github.com/apernet/hysteria/releases";
|
||||||
public const string NaiveproxyCoreUrl = "https://github.com/klzgrad/naiveproxy/releases";
|
public const string NaiveproxyCoreUrl = "https://github.com/klzgrad/naiveproxy/releases";
|
||||||
@@ -31,21 +28,24 @@
|
|||||||
public const string CoreSpeedtestConfigFileName = "configSpeedtest.json";
|
public const string CoreSpeedtestConfigFileName = "configSpeedtest.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 V2raySampleClient = "ServiceLib.Sample.SampleClientConfig";
|
|
||||||
public const string SingboxSampleClient = "ServiceLib.Sample.SingboxSampleClientConfig";
|
public const string NamespaceSample = "ServiceLib.Sample.";
|
||||||
public const string V2raySampleHttpRequestFileName = "ServiceLib.Sample.SampleHttpRequest";
|
public const string V2raySampleClient = NamespaceSample + "SampleClientConfig";
|
||||||
public const string V2raySampleHttpResponseFileName = "ServiceLib.Sample.SampleHttpResponse";
|
public const string SingboxSampleClient = NamespaceSample + "SingboxSampleClientConfig";
|
||||||
public const string V2raySampleInbound = "ServiceLib.Sample.SampleInbound";
|
public const string V2raySampleHttpRequestFileName = NamespaceSample + "SampleHttpRequest";
|
||||||
public const string V2raySampleOutbound = "ServiceLib.Sample.SampleOutbound";
|
public const string V2raySampleHttpResponseFileName = NamespaceSample + "SampleHttpResponse";
|
||||||
public const string SingboxSampleOutbound = "ServiceLib.Sample.SingboxSampleOutbound";
|
public const string V2raySampleInbound = NamespaceSample + "SampleInbound";
|
||||||
public const string CustomRoutingFileName = "ServiceLib.Sample.custom_routing_";
|
public const string V2raySampleOutbound = NamespaceSample + "SampleOutbound";
|
||||||
public const string TunSingboxDNSFileName = "ServiceLib.Sample.tun_singbox_dns";
|
public const string SingboxSampleOutbound = NamespaceSample + "SingboxSampleOutbound";
|
||||||
public const string TunSingboxInboundFileName = "ServiceLib.Sample.tun_singbox_inbound";
|
public const string CustomRoutingFileName = NamespaceSample + "custom_routing_";
|
||||||
public const string TunSingboxRulesFileName = "ServiceLib.Sample.tun_singbox_rules";
|
public const string TunSingboxDNSFileName = NamespaceSample + "tun_singbox_dns";
|
||||||
public const string DNSV2rayNormalFileName = "ServiceLib.Sample.dns_v2ray_normal";
|
public const string TunSingboxInboundFileName = NamespaceSample + "tun_singbox_inbound";
|
||||||
public const string DNSSingboxNormalFileName = "ServiceLib.Sample.dns_singbox_normal";
|
public const string TunSingboxRulesFileName = NamespaceSample + "tun_singbox_rules";
|
||||||
public const string ClashMixinYaml = "ServiceLib.Sample.clash_mixin_yaml";
|
public const string DNSV2rayNormalFileName = NamespaceSample + "dns_v2ray_normal";
|
||||||
public const string ClashTunYaml = "ServiceLib.Sample.clash_tun_yaml";
|
public const string DNSSingboxNormalFileName = NamespaceSample + "dns_singbox_normal";
|
||||||
|
public const string ClashMixinYaml = NamespaceSample + "clash_mixin_yaml";
|
||||||
|
public const string ClashTunYaml = NamespaceSample + "clash_tun_yaml";
|
||||||
|
public const string LinuxAutostartConfig = NamespaceSample + "linux_autostart_config";
|
||||||
|
|
||||||
public const string DefaultSecurity = "auto";
|
public const string DefaultSecurity = "auto";
|
||||||
public const string DefaultNetwork = "tcp";
|
public const string DefaultNetwork = "tcp";
|
||||||
@@ -71,11 +71,6 @@
|
|||||||
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 string CommandClearMsg = "CommandClearMsg";
|
|
||||||
public const string CommandSendMsgView = "CommandSendMsgView";
|
|
||||||
public const string CommandSendSnackMsg = "CommandSendSnackMsg";
|
|
||||||
public const string CommandStopSpeedTest = "CommandStopSpeedTest";
|
|
||||||
public const string CommandRefreshProfiles = "CommandRefreshProfiles";
|
|
||||||
public const string DelayUnit = "";
|
public const string DelayUnit = "";
|
||||||
public const string SpeedUnit = "";
|
public const string SpeedUnit = "";
|
||||||
public const int MinFontSize = 10;
|
public const int MinFontSize = 10;
|
||||||
@@ -110,9 +105,9 @@
|
|||||||
|
|
||||||
public static readonly List<string> SpeedTestUrls = new() {
|
public static readonly List<string> SpeedTestUrls = new() {
|
||||||
@"https://speed.cloudflare.com/__down?bytes=100000000",
|
@"https://speed.cloudflare.com/__down?bytes=100000000",
|
||||||
|
@"https://speed.cloudflare.com/__down?bytes=50000000",
|
||||||
@"https://speed.cloudflare.com/__down?bytes=10000000",
|
@"https://speed.cloudflare.com/__down?bytes=10000000",
|
||||||
@"http://cachefly.cachefly.net/50mb.test",
|
@"https://cachefly.cachefly.net/50mb.test",
|
||||||
@"http://cachefly.cachefly.net/10mb.test"
|
|
||||||
};
|
};
|
||||||
|
|
||||||
public static readonly List<string> SpeedPingTestUrls = new() {
|
public static readonly List<string> SpeedPingTestUrls = new() {
|
||||||
@@ -122,6 +117,26 @@
|
|||||||
@"http://www.msftconnecttest.com/connecttest.txt",
|
@"http://www.msftconnecttest.com/connecttest.txt",
|
||||||
};
|
};
|
||||||
|
|
||||||
|
public static readonly List<string> GeoFilesSources = new() {
|
||||||
|
"",
|
||||||
|
@"https://github.com/runetfreedom/russia-v2ray-rules-dat/releases/latest/download/{0}.dat",
|
||||||
|
};
|
||||||
|
|
||||||
|
public static readonly List<string> SingboxRulesetSources = new() {
|
||||||
|
"",
|
||||||
|
@"https://cdn.jsdelivr.net/gh/runetfreedom/russia-v2ray-rules-dat@release/sing-box/rule-set-{0}/{1}.srs",
|
||||||
|
};
|
||||||
|
|
||||||
|
public static readonly List<string> RoutingRulesSources = new() {
|
||||||
|
"",
|
||||||
|
@"https://cdn.jsdelivr.net/gh/runetfreedom/russia-v2ray-custom-routing-list@main/v2rayN/template.json",
|
||||||
|
};
|
||||||
|
|
||||||
|
public static readonly List<string> DNSTemplateSources = new() {
|
||||||
|
"",
|
||||||
|
@"https://cdn.jsdelivr.net/gh/runetfreedom/russia-v2ray-custom-routing-list@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" },
|
||||||
@@ -137,25 +152,25 @@
|
|||||||
{
|
{
|
||||||
{EConfigType.VMess,"vmess://"},
|
{EConfigType.VMess,"vmess://"},
|
||||||
{EConfigType.Shadowsocks,"ss://"},
|
{EConfigType.Shadowsocks,"ss://"},
|
||||||
{EConfigType.Socks,"socks://"},
|
{EConfigType.SOCKS,"socks://"},
|
||||||
{EConfigType.VLESS,"vless://"},
|
{EConfigType.VLESS,"vless://"},
|
||||||
{EConfigType.Trojan,"trojan://"},
|
{EConfigType.Trojan,"trojan://"},
|
||||||
{EConfigType.Hysteria2,"hysteria2://"},
|
{EConfigType.Hysteria2,"hysteria2://"},
|
||||||
{EConfigType.Tuic,"tuic://"},
|
{EConfigType.TUIC,"tuic://"},
|
||||||
{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"},
|
||||||
{EConfigType.Socks,"socks"},
|
{EConfigType.SOCKS,"socks"},
|
||||||
{EConfigType.Http,"http"},
|
{EConfigType.HTTP,"http"},
|
||||||
{EConfigType.VLESS,"vless"},
|
{EConfigType.VLESS,"vless"},
|
||||||
{EConfigType.Trojan,"trojan"},
|
{EConfigType.Trojan,"trojan"},
|
||||||
{EConfigType.Hysteria2,"hysteria2"},
|
{EConfigType.Hysteria2,"hysteria2"},
|
||||||
{EConfigType.Tuic,"tuic"},
|
{EConfigType.TUIC,"tuic"},
|
||||||
{EConfigType.Wireguard,"wireguard"}
|
{EConfigType.WireGuard,"wireguard"}
|
||||||
};
|
};
|
||||||
|
|
||||||
public static readonly List<string> VmessSecurities = new() { "aes-128-gcm", "chacha20-poly1305", "auto", "none", "zero" };
|
public static readonly List<string> VmessSecurities = new() { "aes-128-gcm", "chacha20-poly1305", "auto", "none", "zero" };
|
||||||
@@ -166,7 +181,7 @@
|
|||||||
public static readonly List<string> Flows = new() { "", "xtls-rprx-vision", "xtls-rprx-vision-udp443" };
|
public static readonly List<string> Flows = new() { "", "xtls-rprx-vision", "xtls-rprx-vision-udp443" };
|
||||||
public static readonly List<string> Networks = new() { "tcp", "kcp", "ws", "httpupgrade", "splithttp", "h2", "quic", "grpc" };
|
public static readonly List<string> Networks = new() { "tcp", "kcp", "ws", "httpupgrade", "splithttp", "h2", "quic", "grpc" };
|
||||||
public static readonly List<string> KcpHeaderTypes = new() { "srtp", "utp", "wechat-video", "dtls", "wireguard" };
|
public static readonly List<string> KcpHeaderTypes = new() { "srtp", "utp", "wechat-video", "dtls", "wireguard" };
|
||||||
public static readonly List<string> CoreTypes = new() { "v2fly", "SagerNet", "Xray", "sing_box" };
|
public static readonly List<string> CoreTypes = new() { "v2fly", "Xray", "sing_box" };
|
||||||
public static readonly List<string> CoreTypes4VLESS = new() { "Xray", "sing_box" };
|
public static readonly List<string> CoreTypes4VLESS = new() { "Xray", "sing_box" };
|
||||||
public static readonly List<string> DomainStrategies = new() { "AsIs", "IPIfNonMatch", "IPOnDemand" };
|
public static readonly List<string> DomainStrategies = new() { "AsIs", "IPIfNonMatch", "IPOnDemand" };
|
||||||
public static readonly List<string> DomainStrategies4Singbox = new() { "ipv4_only", "ipv6_only", "prefer_ipv4", "prefer_ipv6", "" };
|
public static readonly List<string> DomainStrategies4Singbox = new() { "ipv4_only", "ipv6_only", "prefer_ipv4", "prefer_ipv6", "" };
|
||||||
|
|||||||
@@ -2,8 +2,10 @@
|
|||||||
global using ServiceLib.Common;
|
global using ServiceLib.Common;
|
||||||
global using ServiceLib.Enums;
|
global using ServiceLib.Enums;
|
||||||
global using ServiceLib.Handler;
|
global using ServiceLib.Handler;
|
||||||
global using ServiceLib.Handler.CoreConfig;
|
|
||||||
global using ServiceLib.Handler.Fmt;
|
global using ServiceLib.Handler.Fmt;
|
||||||
global using ServiceLib.Handler.Statistics;
|
global using ServiceLib.Services;
|
||||||
|
global using ServiceLib.Services.Statistics;
|
||||||
|
global using ServiceLib.Services.CoreConfig;
|
||||||
global using ServiceLib.Models;
|
global using ServiceLib.Models;
|
||||||
global using ServiceLib.Resx;
|
global using ServiceLib.Resx;
|
||||||
|
global using ServiceLib.Handler.SysProxy;
|
||||||
274
v2rayN/ServiceLib/Handler/AppHandler.cs
Normal file
274
v2rayN/ServiceLib/Handler/AppHandler.cs
Normal file
@@ -0,0 +1,274 @@
|
|||||||
|
namespace ServiceLib.Handler
|
||||||
|
{
|
||||||
|
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
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
_statePort ??= Utils.GetFreePort(GetLocalPort(EInboundProtocol.api));
|
||||||
|
return _statePort.Value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public int StatePort2
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
_statePort2 ??= Utils.GetFreePort(GetLocalPort(EInboundProtocol.api2));
|
||||||
|
return _statePort2.Value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool IsAdministrator
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
_isAdministrator ??= Utils.IsAdministrator();
|
||||||
|
return _isAdministrator.Value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion Property
|
||||||
|
|
||||||
|
#region Init
|
||||||
|
|
||||||
|
public bool InitApp()
|
||||||
|
{
|
||||||
|
_config = ConfigHandler.LoadConfig();
|
||||||
|
if (_config == null)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
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.Setup();
|
||||||
|
Logging.LoggingEnabled(_config.GuiItem.EnableLog);
|
||||||
|
Logging.SaveLog($"v2rayN start up | {Utils.GetVersion()} | {Utils.GetExePath()}");
|
||||||
|
Logging.SaveLog($"{Environment.OSVersion} - {(Environment.Is64BitOperatingSystem ? 64 : 32)}");
|
||||||
|
Logging.ClearLogs();
|
||||||
|
|
||||||
|
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();
|
||||||
|
_processJob?.AddProcess(processHandle);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#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 (Utils.IsNullOrEmpty(subid))
|
||||||
|
{
|
||||||
|
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
|
||||||
|
from ProfileItem a
|
||||||
|
left join SubItem b on a.subid = b.id
|
||||||
|
where 1=1 ";
|
||||||
|
if (Utils.IsNotEmpty(subid))
|
||||||
|
{
|
||||||
|
sql += $" and a.subid = '{subid}'";
|
||||||
|
}
|
||||||
|
if (Utils.IsNotEmpty(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<List<ProfileItemModel>?> ProfileItemsEx(string subid, string filter)
|
||||||
|
{
|
||||||
|
var lstModel = await ProfileItems(_config.SubIndexId, filter);
|
||||||
|
|
||||||
|
await ConfigHandler.SetDefaultServer(_config, lstModel);
|
||||||
|
|
||||||
|
var lstServerStat = (_config.GuiItem.EnableStatistics ? StatisticsHandler.Instance.ServerStat : null) ?? [];
|
||||||
|
var lstProfileExs = await ProfileExHandler.Instance.GetProfileExs();
|
||||||
|
lstModel = (from t in lstModel
|
||||||
|
join t2 in lstServerStat on t.IndexId equals t2.IndexId into t2b
|
||||||
|
from t22 in t2b.DefaultIfEmpty()
|
||||||
|
join t3 in lstProfileExs on t.IndexId equals t3.IndexId into t3b
|
||||||
|
from t33 in t3b.DefaultIfEmpty()
|
||||||
|
select new ProfileItemModel
|
||||||
|
{
|
||||||
|
IndexId = t.IndexId,
|
||||||
|
ConfigType = t.ConfigType,
|
||||||
|
Remarks = t.Remarks,
|
||||||
|
Address = t.Address,
|
||||||
|
Port = t.Port,
|
||||||
|
Security = t.Security,
|
||||||
|
Network = t.Network,
|
||||||
|
StreamSecurity = t.StreamSecurity,
|
||||||
|
Subid = t.Subid,
|
||||||
|
SubRemarks = t.SubRemarks,
|
||||||
|
IsActive = t.IndexId == _config.IndexId,
|
||||||
|
Sort = t33 == null ? 0 : t33.Sort,
|
||||||
|
Delay = t33 == null ? 0 : t33.Delay,
|
||||||
|
DelayVal = t33?.Delay != 0 ? $"{t33?.Delay} {Global.DelayUnit}" : string.Empty,
|
||||||
|
SpeedVal = t33?.Speed != 0 ? $"{t33?.Speed} {Global.SpeedUnit}" : string.Empty,
|
||||||
|
TodayDown = t22 == null ? "" : Utils.HumanFy(t22.TodayDown),
|
||||||
|
TodayUp = t22 == null ? "" : Utils.HumanFy(t22.TodayUp),
|
||||||
|
TotalDown = t22 == null ? "" : Utils.HumanFy(t22.TotalDown),
|
||||||
|
TotalUp = t22 == null ? "" : Utils.HumanFy(t22.TotalUp)
|
||||||
|
}).OrderBy(t => t.Sort).ToList();
|
||||||
|
|
||||||
|
return lstModel;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<ProfileItem?> GetProfileItem(string indexId)
|
||||||
|
{
|
||||||
|
if (Utils.IsNullOrEmpty(indexId))
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return await SQLiteHelper.Instance.TableAsync<ProfileItem>().FirstOrDefaultAsync(it => it.IndexId == indexId);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<ProfileItem?> GetProfileItemViaRemarks(string? remarks)
|
||||||
|
{
|
||||||
|
if (Utils.IsNullOrEmpty(remarks))
|
||||||
|
{
|
||||||
|
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>().Where(it => it.Locked == false).OrderBy(t => t.Sort).ToListAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<RoutingItem?> GetRoutingItem(string id)
|
||||||
|
{
|
||||||
|
return await SQLiteHelper.Instance.TableAsync<RoutingItem>().FirstOrDefaultAsync(it => it.Locked == false && 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.SsSecuritiesInSagerNet;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ECoreType GetCoreType(ProfileItem profileItem, EConfigType eConfigType)
|
||||||
|
{
|
||||||
|
if (profileItem?.CoreType != null)
|
||||||
|
{
|
||||||
|
return (ECoreType)profileItem.CoreType;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_config.CoreTypeItem == null)
|
||||||
|
{
|
||||||
|
return ECoreType.Xray;
|
||||||
|
}
|
||||||
|
var item = _config.CoreTypeItem.FirstOrDefault(it => it.ConfigType == eConfigType);
|
||||||
|
if (item == null)
|
||||||
|
{
|
||||||
|
return ECoreType.Xray;
|
||||||
|
}
|
||||||
|
return item.CoreType;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion Core Type
|
||||||
|
}
|
||||||
|
}
|
||||||
155
v2rayN/ServiceLib/Handler/AutoStartupHandler.cs
Normal file
155
v2rayN/ServiceLib/Handler/AutoStartupHandler.cs
Normal file
@@ -0,0 +1,155 @@
|
|||||||
|
using System.Security.Principal;
|
||||||
|
using System.Text.RegularExpressions;
|
||||||
|
|
||||||
|
namespace ServiceLib.Handler
|
||||||
|
{
|
||||||
|
public static class AutoStartupHandler
|
||||||
|
{
|
||||||
|
public static async Task<bool> UpdateTask(Config config)
|
||||||
|
{
|
||||||
|
if (Utils.IsWindows())
|
||||||
|
{
|
||||||
|
await ClearTaskWindows();
|
||||||
|
|
||||||
|
if (config.GuiItem.AutoRun)
|
||||||
|
{
|
||||||
|
await SetTaskWindows();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (Utils.IsLinux())
|
||||||
|
{
|
||||||
|
await ClearTaskLinux();
|
||||||
|
|
||||||
|
if (config.GuiItem.AutoRun)
|
||||||
|
{
|
||||||
|
await SetTaskLinux();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
#region Windows
|
||||||
|
|
||||||
|
private static async Task ClearTaskWindows()
|
||||||
|
{
|
||||||
|
var autoRunName = GetAutoRunNameWindows();
|
||||||
|
WindowsUtils.RegWriteValue(Global.AutoRunRegPath, autoRunName, "");
|
||||||
|
if (Utils.IsAdministrator())
|
||||||
|
{
|
||||||
|
AutoStartTaskService(autoRunName, "", "");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static async Task SetTaskWindows()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var autoRunName = GetAutoRunNameWindows();
|
||||||
|
var exePath = Utils.GetExePath();
|
||||||
|
if (Utils.IsAdministrator())
|
||||||
|
{
|
||||||
|
AutoStartTaskService(autoRunName, exePath, "");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
WindowsUtils.RegWriteValue(Global.AutoRunRegPath, autoRunName, exePath.AppendQuotes());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Logging.SaveLog(ex.Message, ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <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 (Utils.IsNullOrEmpty(taskName))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var logonUser = WindowsIdentity.GetCurrent().Name;
|
||||||
|
using var taskService = new Microsoft.Win32.TaskScheduler.TaskService();
|
||||||
|
var tasks = taskService.RootFolder.GetTasks(new Regex(taskName));
|
||||||
|
if (Utils.IsNullOrEmpty(fileName))
|
||||||
|
{
|
||||||
|
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(10) });
|
||||||
|
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(ex.Message, ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static async Task SetTaskLinux()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var linuxConfig = Utils.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(ex.Message, 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
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -7,15 +7,10 @@ namespace ServiceLib.Handler
|
|||||||
private static readonly Lazy<ClashApiHandler> instance = new(() => new());
|
private static readonly Lazy<ClashApiHandler> instance = new(() => new());
|
||||||
public static ClashApiHandler Instance => instance.Value;
|
public static ClashApiHandler Instance => instance.Value;
|
||||||
|
|
||||||
private Dictionary<String, ProxiesItem>? _proxies;
|
private Dictionary<string, ProxiesItem>? _proxies;
|
||||||
public Dictionary<string, object> ProfileContent { get; set; }
|
public Dictionary<string, object> ProfileContent { get; set; }
|
||||||
|
|
||||||
public void GetClashProxies(Config config, Action<ClashProxies, ClashProviders> update)
|
public async Task<Tuple<ClashProxies, ClashProviders>?> GetClashProxiesAsync(Config config)
|
||||||
{
|
|
||||||
Task.Run(() => GetClashProxiesAsync(config, update));
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task GetClashProxiesAsync(Config config, Action<ClashProxies, ClashProviders> update)
|
|
||||||
{
|
{
|
||||||
for (var i = 0; i < 5; i++)
|
for (var i = 0; i < 5; i++)
|
||||||
{
|
{
|
||||||
@@ -30,74 +25,75 @@ namespace ServiceLib.Handler
|
|||||||
if (clashProxies != null || clashProviders != null)
|
if (clashProxies != null || clashProviders != null)
|
||||||
{
|
{
|
||||||
_proxies = clashProxies?.proxies;
|
_proxies = clashProxies?.proxies;
|
||||||
update(clashProxies, clashProviders);
|
return new Tuple<ClashProxies, ClashProviders>(clashProxies, clashProviders);
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
Task.Delay(5000).Wait();
|
|
||||||
|
await Task.Delay(2000);
|
||||||
}
|
}
|
||||||
update(null, null);
|
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void ClashProxiesDelayTest(bool blAll, List<ClashProxyModel> lstProxy, Action<ClashProxyModel?, string> update)
|
public void ClashProxiesDelayTest(bool blAll, List<ClashProxyModel> lstProxy, Action<ClashProxyModel?, string> updateFunc)
|
||||||
{
|
{
|
||||||
Task.Run(() =>
|
Task.Run(() =>
|
||||||
|
{
|
||||||
|
if (blAll)
|
||||||
{
|
{
|
||||||
if (blAll)
|
for (int i = 0; i < 5; i++)
|
||||||
{
|
{
|
||||||
for (int i = 0; i < 5; i++)
|
if (_proxies != null)
|
||||||
{
|
{
|
||||||
if (_proxies != null)
|
break;
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
Task.Delay(5000).Wait();
|
|
||||||
}
|
|
||||||
if (_proxies == null)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
lstProxy = new List<ClashProxyModel>();
|
|
||||||
foreach (KeyValuePair<string, ProxiesItem> 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(),
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
Task.Delay(5000).Wait();
|
||||||
}
|
}
|
||||||
|
if (_proxies == null)
|
||||||
if (lstProxy == null)
|
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
var urlBase = $"{GetApiUrl()}/proxies";
|
lstProxy = new List<ClashProxyModel>();
|
||||||
urlBase += @"/{0}/delay?timeout=10000&url=" + LazyConfig.Instance.Config.speedTestItem.speedPingTestUrl;
|
foreach (KeyValuePair<string, ProxiesItem> kv in _proxies)
|
||||||
|
|
||||||
List<Task> tasks = new List<Task>();
|
|
||||||
foreach (var it in lstProxy)
|
|
||||||
{
|
{
|
||||||
if (Global.notAllowTestType.Contains(it.type.ToLower()))
|
if (Global.notAllowTestType.Contains(kv.Value.type.ToLower()))
|
||||||
{
|
{
|
||||||
continue;
|
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,
|
||||||
update(it, result);
|
Type = kv.Value.type.ToLower(),
|
||||||
}));
|
});
|
||||||
}
|
}
|
||||||
Task.WaitAll(tasks.ToArray());
|
}
|
||||||
|
|
||||||
Task.Delay(1000).Wait();
|
if (lstProxy == null)
|
||||||
update(null, "");
|
{
|
||||||
});
|
return;
|
||||||
|
}
|
||||||
|
var urlBase = $"{GetApiUrl()}/proxies";
|
||||||
|
urlBase += @"/{0}/delay?timeout=10000&url=" + AppHandler.Instance.Config.SpeedTestItem.SpeedPingTestUrl;
|
||||||
|
|
||||||
|
List<Task> 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);
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
Task.WaitAll(tasks.ToArray());
|
||||||
|
|
||||||
|
Task.Delay(1000).Wait();
|
||||||
|
updateFunc?.Invoke(null, "");
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<ProxiesItem>? GetClashProxyGroups()
|
public List<ProxiesItem>? GetClashProxyGroups()
|
||||||
@@ -118,7 +114,7 @@ namespace ServiceLib.Handler
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public async void ClashSetActiveProxy(string name, string nameNode)
|
public async Task ClashSetActiveProxy(string name, string nameNode)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@@ -133,24 +129,21 @@ namespace ServiceLib.Handler
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void ClashConfigUpdate(Dictionary<string, string> headers)
|
public async Task ClashConfigUpdate(Dictionary<string, string> headers)
|
||||||
{
|
{
|
||||||
Task.Run(async () =>
|
if (_proxies == null)
|
||||||
{
|
{
|
||||||
if (_proxies == null)
|
return;
|
||||||
{
|
}
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var urlBase = $"{GetApiUrl()}/configs";
|
var urlBase = $"{GetApiUrl()}/configs";
|
||||||
|
|
||||||
await HttpClientHelper.Instance.PatchAsync(urlBase, headers);
|
await HttpClientHelper.Instance.PatchAsync(urlBase, headers);
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public async void ClashConfigReload(string filePath)
|
public async Task ClashConfigReload(string filePath)
|
||||||
{
|
{
|
||||||
ClashConnectionClose("");
|
await ClashConnectionClose("");
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var url = $"{GetApiUrl()}/configs?force=true";
|
var url = $"{GetApiUrl()}/configs?force=true";
|
||||||
@@ -164,12 +157,7 @@ namespace ServiceLib.Handler
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void GetClashConnections(Config config, Action<ClashConnections> update)
|
public async Task<ClashConnections?> GetClashConnectionsAsync(Config config)
|
||||||
{
|
|
||||||
Task.Run(() => GetClashConnectionsAsync(config, update));
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task GetClashConnectionsAsync(Config config, Action<ClashConnections> update)
|
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@@ -177,15 +165,17 @@ namespace ServiceLib.Handler
|
|||||||
var result = await HttpClientHelper.Instance.TryGetAsync(url);
|
var result = await HttpClientHelper.Instance.TryGetAsync(url);
|
||||||
var clashConnections = JsonUtils.Deserialize<ClashConnections>(result);
|
var clashConnections = JsonUtils.Deserialize<ClashConnections>(result);
|
||||||
|
|
||||||
update(clashConnections);
|
return clashConnections;
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Logging.SaveLog(ex.Message, ex);
|
Logging.SaveLog(ex.Message, ex);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async void ClashConnectionClose(string id)
|
public async Task ClashConnectionClose(string id)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@@ -200,7 +190,7 @@ namespace ServiceLib.Handler
|
|||||||
|
|
||||||
private string GetApiUrl()
|
private string GetApiUrl()
|
||||||
{
|
{
|
||||||
return $"{Global.HttpProtocol}{Global.Loopback}:{LazyConfig.Instance.StatePort2}";
|
return $"{Global.HttpProtocol}{Global.Loopback}:{AppHandler.Instance.StatePort2}";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -1,171 +0,0 @@
|
|||||||
namespace ServiceLib.Handler.CoreConfig
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Core configuration file processing class
|
|
||||||
/// </summary>
|
|
||||||
public class CoreConfigHandler
|
|
||||||
{
|
|
||||||
public static int GenerateClientConfig(ProfileItem node, string? fileName, out string msg, out string content)
|
|
||||||
{
|
|
||||||
content = string.Empty;
|
|
||||||
try
|
|
||||||
{
|
|
||||||
if (node == null)
|
|
||||||
{
|
|
||||||
msg = ResUI.CheckServerSettings;
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
var config = LazyConfig.Instance.Config;
|
|
||||||
|
|
||||||
msg = ResUI.InitialConfiguration;
|
|
||||||
if (node.configType == EConfigType.Custom)
|
|
||||||
{
|
|
||||||
if (node.coreType is ECoreType.clash or ECoreType.clash_meta or ECoreType.mihomo)
|
|
||||||
{
|
|
||||||
var configGenClash = new CoreConfigClash(config);
|
|
||||||
return configGenClash.GenerateClientCustomConfig(node, fileName, out msg);
|
|
||||||
}
|
|
||||||
if (node.coreType is ECoreType.sing_box)
|
|
||||||
{
|
|
||||||
var configGenSingbox = new CoreConfigSingbox(config);
|
|
||||||
return configGenSingbox.GenerateClientCustomConfig(node, fileName, out msg);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return GenerateClientCustomConfig(node, fileName, out msg);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (LazyConfig.Instance.GetCoreType(node, node.configType) == ECoreType.sing_box)
|
|
||||||
{
|
|
||||||
var configGenSingbox = new CoreConfigSingbox(config);
|
|
||||||
if (configGenSingbox.GenerateClientConfigContent(node, out SingboxConfig? singboxConfig, out msg) != 0)
|
|
||||||
{
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
if (Utils.IsNullOrEmpty(fileName))
|
|
||||||
{
|
|
||||||
content = JsonUtils.Serialize(singboxConfig);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
JsonUtils.ToFile(singboxConfig, fileName, false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
var coreConfigV2ray = new CoreConfigV2ray(config);
|
|
||||||
if (coreConfigV2ray.GenerateClientConfigContent(node, out V2rayConfig? v2rayConfig, out msg) != 0)
|
|
||||||
{
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
if (Utils.IsNullOrEmpty(fileName))
|
|
||||||
{
|
|
||||||
content = JsonUtils.Serialize(v2rayConfig);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
JsonUtils.ToFile(v2rayConfig, fileName, false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
Logging.SaveLog("GenerateClientConfig", ex);
|
|
||||||
msg = ResUI.FailedGenDefaultConfiguration;
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static int GenerateClientCustomConfig(ProfileItem node, string? fileName, out string msg)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
if (node == null || fileName is null)
|
|
||||||
{
|
|
||||||
msg = ResUI.CheckServerSettings;
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
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))
|
|
||||||
{
|
|
||||||
msg = ResUI.FailedGenDefaultConfiguration;
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
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))
|
|
||||||
{
|
|
||||||
msg = ResUI.FailedGenDefaultConfiguration;
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
msg = string.Format(ResUI.SuccessfulConfiguration, "");
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
Logging.SaveLog("GenerateClientCustomConfig", ex);
|
|
||||||
msg = ResUI.FailedGenDefaultConfiguration;
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static int GenerateClientSpeedtestConfig(Config config, string fileName, List<ServerTestItem> selecteds, ECoreType coreType, out string msg)
|
|
||||||
{
|
|
||||||
if (coreType == ECoreType.sing_box)
|
|
||||||
{
|
|
||||||
if (new CoreConfigSingbox(config).GenerateClientSpeedtestConfig(selecteds, out SingboxConfig? singboxConfig, out msg) != 0)
|
|
||||||
{
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
JsonUtils.ToFile(singboxConfig, fileName, false);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (new CoreConfigV2ray(config).GenerateClientSpeedtestConfig(selecteds, out V2rayConfig? v2rayConfig, out msg) != 0)
|
|
||||||
{
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
JsonUtils.ToFile(v2rayConfig, fileName, false);
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static int GenerateClientMultipleLoadConfig(Config config, string fileName, List<ProfileItem> selecteds, ECoreType coreType, out string msg)
|
|
||||||
{
|
|
||||||
msg = ResUI.CheckServerSettings;
|
|
||||||
if (coreType == ECoreType.sing_box)
|
|
||||||
{
|
|
||||||
if (new CoreConfigSingbox(config).GenerateClientMultipleLoadConfig(selecteds, out SingboxConfig? singboxConfig, out msg) != 0)
|
|
||||||
{
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
JsonUtils.ToFile(singboxConfig, fileName, false);
|
|
||||||
}
|
|
||||||
else if (coreType == ECoreType.Xray)
|
|
||||||
{
|
|
||||||
if (new CoreConfigV2ray(config).GenerateClientMultipleLoadConfig(selecteds, out V2rayConfig? v2rayConfig, out msg) != 0)
|
|
||||||
{
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
JsonUtils.ToFile(v2rayConfig, fileName, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
130
v2rayN/ServiceLib/Handler/CoreConfigHandler.cs
Normal file
130
v2rayN/ServiceLib/Handler/CoreConfigHandler.cs
Normal file
@@ -0,0 +1,130 @@
|
|||||||
|
namespace ServiceLib.Handler
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Core configuration file processing class
|
||||||
|
/// </summary>
|
||||||
|
public class CoreConfigHandler
|
||||||
|
{
|
||||||
|
public static async Task<RetResult> GenerateClientConfig(ProfileItem node, string? fileName)
|
||||||
|
{
|
||||||
|
var config = AppHandler.Instance.Config;
|
||||||
|
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),
|
||||||
|
_ => await GenerateClientCustomConfig(node, fileName)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
else if (AppHandler.Instance.GetCoreType(node, node.ConfigType) == ECoreType.sing_box)
|
||||||
|
{
|
||||||
|
result = await new CoreConfigSingboxService(config).GenerateClientConfigContent(node);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
result = await new CoreConfigV2rayService(config).GenerateClientConfigContent(node);
|
||||||
|
}
|
||||||
|
if (result.Success != true)
|
||||||
|
{
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
if (Utils.IsNotEmpty(fileName) && result.Data != null)
|
||||||
|
{
|
||||||
|
await File.WriteAllTextAsync(fileName, result.Data.ToString());
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static async Task<RetResult> GenerateClientCustomConfig(ProfileItem node, string? fileName)
|
||||||
|
{
|
||||||
|
var ret = new RetResult();
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (node == null || fileName is null)
|
||||||
|
{
|
||||||
|
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 ret;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Logging.SaveLog("GenerateClientCustomConfig", ex);
|
||||||
|
ret.Msg = ResUI.FailedGenDefaultConfiguration;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static async Task<RetResult> GenerateClientSpeedtestConfig(Config config, string fileName, List<ServerTestItem> selecteds, ECoreType coreType)
|
||||||
|
{
|
||||||
|
var result = new RetResult();
|
||||||
|
if (coreType == ECoreType.sing_box)
|
||||||
|
{
|
||||||
|
result = await new CoreConfigSingboxService(config).GenerateClientSpeedtestConfig(selecteds);
|
||||||
|
}
|
||||||
|
else if (coreType == ECoreType.Xray)
|
||||||
|
{
|
||||||
|
result = await new CoreConfigV2rayService(config).GenerateClientSpeedtestConfig(selecteds);
|
||||||
|
}
|
||||||
|
if (result.Success != true)
|
||||||
|
{
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
await File.WriteAllTextAsync(fileName, result.Data.ToString());
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static async Task<RetResult> 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -8,21 +8,48 @@ namespace ServiceLib.Handler
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public class CoreHandler
|
public class CoreHandler
|
||||||
{
|
{
|
||||||
|
private static readonly Lazy<CoreHandler> _instance = new(() => new());
|
||||||
|
public static CoreHandler Instance => _instance.Value;
|
||||||
private Config _config;
|
private Config _config;
|
||||||
private Process? _process;
|
private Process? _process;
|
||||||
private Process? _processPre;
|
private Process? _processPre;
|
||||||
private Action<bool, string> _updateFunc;
|
private Action<bool, string>? _updateFunc;
|
||||||
|
|
||||||
public CoreHandler(Config config, Action<bool, string> update)
|
public async Task Init(Config config, Action<bool, string> updateFunc)
|
||||||
{
|
{
|
||||||
_config = config;
|
_config = config;
|
||||||
_updateFunc = update;
|
_updateFunc = updateFunc;
|
||||||
|
|
||||||
Environment.SetEnvironmentVariable("v2ray.location.asset", Utils.GetBinPath(""), EnvironmentVariableTarget.Process);
|
Environment.SetEnvironmentVariable("V2RAY_LOCATION_ASSET", Utils.GetBinPath(""), EnvironmentVariableTarget.Process);
|
||||||
Environment.SetEnvironmentVariable("xray.location.asset", Utils.GetBinPath(""), EnvironmentVariableTarget.Process);
|
Environment.SetEnvironmentVariable("XRAY_LOCATION_ASSET", Utils.GetBinPath(""), EnvironmentVariableTarget.Process);
|
||||||
|
|
||||||
|
if (Utils.IsLinux())
|
||||||
|
{
|
||||||
|
var coreInfo = CoreInfoHandler.Instance.GetCoreInfo();
|
||||||
|
foreach (var it in coreInfo)
|
||||||
|
{
|
||||||
|
if (it.CoreType == ECoreType.v2rayN)
|
||||||
|
{
|
||||||
|
if (Utils.UpgradeAppExists(out var fileName))
|
||||||
|
{
|
||||||
|
await Utils.SetLinuxChmod(fileName);
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var name in it.CoreExes)
|
||||||
|
{
|
||||||
|
var exe = Utils.GetBinPath(Utils.GetExeName(name), it.CoreType.ToString());
|
||||||
|
if (File.Exists(exe))
|
||||||
|
{
|
||||||
|
await Utils.SetLinuxChmod(exe);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void LoadCore(ProfileItem? node)
|
public async Task LoadCore(ProfileItem? node)
|
||||||
{
|
{
|
||||||
if (node == null)
|
if (node == null)
|
||||||
{
|
{
|
||||||
@@ -30,18 +57,18 @@ namespace ServiceLib.Handler
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
string fileName = Utils.GetConfigPath(Global.CoreConfigFileName);
|
var fileName = Utils.GetConfigPath(Global.CoreConfigFileName);
|
||||||
if (CoreConfigHandler.GenerateClientConfig(node, fileName, out string msg, out string content) != 0)
|
var result = await CoreConfigHandler.GenerateClientConfig(node, fileName);
|
||||||
|
ShowMsg(false, result.Msg);
|
||||||
|
if (result.Success != true)
|
||||||
{
|
{
|
||||||
ShowMsg(false, msg);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
ShowMsg(false, msg);
|
|
||||||
ShowMsg(true, $"{node.GetSummary()}");
|
ShowMsg(true, $"{node.GetSummary()}");
|
||||||
CoreStop();
|
await CoreStop();
|
||||||
CoreStart(node);
|
await CoreStart(node);
|
||||||
|
|
||||||
//In tun mode, do a delay check and restart the core
|
//In tun mode, do a delay check and restart the core
|
||||||
//if (_config.tunModeItem.enableTun)
|
//if (_config.tunModeItem.enableTun)
|
||||||
@@ -63,66 +90,36 @@ namespace ServiceLib.Handler
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public int LoadCoreConfigSpeedtest(List<ServerTestItem> selecteds)
|
public async Task<int> LoadCoreConfigSpeedtest(List<ServerTestItem> selecteds)
|
||||||
{
|
{
|
||||||
int pid = -1;
|
var pid = -1;
|
||||||
var coreType = selecteds.Exists(t => t.configType == EConfigType.Hysteria2 || t.configType == EConfigType.Tuic || t.configType == EConfigType.Wireguard) ? ECoreType.sing_box : ECoreType.Xray;
|
var coreType = selecteds.Exists(t => t.ConfigType is EConfigType.Hysteria2 or EConfigType.TUIC or EConfigType.WireGuard) ? ECoreType.sing_box : ECoreType.Xray;
|
||||||
string configPath = Utils.GetConfigPath(Global.CoreSpeedtestConfigFileName);
|
var configPath = Utils.GetConfigPath(Global.CoreSpeedtestConfigFileName);
|
||||||
if (CoreConfigHandler.GenerateClientSpeedtestConfig(_config, configPath, selecteds, coreType, out string msg) != 0)
|
var result = await CoreConfigHandler.GenerateClientSpeedtestConfig(_config, configPath, selecteds, coreType);
|
||||||
|
ShowMsg(false, result.Msg);
|
||||||
|
if (result.Success)
|
||||||
{
|
{
|
||||||
ShowMsg(false, msg);
|
pid = await CoreStartSpeedtest(configPath, coreType);
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
ShowMsg(false, msg);
|
|
||||||
pid = CoreStartSpeedtest(configPath, coreType);
|
|
||||||
}
|
}
|
||||||
return pid;
|
return pid;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void CoreStop()
|
public async Task CoreStop()
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
bool hasProc = false;
|
|
||||||
if (_process != null)
|
if (_process != null)
|
||||||
{
|
{
|
||||||
KillProcess(_process);
|
await KillProcess(_process);
|
||||||
_process.Dispose();
|
_process.Dispose();
|
||||||
_process = null;
|
_process = null;
|
||||||
hasProc = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_processPre != null)
|
if (_processPre != null)
|
||||||
{
|
{
|
||||||
KillProcess(_processPre);
|
await KillProcess(_processPre);
|
||||||
_processPre.Dispose();
|
_processPre.Dispose();
|
||||||
_processPre = null;
|
_processPre = null;
|
||||||
hasProc = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!hasProc)
|
|
||||||
{
|
|
||||||
var coreInfo = CoreInfoHandler.Instance.GetCoreInfo();
|
|
||||||
foreach (var it in coreInfo)
|
|
||||||
{
|
|
||||||
if (it.coreType == ECoreType.v2rayN)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
foreach (string vName in it.coreExes)
|
|
||||||
{
|
|
||||||
var existing = Process.GetProcessesByName(vName);
|
|
||||||
foreach (Process p in existing)
|
|
||||||
{
|
|
||||||
string? path = p.MainModule?.FileName;
|
|
||||||
if (path == Utils.GetExeName(Utils.GetBinPath(vName, it.coreType.ToString())))
|
|
||||||
{
|
|
||||||
KillProcess(p);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
@@ -131,12 +128,12 @@ namespace ServiceLib.Handler
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void CoreStopPid(int pid)
|
public async Task CoreStopPid(int pid)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var _p = Process.GetProcessById(pid);
|
var _p = Process.GetProcessById(pid);
|
||||||
KillProcess(_p);
|
await KillProcess(_p);
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
@@ -149,10 +146,9 @@ namespace ServiceLib.Handler
|
|||||||
private string CoreFindExe(CoreInfo coreInfo)
|
private string CoreFindExe(CoreInfo coreInfo)
|
||||||
{
|
{
|
||||||
string fileName = string.Empty;
|
string fileName = string.Empty;
|
||||||
foreach (string name in coreInfo.coreExes)
|
foreach (var name in coreInfo.CoreExes)
|
||||||
{
|
{
|
||||||
string vName = Utils.GetExeName(name);
|
var vName = Utils.GetBinPath(Utils.GetExeName(name), coreInfo.CoreType.ToString());
|
||||||
vName = Utils.GetBinPath(vName, coreInfo.coreType.ToString());
|
|
||||||
if (File.Exists(vName))
|
if (File.Exists(vName))
|
||||||
{
|
{
|
||||||
fileName = vName;
|
fileName = vName;
|
||||||
@@ -161,14 +157,14 @@ namespace ServiceLib.Handler
|
|||||||
}
|
}
|
||||||
if (Utils.IsNullOrEmpty(fileName))
|
if (Utils.IsNullOrEmpty(fileName))
|
||||||
{
|
{
|
||||||
string msg = string.Format(ResUI.NotFoundCore, Utils.GetBinPath("", coreInfo.coreType.ToString()), string.Join(", ", coreInfo.coreExes.ToArray()), coreInfo.coreUrl);
|
string msg = string.Format(ResUI.NotFoundCore, Utils.GetBinPath("", coreInfo.CoreType.ToString()), string.Join(", ", coreInfo.CoreExes.ToArray()), coreInfo.Url);
|
||||||
Logging.SaveLog(msg);
|
Logging.SaveLog(msg);
|
||||||
ShowMsg(false, msg);
|
ShowMsg(false, msg);
|
||||||
}
|
}
|
||||||
return fileName;
|
return fileName;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void CoreStart(ProfileItem node)
|
private async Task CoreStart(ProfileItem node)
|
||||||
{
|
{
|
||||||
ShowMsg(false, $"{Environment.OSVersion} - {(Environment.Is64BitOperatingSystem ? 64 : 32)}");
|
ShowMsg(false, $"{Environment.OSVersion} - {(Environment.Is64BitOperatingSystem ? 64 : 32)}");
|
||||||
ShowMsg(false, string.Format(ResUI.StartService, DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss")));
|
ShowMsg(false, string.Format(ResUI.StartService, DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss")));
|
||||||
@@ -182,12 +178,12 @@ namespace ServiceLib.Handler
|
|||||||
//{
|
//{
|
||||||
// coreType = LazyConfig.Instance.GetCoreType(node, node.configType);
|
// coreType = LazyConfig.Instance.GetCoreType(node, node.configType);
|
||||||
//}
|
//}
|
||||||
var coreType = LazyConfig.Instance.GetCoreType(node, node.configType);
|
var coreType = AppHandler.Instance.GetCoreType(node, node.ConfigType);
|
||||||
_config.runningCoreType = coreType;
|
_config.RunningCoreType = coreType;
|
||||||
var coreInfo = CoreInfoHandler.Instance.GetCoreInfo(coreType);
|
var coreInfo = CoreInfoHandler.Instance.GetCoreInfo(coreType);
|
||||||
|
|
||||||
var displayLog = node.configType != EConfigType.Custom || node.displayLog;
|
var displayLog = node.ConfigType != EConfigType.Custom || node.DisplayLog;
|
||||||
var proc = RunProcess(node, coreInfo, "", displayLog);
|
var proc = await RunProcess(node, coreInfo, "", displayLog);
|
||||||
if (proc is null)
|
if (proc is null)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
@@ -199,36 +195,37 @@ namespace ServiceLib.Handler
|
|||||||
{
|
{
|
||||||
ProfileItem? itemSocks = null;
|
ProfileItem? itemSocks = null;
|
||||||
var preCoreType = ECoreType.sing_box;
|
var preCoreType = ECoreType.sing_box;
|
||||||
if (node.configType != EConfigType.Custom && coreType != ECoreType.sing_box && _config.tunModeItem.enableTun)
|
if (node.ConfigType != EConfigType.Custom && coreType != ECoreType.sing_box && _config.TunModeItem.EnableTun)
|
||||||
{
|
{
|
||||||
itemSocks = new ProfileItem()
|
itemSocks = new ProfileItem()
|
||||||
{
|
{
|
||||||
coreType = preCoreType,
|
CoreType = preCoreType,
|
||||||
configType = EConfigType.Socks,
|
ConfigType = EConfigType.SOCKS,
|
||||||
address = Global.Loopback,
|
Address = Global.Loopback,
|
||||||
sni = node.address, //Tun2SocksAddress
|
Sni = node.Address, //Tun2SocksAddress
|
||||||
port = LazyConfig.Instance.GetLocalPort(EInboundProtocol.socks)
|
Port = AppHandler.Instance.GetLocalPort(EInboundProtocol.socks)
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
else if ((node.configType == EConfigType.Custom && node.preSocksPort > 0))
|
else if ((node.ConfigType == EConfigType.Custom && node.PreSocksPort > 0))
|
||||||
{
|
{
|
||||||
preCoreType = _config.tunModeItem.enableTun ? ECoreType.sing_box : ECoreType.Xray;
|
preCoreType = _config.TunModeItem.EnableTun ? ECoreType.sing_box : ECoreType.Xray;
|
||||||
itemSocks = new ProfileItem()
|
itemSocks = new ProfileItem()
|
||||||
{
|
{
|
||||||
coreType = preCoreType,
|
CoreType = preCoreType,
|
||||||
configType = EConfigType.Socks,
|
ConfigType = EConfigType.SOCKS,
|
||||||
address = Global.Loopback,
|
Address = Global.Loopback,
|
||||||
port = node.preSocksPort.Value,
|
Port = node.PreSocksPort.Value,
|
||||||
};
|
};
|
||||||
_config.runningCoreType = preCoreType;
|
_config.RunningCoreType = preCoreType;
|
||||||
}
|
}
|
||||||
if (itemSocks != null)
|
if (itemSocks != null)
|
||||||
{
|
{
|
||||||
string fileName2 = Utils.GetConfigPath(Global.CorePreConfigFileName);
|
string fileName2 = Utils.GetConfigPath(Global.CorePreConfigFileName);
|
||||||
if (CoreConfigHandler.GenerateClientConfig(itemSocks, fileName2, out string msg2, out string configStr) == 0)
|
var result = await CoreConfigHandler.GenerateClientConfig(itemSocks, fileName2);
|
||||||
|
if (result.Success)
|
||||||
{
|
{
|
||||||
var coreInfo2 = CoreInfoHandler.Instance.GetCoreInfo(preCoreType);
|
var coreInfo2 = CoreInfoHandler.Instance.GetCoreInfo(preCoreType);
|
||||||
var proc2 = RunProcess(node, coreInfo2, $" -c {Global.CorePreConfigFileName}", true);
|
var proc2 = await RunProcess(node, coreInfo2, $" -c {Global.CorePreConfigFileName}", true);
|
||||||
if (proc2 is not null)
|
if (proc2 is not null)
|
||||||
{
|
{
|
||||||
_processPre = proc2;
|
_processPre = proc2;
|
||||||
@@ -238,7 +235,7 @@ namespace ServiceLib.Handler
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private int CoreStartSpeedtest(string configPath, ECoreType coreType)
|
private async Task<int> CoreStartSpeedtest(string configPath, ECoreType coreType)
|
||||||
{
|
{
|
||||||
ShowMsg(false, string.Format(ResUI.StartService, DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss")));
|
ShowMsg(false, string.Format(ResUI.StartService, DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss")));
|
||||||
|
|
||||||
@@ -246,7 +243,7 @@ namespace ServiceLib.Handler
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
var coreInfo = CoreInfoHandler.Instance.GetCoreInfo(coreType);
|
var coreInfo = CoreInfoHandler.Instance.GetCoreInfo(coreType);
|
||||||
var proc = RunProcess(new(), coreInfo, $" -c {Global.CoreSpeedtestConfigFileName}", true);
|
var proc = await RunProcess(new(), coreInfo, $" -c {Global.CoreSpeedtestConfigFileName}", true);
|
||||||
if (proc is null)
|
if (proc is null)
|
||||||
{
|
{
|
||||||
return -1;
|
return -1;
|
||||||
@@ -265,14 +262,14 @@ namespace ServiceLib.Handler
|
|||||||
|
|
||||||
private void ShowMsg(bool notify, string msg)
|
private void ShowMsg(bool notify, string msg)
|
||||||
{
|
{
|
||||||
_updateFunc(notify, msg);
|
_updateFunc?.Invoke(notify, msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion Private
|
#endregion Private
|
||||||
|
|
||||||
#region Process
|
#region Process
|
||||||
|
|
||||||
private Process? RunProcess(ProfileItem node, CoreInfo coreInfo, string configPath, bool displayLog)
|
private async Task<Process?> RunProcess(ProfileItem node, CoreInfo coreInfo, string configPath, bool displayLog)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@@ -286,7 +283,7 @@ namespace ServiceLib.Handler
|
|||||||
StartInfo = new()
|
StartInfo = new()
|
||||||
{
|
{
|
||||||
FileName = fileName,
|
FileName = fileName,
|
||||||
Arguments = string.Format(coreInfo.arguments, configPath),
|
Arguments = string.Format(coreInfo.Arguments, configPath),
|
||||||
WorkingDirectory = Utils.GetConfigPath(),
|
WorkingDirectory = Utils.GetConfigPath(),
|
||||||
UseShellExecute = false,
|
UseShellExecute = false,
|
||||||
RedirectStandardOutput = displayLog,
|
RedirectStandardOutput = displayLog,
|
||||||
@@ -302,7 +299,7 @@ namespace ServiceLib.Handler
|
|||||||
{
|
{
|
||||||
proc.OutputDataReceived += (sender, e) =>
|
proc.OutputDataReceived += (sender, e) =>
|
||||||
{
|
{
|
||||||
if (!Utils.IsNullOrEmpty(e.Data))
|
if (Utils.IsNotEmpty(e.Data))
|
||||||
{
|
{
|
||||||
string msg = e.Data + Environment.NewLine;
|
string msg = e.Data + Environment.NewLine;
|
||||||
ShowMsg(false, msg);
|
ShowMsg(false, msg);
|
||||||
@@ -310,7 +307,7 @@ namespace ServiceLib.Handler
|
|||||||
};
|
};
|
||||||
proc.ErrorDataReceived += (sender, e) =>
|
proc.ErrorDataReceived += (sender, e) =>
|
||||||
{
|
{
|
||||||
if (!Utils.IsNullOrEmpty(e.Data))
|
if (Utils.IsNotEmpty(e.Data))
|
||||||
{
|
{
|
||||||
string msg = e.Data + Environment.NewLine;
|
string msg = e.Data + Environment.NewLine;
|
||||||
ShowMsg(false, msg);
|
ShowMsg(false, msg);
|
||||||
@@ -339,7 +336,7 @@ namespace ServiceLib.Handler
|
|||||||
startUpSuccessful = true;
|
startUpSuccessful = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
LazyConfig.Instance.AddProcess(proc.Handle);
|
AppHandler.Instance.AddProcess(proc.Handle);
|
||||||
return proc;
|
return proc;
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
@@ -351,7 +348,7 @@ namespace ServiceLib.Handler
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void KillProcess(Process? proc)
|
private async Task KillProcess(Process? proc)
|
||||||
{
|
{
|
||||||
if (proc is null)
|
if (proc is null)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ namespace ServiceLib.Handler
|
|||||||
{
|
{
|
||||||
InitCoreInfo();
|
InitCoreInfo();
|
||||||
}
|
}
|
||||||
return _coreInfo?.FirstOrDefault(t => t.coreType == coreType);
|
return _coreInfo?.FirstOrDefault(t => t.CoreType == coreType);
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<CoreInfo> GetCoreInfo()
|
public List<CoreInfo> GetCoreInfo()
|
||||||
@@ -37,175 +37,131 @@ namespace ServiceLib.Handler
|
|||||||
|
|
||||||
_coreInfo.Add(new CoreInfo
|
_coreInfo.Add(new CoreInfo
|
||||||
{
|
{
|
||||||
coreType = ECoreType.v2rayN,
|
CoreType = ECoreType.v2rayN,
|
||||||
coreUrl = Global.NUrl,
|
Url = Global.NUrl,
|
||||||
coreReleaseApiUrl = Global.NUrl.Replace(Global.GithubUrl, Global.GithubApiUrl),
|
ReleaseApiUrl = Global.NUrl.Replace(Global.GithubUrl, Global.GithubApiUrl),
|
||||||
coreDownloadUrl32 = Global.NUrl + "/download/{0}/v2rayN-32.zip",
|
DownloadUrlWin64 = Global.NUrl + "/download/{0}/v2rayN-windows-64.zip",
|
||||||
coreDownloadUrl64 = Global.NUrl + "/download/{0}/v2rayN.zip",
|
DownloadUrlWinArm64 = Global.NUrl + "/download/{0}/v2rayN-windows-arm64.zip",
|
||||||
coreDownloadUrlArm64 = Global.NUrl + "/download/{0}/v2rayN-arm64.zip",
|
DownloadUrlLinux64 = Global.NUrl + "/download/{0}/v2rayN-linux-64.zip",
|
||||||
coreDownloadUrlLinux32 = Global.NUrl + "/download/{0}/v2rayN-linux-32.zip",
|
DownloadUrlLinuxArm64 = Global.NUrl + "/download/{0}/v2rayN-linux-arm64.zip",
|
||||||
coreDownloadUrlLinux64 = Global.NUrl + "/download/{0}/v2rayN-linux-64.zip",
|
|
||||||
coreDownloadUrlLinuxArm64 = Global.NUrl + "/download/{0}/v2rayN-linux-arm64.zip",
|
|
||||||
});
|
});
|
||||||
|
|
||||||
_coreInfo.Add(new CoreInfo
|
_coreInfo.Add(new CoreInfo
|
||||||
{
|
{
|
||||||
coreType = ECoreType.v2fly,
|
CoreType = ECoreType.v2fly,
|
||||||
coreExes = new List<string> { "wv2ray", "v2ray" },
|
CoreExes = new List<string> { "wv2ray", "v2ray" },
|
||||||
arguments = "",
|
Arguments = "",
|
||||||
coreUrl = Global.V2flyCoreUrl,
|
Url = Global.V2flyCoreUrl,
|
||||||
coreReleaseApiUrl = Global.V2flyCoreUrl.Replace(Global.GithubUrl, Global.GithubApiUrl),
|
ReleaseApiUrl = Global.V2flyCoreUrl.Replace(Global.GithubUrl, Global.GithubApiUrl),
|
||||||
match = "V2Ray",
|
Match = "V2Ray",
|
||||||
versionArg = "-version",
|
VersionArg = "-version",
|
||||||
redirectInfo = true,
|
RedirectInfo = true,
|
||||||
});
|
});
|
||||||
|
|
||||||
_coreInfo.Add(new CoreInfo
|
_coreInfo.Add(new CoreInfo
|
||||||
{
|
{
|
||||||
coreType = ECoreType.SagerNet,
|
CoreType = ECoreType.v2fly_v5,
|
||||||
coreExes = new List<string> { "SagerNet", "v2ray" },
|
CoreExes = new List<string> { "v2ray" },
|
||||||
arguments = "run",
|
Arguments = "run -c config.json -format jsonv5",
|
||||||
coreUrl = Global.SagerNetCoreUrl,
|
Url = Global.V2flyCoreUrl,
|
||||||
coreReleaseApiUrl = Global.SagerNetCoreUrl.Replace(Global.GithubUrl, Global.GithubApiUrl),
|
ReleaseApiUrl = Global.V2flyCoreUrl.Replace(Global.GithubUrl, Global.GithubApiUrl),
|
||||||
match = "V2Ray",
|
Match = "V2Ray",
|
||||||
versionArg = "version",
|
VersionArg = "version",
|
||||||
redirectInfo = true,
|
RedirectInfo = true,
|
||||||
});
|
});
|
||||||
|
|
||||||
_coreInfo.Add(new CoreInfo
|
_coreInfo.Add(new CoreInfo
|
||||||
{
|
{
|
||||||
coreType = ECoreType.v2fly_v5,
|
CoreType = ECoreType.Xray,
|
||||||
coreExes = new List<string> { "v2ray" },
|
CoreExes = new List<string> { "xray", "wxray" },
|
||||||
arguments = "run -c config.json -format jsonv5",
|
Arguments = "run {0}",
|
||||||
coreUrl = Global.V2flyCoreUrl,
|
Url = Global.XrayCoreUrl,
|
||||||
coreReleaseApiUrl = Global.V2flyCoreUrl.Replace(Global.GithubUrl, Global.GithubApiUrl),
|
ReleaseApiUrl = Global.XrayCoreUrl.Replace(Global.GithubUrl, Global.GithubApiUrl),
|
||||||
match = "V2Ray",
|
DownloadUrlWin64 = Global.XrayCoreUrl + "/download/{0}/Xray-windows-64.zip",
|
||||||
versionArg = "version",
|
DownloadUrlWinArm64 = Global.XrayCoreUrl + "/download/{0}/Xray-windows-arm64-v8a.zip",
|
||||||
redirectInfo = true,
|
DownloadUrlLinux64 = Global.XrayCoreUrl + "/download/{0}/Xray-linux-64.zip",
|
||||||
|
DownloadUrlLinuxArm64 = Global.XrayCoreUrl + "/download/{0}/Xray-linux-arm64-v8a.zip",
|
||||||
|
Match = "Xray",
|
||||||
|
VersionArg = "-version",
|
||||||
|
RedirectInfo = true,
|
||||||
});
|
});
|
||||||
|
|
||||||
_coreInfo.Add(new CoreInfo
|
_coreInfo.Add(new CoreInfo
|
||||||
{
|
{
|
||||||
coreType = ECoreType.Xray,
|
CoreType = ECoreType.mihomo,
|
||||||
coreExes = new List<string> { "xray", "wxray" },
|
CoreExes = new List<string> { $"mihomo-windows-amd64{(Avx2.X64.IsSupported ? "" : "-compatible")}", "mihomo-windows-amd64-compatible", "mihomo-windows-amd64", "mihomo-windows-386", "mihomo", "clash" },
|
||||||
arguments = "run {0}",
|
Arguments = "-f config.json" + PortableMode(),
|
||||||
coreUrl = Global.XrayCoreUrl,
|
Url = Global.MihomoCoreUrl,
|
||||||
coreReleaseApiUrl = Global.XrayCoreUrl.Replace(Global.GithubUrl, Global.GithubApiUrl),
|
ReleaseApiUrl = Global.MihomoCoreUrl.Replace(Global.GithubUrl, Global.GithubApiUrl),
|
||||||
coreDownloadUrl32 = Global.XrayCoreUrl + "/download/{0}/Xray-windows-32.zip",
|
DownloadUrlWin64 = Global.MihomoCoreUrl + "/download/{0}/mihomo-windows-amd64-compatible-{0}.zip",
|
||||||
coreDownloadUrl64 = Global.XrayCoreUrl + "/download/{0}/Xray-windows-64.zip",
|
DownloadUrlWinArm64 = Global.MihomoCoreUrl + "/download/{0}/mihomo-windows-arm64-{0}.zip",
|
||||||
coreDownloadUrlArm64 = Global.XrayCoreUrl + "/download/{0}/Xray-windows-arm64-v8a.zip",
|
DownloadUrlLinux64 = Global.MihomoCoreUrl + "/download/{0}/mihomo-linux-amd64-compatible-{0}.gz",
|
||||||
coreDownloadUrlLinux32 = Global.XrayCoreUrl + "/download/{0}/Xray-linux-32.zip",
|
DownloadUrlLinuxArm64 = Global.MihomoCoreUrl + "/download/{0}/mihomo-linux-arm64-{0}.gz",
|
||||||
coreDownloadUrlLinux64 = Global.XrayCoreUrl + "/download/{0}/Xray-linux-64.zip",
|
Match = "Mihomo",
|
||||||
coreDownloadUrlLinuxArm64 = Global.XrayCoreUrl + "/download/{0}/Xray-linux-arm64-v8a.zip",
|
VersionArg = "-v",
|
||||||
match = "Xray",
|
RedirectInfo = true,
|
||||||
versionArg = "-version",
|
|
||||||
redirectInfo = true,
|
|
||||||
});
|
});
|
||||||
|
|
||||||
_coreInfo.Add(new CoreInfo
|
_coreInfo.Add(new CoreInfo
|
||||||
{
|
{
|
||||||
coreType = ECoreType.clash,
|
CoreType = ECoreType.hysteria,
|
||||||
coreExes = new List<string> { "clash-windows-amd64-v3", "clash-windows-amd64", "clash-windows-386", "clash" },
|
CoreExes = new List<string> { "hysteria-windows-amd64", "hysteria-windows-386", "hysteria" },
|
||||||
arguments = "-f config.json" + PortableMode(),
|
Arguments = "",
|
||||||
coreUrl = Global.ClashCoreUrl,
|
Url = Global.HysteriaCoreUrl,
|
||||||
coreReleaseApiUrl = Global.ClashCoreUrl.Replace(Global.GithubUrl, Global.GithubApiUrl),
|
ReleaseApiUrl = Global.HysteriaCoreUrl.Replace(Global.GithubUrl, Global.GithubApiUrl),
|
||||||
match = "v",
|
RedirectInfo = true,
|
||||||
versionArg = "-v",
|
|
||||||
redirectInfo = true,
|
|
||||||
});
|
});
|
||||||
|
|
||||||
_coreInfo.Add(new CoreInfo
|
_coreInfo.Add(new CoreInfo
|
||||||
{
|
{
|
||||||
coreType = ECoreType.clash_meta,
|
CoreType = ECoreType.naiveproxy,
|
||||||
coreExes = new List<string> { "Clash.Meta-windows-amd64-compatible", "Clash.Meta-windows-amd64", "Clash.Meta-windows-386", "Clash.Meta", "clash" },
|
CoreExes = new List<string> { "naiveproxy", "naive" },
|
||||||
arguments = "-f config.json" + PortableMode(),
|
Arguments = "config.json",
|
||||||
coreUrl = Global.ClashMetaCoreUrl,
|
Url = Global.NaiveproxyCoreUrl,
|
||||||
coreReleaseApiUrl = Global.ClashMetaCoreUrl.Replace(Global.GithubUrl, Global.GithubApiUrl),
|
RedirectInfo = false,
|
||||||
match = "v",
|
|
||||||
versionArg = "-v",
|
|
||||||
redirectInfo = true,
|
|
||||||
});
|
});
|
||||||
|
|
||||||
_coreInfo.Add(new CoreInfo
|
_coreInfo.Add(new CoreInfo
|
||||||
{
|
{
|
||||||
coreType = ECoreType.mihomo,
|
CoreType = ECoreType.tuic,
|
||||||
coreExes = new List<string> { $"mihomo-windows-amd64{(Avx2.X64.IsSupported ? "" : "-compatible")}", "mihomo-windows-amd64-compatible", "mihomo-windows-amd64", "mihomo-windows-386", "mihomo", "clash" },
|
CoreExes = new List<string> { "tuic-client", "tuic" },
|
||||||
arguments = "-f config.json" + PortableMode(),
|
Arguments = "-c config.json",
|
||||||
coreUrl = Global.MihomoCoreUrl,
|
Url = Global.TuicCoreUrl,
|
||||||
coreReleaseApiUrl = Global.MihomoCoreUrl.Replace(Global.GithubUrl, Global.GithubApiUrl),
|
RedirectInfo = true,
|
||||||
coreDownloadUrl32 = Global.ClashMetaCoreUrl + "/download/{0}/mihomo-windows-386-{0}.zip",
|
|
||||||
coreDownloadUrl64 = Global.ClashMetaCoreUrl + "/download/{0}/mihomo-windows-amd64-compatible-{0}.zip",
|
|
||||||
coreDownloadUrlArm64 = Global.ClashMetaCoreUrl + "/download/{0}/mihomo-windows-arm64-{0}.zip",
|
|
||||||
coreDownloadUrlLinux32 = Global.ClashMetaCoreUrl + "/download/{0}/mihomo-linux-386-{0}.gz",
|
|
||||||
coreDownloadUrlLinux64 = Global.ClashMetaCoreUrl + "/download/{0}/mihomo-linux-amd64-compatible-{0}.gz",
|
|
||||||
coreDownloadUrlLinuxArm64 = Global.ClashMetaCoreUrl + "/download/{0}/mihomo-linux-arm64-{0}.gz",
|
|
||||||
match = "Mihomo",
|
|
||||||
versionArg = "-v",
|
|
||||||
redirectInfo = true,
|
|
||||||
});
|
});
|
||||||
|
|
||||||
_coreInfo.Add(new CoreInfo
|
_coreInfo.Add(new CoreInfo
|
||||||
{
|
{
|
||||||
coreType = ECoreType.hysteria,
|
CoreType = ECoreType.sing_box,
|
||||||
coreExes = new List<string> { "hysteria-windows-amd64", "hysteria-windows-386", "hysteria" },
|
CoreExes = new List<string> { "sing-box-client", "sing-box" },
|
||||||
arguments = "",
|
Arguments = "run {0} --disable-color",
|
||||||
coreUrl = Global.HysteriaCoreUrl,
|
Url = Global.SingboxCoreUrl,
|
||||||
coreReleaseApiUrl = Global.HysteriaCoreUrl.Replace(Global.GithubUrl, Global.GithubApiUrl),
|
RedirectInfo = true,
|
||||||
redirectInfo = true,
|
ReleaseApiUrl = Global.SingboxCoreUrl.Replace(Global.GithubUrl, Global.GithubApiUrl),
|
||||||
|
DownloadUrlWin64 = Global.SingboxCoreUrl + "/download/{0}/sing-box-{1}-windows-amd64.zip",
|
||||||
|
DownloadUrlWinArm64 = Global.SingboxCoreUrl + "/download/{0}/sing-box-{1}-windows-arm64.zip",
|
||||||
|
DownloadUrlLinux64 = Global.SingboxCoreUrl + "/download/{0}/sing-box-{1}-linux-amd64.tar.gz",
|
||||||
|
DownloadUrlLinuxArm64 = Global.SingboxCoreUrl + "/download/{0}/sing-box-{1}-linux-arm64.tar.gz",
|
||||||
|
Match = "sing-box",
|
||||||
|
VersionArg = "version",
|
||||||
});
|
});
|
||||||
|
|
||||||
_coreInfo.Add(new CoreInfo
|
_coreInfo.Add(new CoreInfo
|
||||||
{
|
{
|
||||||
coreType = ECoreType.naiveproxy,
|
CoreType = ECoreType.juicity,
|
||||||
coreExes = new List<string> { "naiveproxy", "naive" },
|
CoreExes = new List<string> { "juicity-client", "juicity" },
|
||||||
arguments = "config.json",
|
Arguments = "run -c config.json",
|
||||||
coreUrl = Global.NaiveproxyCoreUrl,
|
Url = Global.JuicityCoreUrl
|
||||||
redirectInfo = false,
|
|
||||||
});
|
});
|
||||||
|
|
||||||
_coreInfo.Add(new CoreInfo
|
_coreInfo.Add(new CoreInfo
|
||||||
{
|
{
|
||||||
coreType = ECoreType.tuic,
|
CoreType = ECoreType.hysteria2,
|
||||||
coreExes = new List<string> { "tuic-client", "tuic" },
|
CoreExes = new List<string> { "hysteria-windows-amd64", "hysteria-windows-386", "hysteria" },
|
||||||
arguments = "-c config.json",
|
Arguments = "",
|
||||||
coreUrl = Global.TuicCoreUrl,
|
Url = Global.HysteriaCoreUrl,
|
||||||
redirectInfo = true,
|
ReleaseApiUrl = Global.HysteriaCoreUrl.Replace(Global.GithubUrl, Global.GithubApiUrl),
|
||||||
});
|
RedirectInfo = true,
|
||||||
|
|
||||||
_coreInfo.Add(new CoreInfo
|
|
||||||
{
|
|
||||||
coreType = ECoreType.sing_box,
|
|
||||||
coreExes = new List<string> { "sing-box-client", "sing-box" },
|
|
||||||
arguments = "run {0} --disable-color",
|
|
||||||
coreUrl = Global.SingboxCoreUrl,
|
|
||||||
redirectInfo = true,
|
|
||||||
coreReleaseApiUrl = Global.SingboxCoreUrl.Replace(Global.GithubUrl, Global.GithubApiUrl),
|
|
||||||
coreDownloadUrl32 = Global.SingboxCoreUrl + "/download/{0}/sing-box-{1}-windows-386.zip",
|
|
||||||
coreDownloadUrl64 = Global.SingboxCoreUrl + "/download/{0}/sing-box-{1}-windows-amd64.zip",
|
|
||||||
coreDownloadUrlArm64 = Global.SingboxCoreUrl + "/download/{0}/sing-box-{1}-windows-arm64.zip",
|
|
||||||
coreDownloadUrlLinux32 = Global.SingboxCoreUrl + "/download/{0}/sing-box-{1}-linux-386.tar.gz",
|
|
||||||
coreDownloadUrlLinux64 = Global.SingboxCoreUrl + "/download/{0}/sing-box-{1}-linux-amd64.tar.gz",
|
|
||||||
coreDownloadUrlLinuxArm64 = Global.SingboxCoreUrl + "/download/{0}/sing-box-{1}-linux-arm64.tar.gz",
|
|
||||||
match = "sing-box",
|
|
||||||
versionArg = "version",
|
|
||||||
});
|
|
||||||
|
|
||||||
_coreInfo.Add(new CoreInfo
|
|
||||||
{
|
|
||||||
coreType = ECoreType.juicity,
|
|
||||||
coreExes = new List<string> { "juicity-client", "juicity" },
|
|
||||||
arguments = "run -c config.json",
|
|
||||||
coreUrl = Global.JuicityCoreUrl
|
|
||||||
});
|
|
||||||
|
|
||||||
_coreInfo.Add(new CoreInfo
|
|
||||||
{
|
|
||||||
coreType = ECoreType.hysteria2,
|
|
||||||
coreExes = new List<string> { "hysteria-windows-amd64", "hysteria-windows-386", "hysteria" },
|
|
||||||
arguments = "",
|
|
||||||
coreUrl = Global.HysteriaCoreUrl,
|
|
||||||
coreReleaseApiUrl = Global.HysteriaCoreUrl.Replace(Global.GithubUrl, Global.GithubApiUrl),
|
|
||||||
redirectInfo = true,
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -16,14 +16,14 @@ namespace ServiceLib.Handler.Fmt
|
|||||||
|
|
||||||
protected static int GetStdTransport(ProfileItem item, string? securityDef, ref Dictionary<string, string> dicQuery)
|
protected static int GetStdTransport(ProfileItem item, string? securityDef, ref Dictionary<string, string> dicQuery)
|
||||||
{
|
{
|
||||||
if (!Utils.IsNullOrEmpty(item.flow))
|
if (Utils.IsNotEmpty(item.Flow))
|
||||||
{
|
{
|
||||||
dicQuery.Add("flow", item.flow);
|
dicQuery.Add("flow", item.Flow);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!Utils.IsNullOrEmpty(item.streamSecurity))
|
if (Utils.IsNotEmpty(item.StreamSecurity))
|
||||||
{
|
{
|
||||||
dicQuery.Add("security", item.streamSecurity);
|
dicQuery.Add("security", item.StreamSecurity);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -32,95 +32,95 @@ namespace ServiceLib.Handler.Fmt
|
|||||||
dicQuery.Add("security", securityDef);
|
dicQuery.Add("security", securityDef);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!Utils.IsNullOrEmpty(item.sni))
|
if (Utils.IsNotEmpty(item.Sni))
|
||||||
{
|
{
|
||||||
dicQuery.Add("sni", item.sni);
|
dicQuery.Add("sni", item.Sni);
|
||||||
}
|
}
|
||||||
if (!Utils.IsNullOrEmpty(item.alpn))
|
if (Utils.IsNotEmpty(item.Alpn))
|
||||||
{
|
{
|
||||||
dicQuery.Add("alpn", Utils.UrlEncode(item.alpn));
|
dicQuery.Add("alpn", Utils.UrlEncode(item.Alpn));
|
||||||
}
|
}
|
||||||
if (!Utils.IsNullOrEmpty(item.fingerprint))
|
if (Utils.IsNotEmpty(item.Fingerprint))
|
||||||
{
|
{
|
||||||
dicQuery.Add("fp", Utils.UrlEncode(item.fingerprint));
|
dicQuery.Add("fp", Utils.UrlEncode(item.Fingerprint));
|
||||||
}
|
}
|
||||||
if (!Utils.IsNullOrEmpty(item.publicKey))
|
if (Utils.IsNotEmpty(item.PublicKey))
|
||||||
{
|
{
|
||||||
dicQuery.Add("pbk", Utils.UrlEncode(item.publicKey));
|
dicQuery.Add("pbk", Utils.UrlEncode(item.PublicKey));
|
||||||
}
|
}
|
||||||
if (!Utils.IsNullOrEmpty(item.shortId))
|
if (Utils.IsNotEmpty(item.ShortId))
|
||||||
{
|
{
|
||||||
dicQuery.Add("sid", Utils.UrlEncode(item.shortId));
|
dicQuery.Add("sid", Utils.UrlEncode(item.ShortId));
|
||||||
}
|
}
|
||||||
if (!Utils.IsNullOrEmpty(item.spiderX))
|
if (Utils.IsNotEmpty(item.SpiderX))
|
||||||
{
|
{
|
||||||
dicQuery.Add("spx", Utils.UrlEncode(item.spiderX));
|
dicQuery.Add("spx", Utils.UrlEncode(item.SpiderX));
|
||||||
}
|
}
|
||||||
if (item.allowInsecure.Equals("true"))
|
if (item.AllowInsecure.Equals("true"))
|
||||||
{
|
{
|
||||||
dicQuery.Add("allowInsecure", "1");
|
dicQuery.Add("allowInsecure", "1");
|
||||||
}
|
}
|
||||||
|
|
||||||
dicQuery.Add("type", !Utils.IsNullOrEmpty(item.network) ? item.network : nameof(ETransport.tcp));
|
dicQuery.Add("type", Utils.IsNotEmpty(item.Network) ? item.Network : nameof(ETransport.tcp));
|
||||||
|
|
||||||
switch (item.network)
|
switch (item.Network)
|
||||||
{
|
{
|
||||||
case nameof(ETransport.tcp):
|
case nameof(ETransport.tcp):
|
||||||
dicQuery.Add("headerType", !Utils.IsNullOrEmpty(item.headerType) ? item.headerType : Global.None);
|
dicQuery.Add("headerType", Utils.IsNotEmpty(item.HeaderType) ? item.HeaderType : Global.None);
|
||||||
if (!Utils.IsNullOrEmpty(item.requestHost))
|
if (Utils.IsNotEmpty(item.RequestHost))
|
||||||
{
|
{
|
||||||
dicQuery.Add("host", Utils.UrlEncode(item.requestHost));
|
dicQuery.Add("host", Utils.UrlEncode(item.RequestHost));
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case nameof(ETransport.kcp):
|
case nameof(ETransport.kcp):
|
||||||
dicQuery.Add("headerType", !Utils.IsNullOrEmpty(item.headerType) ? item.headerType : Global.None);
|
dicQuery.Add("headerType", Utils.IsNotEmpty(item.HeaderType) ? item.HeaderType : Global.None);
|
||||||
if (!Utils.IsNullOrEmpty(item.path))
|
if (Utils.IsNotEmpty(item.Path))
|
||||||
{
|
{
|
||||||
dicQuery.Add("seed", Utils.UrlEncode(item.path));
|
dicQuery.Add("seed", Utils.UrlEncode(item.Path));
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case nameof(ETransport.ws):
|
case nameof(ETransport.ws):
|
||||||
case nameof(ETransport.httpupgrade):
|
case nameof(ETransport.httpupgrade):
|
||||||
case nameof(ETransport.splithttp):
|
case nameof(ETransport.splithttp):
|
||||||
if (!Utils.IsNullOrEmpty(item.requestHost))
|
if (Utils.IsNotEmpty(item.RequestHost))
|
||||||
{
|
{
|
||||||
dicQuery.Add("host", Utils.UrlEncode(item.requestHost));
|
dicQuery.Add("host", Utils.UrlEncode(item.RequestHost));
|
||||||
}
|
}
|
||||||
if (!Utils.IsNullOrEmpty(item.path))
|
if (Utils.IsNotEmpty(item.Path))
|
||||||
{
|
{
|
||||||
dicQuery.Add("path", Utils.UrlEncode(item.path));
|
dicQuery.Add("path", Utils.UrlEncode(item.Path));
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case nameof(ETransport.http):
|
case nameof(ETransport.http):
|
||||||
case nameof(ETransport.h2):
|
case nameof(ETransport.h2):
|
||||||
dicQuery["type"] = nameof(ETransport.http);
|
dicQuery["type"] = nameof(ETransport.http);
|
||||||
if (!Utils.IsNullOrEmpty(item.requestHost))
|
if (Utils.IsNotEmpty(item.RequestHost))
|
||||||
{
|
{
|
||||||
dicQuery.Add("host", Utils.UrlEncode(item.requestHost));
|
dicQuery.Add("host", Utils.UrlEncode(item.RequestHost));
|
||||||
}
|
}
|
||||||
if (!Utils.IsNullOrEmpty(item.path))
|
if (Utils.IsNotEmpty(item.Path))
|
||||||
{
|
{
|
||||||
dicQuery.Add("path", Utils.UrlEncode(item.path));
|
dicQuery.Add("path", Utils.UrlEncode(item.Path));
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case nameof(ETransport.quic):
|
case nameof(ETransport.quic):
|
||||||
dicQuery.Add("headerType", !Utils.IsNullOrEmpty(item.headerType) ? item.headerType : Global.None);
|
dicQuery.Add("headerType", Utils.IsNotEmpty(item.HeaderType) ? item.HeaderType : Global.None);
|
||||||
dicQuery.Add("quicSecurity", Utils.UrlEncode(item.requestHost));
|
dicQuery.Add("quicSecurity", Utils.UrlEncode(item.RequestHost));
|
||||||
dicQuery.Add("key", Utils.UrlEncode(item.path));
|
dicQuery.Add("key", Utils.UrlEncode(item.Path));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case nameof(ETransport.grpc):
|
case nameof(ETransport.grpc):
|
||||||
if (!Utils.IsNullOrEmpty(item.path))
|
if (Utils.IsNotEmpty(item.Path))
|
||||||
{
|
{
|
||||||
dicQuery.Add("authority", Utils.UrlEncode(item.requestHost));
|
dicQuery.Add("authority", Utils.UrlEncode(item.RequestHost));
|
||||||
dicQuery.Add("serviceName", Utils.UrlEncode(item.path));
|
dicQuery.Add("serviceName", Utils.UrlEncode(item.Path));
|
||||||
if (item.headerType is Global.GrpcGunMode or Global.GrpcMultiMode)
|
if (item.HeaderType is Global.GrpcGunMode or Global.GrpcMultiMode)
|
||||||
{
|
{
|
||||||
dicQuery.Add("mode", Utils.UrlEncode(item.headerType));
|
dicQuery.Add("mode", Utils.UrlEncode(item.HeaderType));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@@ -130,54 +130,54 @@ namespace ServiceLib.Handler.Fmt
|
|||||||
|
|
||||||
protected static int ResolveStdTransport(NameValueCollection query, ref ProfileItem item)
|
protected static int ResolveStdTransport(NameValueCollection query, ref ProfileItem item)
|
||||||
{
|
{
|
||||||
item.flow = query["flow"] ?? "";
|
item.Flow = query["flow"] ?? "";
|
||||||
item.streamSecurity = query["security"] ?? "";
|
item.StreamSecurity = query["security"] ?? "";
|
||||||
item.sni = query["sni"] ?? "";
|
item.Sni = query["sni"] ?? "";
|
||||||
item.alpn = Utils.UrlDecode(query["alpn"] ?? "");
|
item.Alpn = Utils.UrlDecode(query["alpn"] ?? "");
|
||||||
item.fingerprint = Utils.UrlDecode(query["fp"] ?? "");
|
item.Fingerprint = Utils.UrlDecode(query["fp"] ?? "");
|
||||||
item.publicKey = Utils.UrlDecode(query["pbk"] ?? "");
|
item.PublicKey = Utils.UrlDecode(query["pbk"] ?? "");
|
||||||
item.shortId = Utils.UrlDecode(query["sid"] ?? "");
|
item.ShortId = Utils.UrlDecode(query["sid"] ?? "");
|
||||||
item.spiderX = Utils.UrlDecode(query["spx"] ?? "");
|
item.SpiderX = Utils.UrlDecode(query["spx"] ?? "");
|
||||||
item.allowInsecure = (query["allowInsecure"] ?? "") == "1" ? "true" : "";
|
item.AllowInsecure = (query["allowInsecure"] ?? "") == "1" ? "true" : "";
|
||||||
|
|
||||||
item.network = query["type"] ?? nameof(ETransport.tcp);
|
item.Network = query["type"] ?? nameof(ETransport.tcp);
|
||||||
switch (item.network)
|
switch (item.Network)
|
||||||
{
|
{
|
||||||
case nameof(ETransport.tcp):
|
case nameof(ETransport.tcp):
|
||||||
item.headerType = query["headerType"] ?? Global.None;
|
item.HeaderType = query["headerType"] ?? Global.None;
|
||||||
item.requestHost = Utils.UrlDecode(query["host"] ?? "");
|
item.RequestHost = Utils.UrlDecode(query["host"] ?? "");
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case nameof(ETransport.kcp):
|
case nameof(ETransport.kcp):
|
||||||
item.headerType = query["headerType"] ?? Global.None;
|
item.HeaderType = query["headerType"] ?? Global.None;
|
||||||
item.path = Utils.UrlDecode(query["seed"] ?? "");
|
item.Path = Utils.UrlDecode(query["seed"] ?? "");
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case nameof(ETransport.ws):
|
case nameof(ETransport.ws):
|
||||||
case nameof(ETransport.httpupgrade):
|
case nameof(ETransport.httpupgrade):
|
||||||
case nameof(ETransport.splithttp):
|
case nameof(ETransport.splithttp):
|
||||||
item.requestHost = Utils.UrlDecode(query["host"] ?? "");
|
item.RequestHost = Utils.UrlDecode(query["host"] ?? "");
|
||||||
item.path = Utils.UrlDecode(query["path"] ?? "/");
|
item.Path = Utils.UrlDecode(query["path"] ?? "/");
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case nameof(ETransport.http):
|
case nameof(ETransport.http):
|
||||||
case nameof(ETransport.h2):
|
case nameof(ETransport.h2):
|
||||||
item.network = nameof(ETransport.h2);
|
item.Network = nameof(ETransport.h2);
|
||||||
item.requestHost = Utils.UrlDecode(query["host"] ?? "");
|
item.RequestHost = Utils.UrlDecode(query["host"] ?? "");
|
||||||
item.path = Utils.UrlDecode(query["path"] ?? "/");
|
item.Path = Utils.UrlDecode(query["path"] ?? "/");
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case nameof(ETransport.quic):
|
case nameof(ETransport.quic):
|
||||||
item.headerType = query["headerType"] ?? Global.None;
|
item.HeaderType = query["headerType"] ?? Global.None;
|
||||||
item.requestHost = query["quicSecurity"] ?? Global.None;
|
item.RequestHost = query["quicSecurity"] ?? Global.None;
|
||||||
item.path = Utils.UrlDecode(query["key"] ?? "");
|
item.Path = Utils.UrlDecode(query["key"] ?? "");
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case nameof(ETransport.grpc):
|
case nameof(ETransport.grpc):
|
||||||
item.requestHost = Utils.UrlDecode(query["authority"] ?? "");
|
item.RequestHost = Utils.UrlDecode(query["authority"] ?? "");
|
||||||
item.path = Utils.UrlDecode(query["serviceName"] ?? "");
|
item.Path = Utils.UrlDecode(query["serviceName"] ?? "");
|
||||||
item.headerType = Utils.UrlDecode(query["mode"] ?? Global.GrpcGunMode);
|
item.HeaderType = Utils.UrlDecode(query["mode"] ?? Global.GrpcGunMode);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
@@ -197,9 +197,19 @@ namespace ServiceLib.Handler.Fmt
|
|||||||
|
|
||||||
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)
|
||||||
|
{
|
||||||
|
var query = dicQuery != null
|
||||||
|
? ("?" + string.Join("&", dicQuery.Select(x => x.Key + "=" + x.Value).ToArray()))
|
||||||
|
: string.Empty;
|
||||||
|
|
||||||
|
var url = $"{Utils.UrlEncode(userInfo)}@{GetIpv6(address)}:{port}";
|
||||||
|
return $"{Global.ProtocolShares[eConfigType]}{url}{query}{remark}";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -10,9 +10,9 @@
|
|||||||
|
|
||||||
var profileItem = new ProfileItem
|
var profileItem = new ProfileItem
|
||||||
{
|
{
|
||||||
coreType = ECoreType.mihomo,
|
CoreType = ECoreType.mihomo,
|
||||||
address = fileName,
|
Address = fileName,
|
||||||
remarks = subRemarks ?? "clash_custom"
|
Remarks = subRemarks ?? "clash_custom"
|
||||||
};
|
};
|
||||||
return profileItem;
|
return profileItem;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,16 +6,16 @@
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var url = item.configType switch
|
var url = item.ConfigType switch
|
||||||
{
|
{
|
||||||
EConfigType.VMess => VmessFmt.ToUri(item),
|
EConfigType.VMess => VmessFmt.ToUri(item),
|
||||||
EConfigType.Shadowsocks => ShadowsocksFmt.ToUri(item),
|
EConfigType.Shadowsocks => ShadowsocksFmt.ToUri(item),
|
||||||
EConfigType.Socks => SocksFmt.ToUri(item),
|
EConfigType.SOCKS => SocksFmt.ToUri(item),
|
||||||
EConfigType.Trojan => TrojanFmt.ToUri(item),
|
EConfigType.Trojan => TrojanFmt.ToUri(item),
|
||||||
EConfigType.VLESS => VLESSFmt.ToUri(item),
|
EConfigType.VLESS => VLESSFmt.ToUri(item),
|
||||||
EConfigType.Hysteria2 => Hysteria2Fmt.ToUri(item),
|
EConfigType.Hysteria2 => Hysteria2Fmt.ToUri(item),
|
||||||
EConfigType.Tuic => TuicFmt.ToUri(item),
|
EConfigType.TUIC => TuicFmt.ToUri(item),
|
||||||
EConfigType.Wireguard => WireguardFmt.ToUri(item),
|
EConfigType.WireGuard => WireguardFmt.ToUri(item),
|
||||||
_ => null,
|
_ => null,
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -49,7 +49,7 @@
|
|||||||
{
|
{
|
||||||
return ShadowsocksFmt.Resolve(str, out msg);
|
return ShadowsocksFmt.Resolve(str, out msg);
|
||||||
}
|
}
|
||||||
else if (str.StartsWith(Global.ProtocolShares[EConfigType.Socks]))
|
else if (str.StartsWith(Global.ProtocolShares[EConfigType.SOCKS]))
|
||||||
{
|
{
|
||||||
return SocksFmt.Resolve(str, out msg);
|
return SocksFmt.Resolve(str, out msg);
|
||||||
}
|
}
|
||||||
@@ -65,11 +65,11 @@
|
|||||||
{
|
{
|
||||||
return Hysteria2Fmt.Resolve(str, out msg);
|
return Hysteria2Fmt.Resolve(str, out msg);
|
||||||
}
|
}
|
||||||
else if (str.StartsWith(Global.ProtocolShares[EConfigType.Tuic]))
|
else if (str.StartsWith(Global.ProtocolShares[EConfigType.TUIC]))
|
||||||
{
|
{
|
||||||
return TuicFmt.Resolve(str, out msg);
|
return TuicFmt.Resolve(str, out msg);
|
||||||
}
|
}
|
||||||
else if (str.StartsWith(Global.ProtocolShares[EConfigType.Wireguard]))
|
else if (str.StartsWith(Global.ProtocolShares[EConfigType.WireGuard]))
|
||||||
{
|
{
|
||||||
return WireguardFmt.Resolve(str, out msg);
|
return WireguardFmt.Resolve(str, out msg);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,20 +7,21 @@
|
|||||||
msg = ResUI.ConfigurationFormatIncorrect;
|
msg = ResUI.ConfigurationFormatIncorrect;
|
||||||
ProfileItem item = new()
|
ProfileItem item = new()
|
||||||
{
|
{
|
||||||
configType = EConfigType.Hysteria2
|
ConfigType = EConfigType.Hysteria2
|
||||||
};
|
};
|
||||||
|
|
||||||
Uri url = new(str);
|
var url = Utils.TryUri(str);
|
||||||
|
if (url == null) return null;
|
||||||
|
|
||||||
item.address = url.IdnHost;
|
item.Address = url.IdnHost;
|
||||||
item.port = url.Port;
|
item.Port = url.Port;
|
||||||
item.remarks = url.GetComponents(UriComponents.Fragment, UriFormat.Unescaped);
|
item.Remarks = url.GetComponents(UriComponents.Fragment, UriFormat.Unescaped);
|
||||||
item.id = Utils.UrlDecode(url.UserInfo);
|
item.Id = Utils.UrlDecode(url.UserInfo);
|
||||||
|
|
||||||
var query = Utils.ParseQueryString(url.Query);
|
var query = Utils.ParseQueryString(url.Query);
|
||||||
ResolveStdTransport(query, ref item);
|
ResolveStdTransport(query, ref item);
|
||||||
item.path = Utils.UrlDecode(query["obfs-password"] ?? "");
|
item.Path = Utils.UrlDecode(query["obfs-password"] ?? "");
|
||||||
item.allowInsecure = (query["insecure"] ?? "") == "1" ? "true" : "false";
|
item.AllowInsecure = (query["insecure"] ?? "") == "1" ? "true" : "false";
|
||||||
|
|
||||||
return item;
|
return item;
|
||||||
}
|
}
|
||||||
@@ -31,34 +32,27 @@
|
|||||||
string url = string.Empty;
|
string url = string.Empty;
|
||||||
|
|
||||||
string remark = string.Empty;
|
string remark = string.Empty;
|
||||||
if (!Utils.IsNullOrEmpty(item.remarks))
|
if (Utils.IsNotEmpty(item.Remarks))
|
||||||
{
|
{
|
||||||
remark = "#" + Utils.UrlEncode(item.remarks);
|
remark = "#" + Utils.UrlEncode(item.Remarks);
|
||||||
}
|
}
|
||||||
var dicQuery = new Dictionary<string, string>();
|
var dicQuery = new Dictionary<string, string>();
|
||||||
if (!Utils.IsNullOrEmpty(item.sni))
|
if (Utils.IsNotEmpty(item.Sni))
|
||||||
{
|
{
|
||||||
dicQuery.Add("sni", item.sni);
|
dicQuery.Add("sni", item.Sni);
|
||||||
}
|
}
|
||||||
if (!Utils.IsNullOrEmpty(item.alpn))
|
if (Utils.IsNotEmpty(item.Alpn))
|
||||||
{
|
{
|
||||||
dicQuery.Add("alpn", Utils.UrlEncode(item.alpn));
|
dicQuery.Add("alpn", Utils.UrlEncode(item.Alpn));
|
||||||
}
|
}
|
||||||
if (!Utils.IsNullOrEmpty(item.path))
|
if (Utils.IsNotEmpty(item.Path))
|
||||||
{
|
{
|
||||||
dicQuery.Add("obfs", "salamander");
|
dicQuery.Add("obfs", "salamander");
|
||||||
dicQuery.Add("obfs-password", Utils.UrlEncode(item.path));
|
dicQuery.Add("obfs-password", Utils.UrlEncode(item.Path));
|
||||||
}
|
}
|
||||||
dicQuery.Add("insecure", item.allowInsecure.ToLower() == "true" ? "1" : "0");
|
dicQuery.Add("insecure", item.AllowInsecure.ToLower() == "true" ? "1" : "0");
|
||||||
|
|
||||||
string query = "?" + string.Join("&", dicQuery.Select(x => x.Key + "=" + x.Value).ToArray());
|
return ToUri(EConfigType.Hysteria2, item.Address, item.Port, item.Id, dicQuery, remark);
|
||||||
|
|
||||||
url = string.Format("{0}@{1}:{2}",
|
|
||||||
item.id,
|
|
||||||
GetIpv6(item.address),
|
|
||||||
item.port);
|
|
||||||
url = $"{Global.ProtocolShares[EConfigType.Hysteria2]}{url}/{query}{remark}";
|
|
||||||
return url;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static ProfileItem? ResolveFull(string strData, string? subRemarks)
|
public static ProfileItem? ResolveFull(string strData, string? subRemarks)
|
||||||
@@ -69,9 +63,9 @@
|
|||||||
|
|
||||||
var profileItem = new ProfileItem
|
var profileItem = new ProfileItem
|
||||||
{
|
{
|
||||||
coreType = ECoreType.hysteria,
|
CoreType = ECoreType.hysteria,
|
||||||
address = fileName,
|
Address = fileName,
|
||||||
remarks = subRemarks ?? "hysteria_custom"
|
Remarks = subRemarks ?? "hysteria_custom"
|
||||||
};
|
};
|
||||||
return profileItem;
|
return profileItem;
|
||||||
}
|
}
|
||||||
@@ -87,9 +81,9 @@
|
|||||||
|
|
||||||
var profileItem = new ProfileItem
|
var profileItem = new ProfileItem
|
||||||
{
|
{
|
||||||
coreType = ECoreType.hysteria2,
|
CoreType = ECoreType.hysteria2,
|
||||||
address = fileName,
|
Address = fileName,
|
||||||
remarks = subRemarks ?? "hysteria2_custom"
|
Remarks = subRemarks ?? "hysteria2_custom"
|
||||||
};
|
};
|
||||||
return profileItem;
|
return profileItem;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,9 +10,9 @@
|
|||||||
|
|
||||||
var profileItem = new ProfileItem
|
var profileItem = new ProfileItem
|
||||||
{
|
{
|
||||||
coreType = ECoreType.naiveproxy,
|
CoreType = ECoreType.naiveproxy,
|
||||||
address = fileName,
|
Address = fileName,
|
||||||
remarks = subRemarks ?? "naiveproxy_custom"
|
Remarks = subRemarks ?? "naiveproxy_custom"
|
||||||
};
|
};
|
||||||
return profileItem;
|
return profileItem;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,12 +14,12 @@ namespace ServiceLib.Handler.Fmt
|
|||||||
{
|
{
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
if (item.address.Length == 0 || item.port == 0 || item.security.Length == 0 || item.id.Length == 0)
|
if (item.Address.Length == 0 || item.Port == 0 || item.Security.Length == 0 || item.Id.Length == 0)
|
||||||
{
|
{
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
item.configType = EConfigType.Shadowsocks;
|
item.ConfigType = EConfigType.Shadowsocks;
|
||||||
|
|
||||||
return item;
|
return item;
|
||||||
}
|
}
|
||||||
@@ -30,9 +30,9 @@ namespace ServiceLib.Handler.Fmt
|
|||||||
string url = string.Empty;
|
string url = string.Empty;
|
||||||
|
|
||||||
string remark = string.Empty;
|
string remark = string.Empty;
|
||||||
if (!Utils.IsNullOrEmpty(item.remarks))
|
if (Utils.IsNotEmpty(item.Remarks))
|
||||||
{
|
{
|
||||||
remark = "#" + Utils.UrlEncode(item.remarks);
|
remark = "#" + Utils.UrlEncode(item.Remarks);
|
||||||
}
|
}
|
||||||
//url = string.Format("{0}:{1}@{2}:{3}",
|
//url = string.Format("{0}:{1}@{2}:{3}",
|
||||||
// item.security,
|
// item.security,
|
||||||
@@ -41,10 +41,8 @@ namespace ServiceLib.Handler.Fmt
|
|||||||
// item.port);
|
// item.port);
|
||||||
//url = Utile.Base64Encode(url);
|
//url = Utile.Base64Encode(url);
|
||||||
//new Sip002
|
//new Sip002
|
||||||
var pw = Utils.Base64Encode($"{item.security}:{item.id}");
|
var pw = Utils.Base64Encode($"{item.Security}:{item.Id}");
|
||||||
url = $"{pw}@{GetIpv6(item.address)}:{item.port}";
|
return ToUri(EConfigType.Shadowsocks, item.Address, item.Port, pw, null, remark);
|
||||||
url = $"{Global.ProtocolShares[EConfigType.Shadowsocks]}{url}{remark}";
|
|
||||||
return url;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static readonly Regex UrlFinder = new(@"ss://(?<base64>[A-Za-z0-9+-/=_]+)(?:#(?<tag>\S+))?", RegexOptions.IgnoreCase | RegexOptions.Compiled);
|
private static readonly Regex UrlFinder = new(@"ss://(?<base64>[A-Za-z0-9+-/=_]+)(?:#(?<tag>\S+))?", RegexOptions.IgnoreCase | RegexOptions.Compiled);
|
||||||
@@ -59,9 +57,9 @@ namespace ServiceLib.Handler.Fmt
|
|||||||
ProfileItem item = new();
|
ProfileItem item = new();
|
||||||
var base64 = match.Groups["base64"].Value.TrimEnd('/');
|
var base64 = match.Groups["base64"].Value.TrimEnd('/');
|
||||||
var tag = match.Groups["tag"].Value;
|
var tag = match.Groups["tag"].Value;
|
||||||
if (!Utils.IsNullOrEmpty(tag))
|
if (Utils.IsNotEmpty(tag))
|
||||||
{
|
{
|
||||||
item.remarks = Utils.UrlDecode(tag);
|
item.Remarks = Utils.UrlDecode(tag);
|
||||||
}
|
}
|
||||||
Match details;
|
Match details;
|
||||||
try
|
try
|
||||||
@@ -74,31 +72,25 @@ namespace ServiceLib.Handler.Fmt
|
|||||||
}
|
}
|
||||||
if (!details.Success)
|
if (!details.Success)
|
||||||
return null;
|
return null;
|
||||||
item.security = details.Groups["method"].Value;
|
item.Security = details.Groups["method"].Value;
|
||||||
item.id = details.Groups["password"].Value;
|
item.Id = details.Groups["password"].Value;
|
||||||
item.address = details.Groups["hostname"].Value;
|
item.Address = details.Groups["hostname"].Value;
|
||||||
item.port = Utils.ToInt(details.Groups["port"].Value);
|
item.Port = Utils.ToInt(details.Groups["port"].Value);
|
||||||
return item;
|
return item;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static ProfileItem? ResolveSip002(string result)
|
private static ProfileItem? ResolveSip002(string result)
|
||||||
{
|
{
|
||||||
Uri parsedUrl;
|
var parsedUrl = Utils.TryUri(result);
|
||||||
try
|
if (parsedUrl == null) return null;
|
||||||
{
|
|
||||||
parsedUrl = new Uri(result);
|
|
||||||
}
|
|
||||||
catch (UriFormatException)
|
|
||||||
{
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
ProfileItem item = new()
|
ProfileItem item = new()
|
||||||
{
|
{
|
||||||
remarks = parsedUrl.GetComponents(UriComponents.Fragment, UriFormat.Unescaped),
|
Remarks = parsedUrl.GetComponents(UriComponents.Fragment, UriFormat.Unescaped),
|
||||||
address = parsedUrl.IdnHost,
|
Address = parsedUrl.IdnHost,
|
||||||
port = parsedUrl.Port,
|
Port = parsedUrl.Port,
|
||||||
};
|
};
|
||||||
string rawUserInfo = parsedUrl.GetComponents(UriComponents.UserInfo, UriFormat.UriEscaped);
|
var rawUserInfo = Utils.UrlDecode(parsedUrl.UserInfo);
|
||||||
//2022-blake3
|
//2022-blake3
|
||||||
if (rawUserInfo.Contains(':'))
|
if (rawUserInfo.Contains(':'))
|
||||||
{
|
{
|
||||||
@@ -107,8 +99,8 @@ namespace ServiceLib.Handler.Fmt
|
|||||||
{
|
{
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
item.security = userInfoParts[0];
|
item.Security = userInfoParts[0];
|
||||||
item.id = Utils.UrlDecode(userInfoParts[1]);
|
item.Id = Utils.UrlDecode(userInfoParts[1]);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -119,8 +111,8 @@ namespace ServiceLib.Handler.Fmt
|
|||||||
{
|
{
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
item.security = userInfoParts[0];
|
item.Security = userInfoParts[0];
|
||||||
item.id = userInfoParts[1];
|
item.Id = userInfoParts[1];
|
||||||
}
|
}
|
||||||
|
|
||||||
var queryParameters = Utils.ParseQueryString(parsedUrl.Query);
|
var queryParameters = Utils.ParseQueryString(parsedUrl.Query);
|
||||||
@@ -128,12 +120,12 @@ namespace ServiceLib.Handler.Fmt
|
|||||||
{
|
{
|
||||||
//obfs-host exists
|
//obfs-host exists
|
||||||
var obfsHost = queryParameters["plugin"]?.Split(';').FirstOrDefault(t => t.Contains("obfs-host"));
|
var obfsHost = queryParameters["plugin"]?.Split(';').FirstOrDefault(t => t.Contains("obfs-host"));
|
||||||
if (queryParameters["plugin"].Contains("obfs=http") && !Utils.IsNullOrEmpty(obfsHost))
|
if (queryParameters["plugin"].Contains("obfs=http") && Utils.IsNotEmpty(obfsHost))
|
||||||
{
|
{
|
||||||
obfsHost = obfsHost?.Replace("obfs-host=", "");
|
obfsHost = obfsHost?.Replace("obfs-host=", "");
|
||||||
item.network = Global.DefaultNetwork;
|
item.Network = Global.DefaultNetwork;
|
||||||
item.headerType = Global.TcpHeaderHttp;
|
item.HeaderType = Global.TcpHeaderHttp;
|
||||||
item.requestHost = obfsHost ?? "";
|
item.RequestHost = obfsHost ?? "";
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -164,11 +156,11 @@ namespace ServiceLib.Handler.Fmt
|
|||||||
{
|
{
|
||||||
var ssItem = new ProfileItem()
|
var ssItem = new ProfileItem()
|
||||||
{
|
{
|
||||||
remarks = it.remarks,
|
Remarks = it.remarks,
|
||||||
security = it.method,
|
Security = it.method,
|
||||||
id = it.password,
|
Id = it.password,
|
||||||
address = it.server,
|
Address = it.server,
|
||||||
port = Utils.ToInt(it.server_port)
|
Port = Utils.ToInt(it.server_port)
|
||||||
};
|
};
|
||||||
lst.Add(ssItem);
|
lst.Add(ssItem);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,9 +20,9 @@
|
|||||||
|
|
||||||
var profileIt = new ProfileItem
|
var profileIt = new ProfileItem
|
||||||
{
|
{
|
||||||
coreType = ECoreType.sing_box,
|
CoreType = ECoreType.sing_box,
|
||||||
address = fileName,
|
Address = fileName,
|
||||||
remarks = subRemarks ?? "singbox_custom",
|
Remarks = subRemarks ?? "singbox_custom",
|
||||||
};
|
};
|
||||||
lstResult.Add(profileIt);
|
lstResult.Add(profileIt);
|
||||||
}
|
}
|
||||||
@@ -42,9 +42,9 @@
|
|||||||
var fileName = WriteAllText(strData);
|
var fileName = WriteAllText(strData);
|
||||||
var profileItem = new ProfileItem
|
var profileItem = new ProfileItem
|
||||||
{
|
{
|
||||||
coreType = ECoreType.sing_box,
|
CoreType = ECoreType.sing_box,
|
||||||
address = fileName,
|
Address = fileName,
|
||||||
remarks = subRemarks ?? "singbox_custom"
|
Remarks = subRemarks ?? "singbox_custom"
|
||||||
};
|
};
|
||||||
|
|
||||||
return profileItem;
|
return profileItem;
|
||||||
|
|||||||
@@ -12,12 +12,12 @@
|
|||||||
{
|
{
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
if (item.address.Length == 0 || item.port == 0)
|
if (item.Address.Length == 0 || item.Port == 0)
|
||||||
{
|
{
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
item.configType = EConfigType.Socks;
|
item.ConfigType = EConfigType.SOCKS;
|
||||||
|
|
||||||
return item;
|
return item;
|
||||||
}
|
}
|
||||||
@@ -28,9 +28,9 @@
|
|||||||
string url = string.Empty;
|
string url = string.Empty;
|
||||||
|
|
||||||
string remark = string.Empty;
|
string remark = string.Empty;
|
||||||
if (!Utils.IsNullOrEmpty(item.remarks))
|
if (Utils.IsNotEmpty(item.Remarks))
|
||||||
{
|
{
|
||||||
remark = "#" + Utils.UrlEncode(item.remarks);
|
remark = "#" + Utils.UrlEncode(item.Remarks);
|
||||||
}
|
}
|
||||||
//url = string.Format("{0}:{1}@{2}:{3}",
|
//url = string.Format("{0}:{1}@{2}:{3}",
|
||||||
// item.security,
|
// item.security,
|
||||||
@@ -39,26 +39,24 @@
|
|||||||
// item.port);
|
// item.port);
|
||||||
//url = Utile.Base64Encode(url);
|
//url = Utile.Base64Encode(url);
|
||||||
//new
|
//new
|
||||||
var pw = Utils.Base64Encode($"{item.security}:{item.id}");
|
var pw = Utils.Base64Encode($"{item.Security}:{item.Id}");
|
||||||
url = $"{pw}@{GetIpv6(item.address)}:{item.port}";
|
return ToUri(EConfigType.SOCKS, item.Address, item.Port, pw, null, remark);
|
||||||
url = $"{Global.ProtocolShares[EConfigType.Socks]}{url}{remark}";
|
|
||||||
return url;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static ProfileItem? ResolveSocks(string result)
|
private static ProfileItem? ResolveSocks(string result)
|
||||||
{
|
{
|
||||||
ProfileItem item = new()
|
ProfileItem item = new()
|
||||||
{
|
{
|
||||||
configType = EConfigType.Socks
|
ConfigType = EConfigType.SOCKS
|
||||||
};
|
};
|
||||||
result = result[Global.ProtocolShares[EConfigType.Socks].Length..];
|
result = result[Global.ProtocolShares[EConfigType.SOCKS].Length..];
|
||||||
//remark
|
//remark
|
||||||
int indexRemark = result.IndexOf("#");
|
int indexRemark = result.IndexOf("#");
|
||||||
if (indexRemark > 0)
|
if (indexRemark > 0)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
item.remarks = Utils.UrlDecode(result.Substring(indexRemark + 1, result.Length - indexRemark - 1));
|
item.Remarks = Utils.UrlDecode(result.Substring(indexRemark + 1, result.Length - indexRemark - 1));
|
||||||
}
|
}
|
||||||
catch { }
|
catch { }
|
||||||
result = result[..indexRemark];
|
result = result[..indexRemark];
|
||||||
@@ -85,40 +83,34 @@
|
|||||||
{
|
{
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
item.address = arr1[1][..indexPort];
|
item.Address = arr1[1][..indexPort];
|
||||||
item.port = Utils.ToInt(arr1[1][(indexPort + 1)..]);
|
item.Port = Utils.ToInt(arr1[1][(indexPort + 1)..]);
|
||||||
item.security = arr21[0];
|
item.Security = arr21[0];
|
||||||
item.id = arr21[1];
|
item.Id = arr21[1];
|
||||||
|
|
||||||
return item;
|
return item;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static ProfileItem? ResolveSocksNew(string result)
|
private static ProfileItem? ResolveSocksNew(string result)
|
||||||
{
|
{
|
||||||
Uri parsedUrl;
|
var parsedUrl = Utils.TryUri(result);
|
||||||
try
|
if (parsedUrl == null) return null;
|
||||||
{
|
|
||||||
parsedUrl = new Uri(result);
|
|
||||||
}
|
|
||||||
catch (UriFormatException)
|
|
||||||
{
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
ProfileItem item = new()
|
ProfileItem item = new()
|
||||||
{
|
{
|
||||||
remarks = parsedUrl.GetComponents(UriComponents.Fragment, UriFormat.Unescaped),
|
Remarks = parsedUrl.GetComponents(UriComponents.Fragment, UriFormat.Unescaped),
|
||||||
address = parsedUrl.IdnHost,
|
Address = parsedUrl.IdnHost,
|
||||||
port = parsedUrl.Port,
|
Port = parsedUrl.Port,
|
||||||
};
|
};
|
||||||
|
|
||||||
// parse base64 UserInfo
|
// parse base64 UserInfo
|
||||||
string rawUserInfo = parsedUrl.GetComponents(UriComponents.UserInfo, UriFormat.Unescaped);
|
var rawUserInfo = Utils.UrlDecode(parsedUrl.UserInfo);
|
||||||
string userInfo = Utils.Base64Decode(rawUserInfo);
|
var userInfo = Utils.Base64Decode(rawUserInfo);
|
||||||
string[] userInfoParts = userInfo.Split(new[] { ':' }, 2);
|
var userInfoParts = userInfo.Split(new[] { ':' }, 2);
|
||||||
if (userInfoParts.Length == 2)
|
if (userInfoParts.Length == 2)
|
||||||
{
|
{
|
||||||
item.security = userInfoParts[0];
|
item.Security = userInfoParts[0];
|
||||||
item.id = userInfoParts[1];
|
item.Id = userInfoParts[1];
|
||||||
}
|
}
|
||||||
|
|
||||||
return item;
|
return item;
|
||||||
|
|||||||
@@ -8,15 +8,16 @@
|
|||||||
|
|
||||||
ProfileItem item = new()
|
ProfileItem item = new()
|
||||||
{
|
{
|
||||||
configType = EConfigType.Trojan
|
ConfigType = EConfigType.Trojan
|
||||||
};
|
};
|
||||||
|
|
||||||
Uri url = new(str);
|
var url = Utils.TryUri(str);
|
||||||
|
if (url == null) return null;
|
||||||
|
|
||||||
item.address = url.IdnHost;
|
item.Address = url.IdnHost;
|
||||||
item.port = url.Port;
|
item.Port = url.Port;
|
||||||
item.remarks = url.GetComponents(UriComponents.Fragment, UriFormat.Unescaped);
|
item.Remarks = url.GetComponents(UriComponents.Fragment, UriFormat.Unescaped);
|
||||||
item.id = Utils.UrlDecode(url.UserInfo);
|
item.Id = Utils.UrlDecode(url.UserInfo);
|
||||||
|
|
||||||
var query = Utils.ParseQueryString(url.Query);
|
var query = Utils.ParseQueryString(url.Query);
|
||||||
ResolveStdTransport(query, ref item);
|
ResolveStdTransport(query, ref item);
|
||||||
@@ -30,20 +31,14 @@
|
|||||||
string url = string.Empty;
|
string url = string.Empty;
|
||||||
|
|
||||||
string remark = string.Empty;
|
string remark = string.Empty;
|
||||||
if (!Utils.IsNullOrEmpty(item.remarks))
|
if (Utils.IsNotEmpty(item.Remarks))
|
||||||
{
|
{
|
||||||
remark = "#" + Utils.UrlEncode(item.remarks);
|
remark = "#" + Utils.UrlEncode(item.Remarks);
|
||||||
}
|
}
|
||||||
var dicQuery = new Dictionary<string, string>();
|
var dicQuery = new Dictionary<string, string>();
|
||||||
GetStdTransport(item, null, ref dicQuery);
|
GetStdTransport(item, null, ref dicQuery);
|
||||||
string query = "?" + string.Join("&", dicQuery.Select(x => x.Key + "=" + x.Value).ToArray());
|
|
||||||
|
|
||||||
url = string.Format("{0}@{1}:{2}",
|
return ToUri(EConfigType.Trojan, item.Address, item.Port, item.Id, dicQuery, remark);
|
||||||
item.id,
|
|
||||||
GetIpv6(item.address),
|
|
||||||
item.port);
|
|
||||||
url = $"{Global.ProtocolShares[EConfigType.Trojan]}{url}{query}{remark}";
|
|
||||||
return url;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -8,24 +8,26 @@
|
|||||||
|
|
||||||
ProfileItem item = new()
|
ProfileItem item = new()
|
||||||
{
|
{
|
||||||
configType = EConfigType.Tuic
|
ConfigType = EConfigType.TUIC
|
||||||
};
|
};
|
||||||
|
|
||||||
Uri url = new(str);
|
var url = Utils.TryUri(str);
|
||||||
|
if (url == null) return null;
|
||||||
|
|
||||||
item.address = url.IdnHost;
|
item.Address = url.IdnHost;
|
||||||
item.port = url.Port;
|
item.Port = url.Port;
|
||||||
item.remarks = url.GetComponents(UriComponents.Fragment, UriFormat.Unescaped);
|
item.Remarks = url.GetComponents(UriComponents.Fragment, UriFormat.Unescaped);
|
||||||
var userInfoParts = url.UserInfo.Split(new[] { ':' }, 2);
|
var rawUserInfo = Utils.UrlDecode(url.UserInfo);
|
||||||
|
var userInfoParts = rawUserInfo.Split(new[] { ':' }, 2);
|
||||||
if (userInfoParts.Length == 2)
|
if (userInfoParts.Length == 2)
|
||||||
{
|
{
|
||||||
item.id = userInfoParts[0];
|
item.Id = userInfoParts[0];
|
||||||
item.security = userInfoParts[1];
|
item.Security = userInfoParts[1];
|
||||||
}
|
}
|
||||||
|
|
||||||
var query = Utils.ParseQueryString(url.Query);
|
var query = Utils.ParseQueryString(url.Query);
|
||||||
ResolveStdTransport(query, ref item);
|
ResolveStdTransport(query, ref item);
|
||||||
item.headerType = query["congestion_control"] ?? "";
|
item.HeaderType = query["congestion_control"] ?? "";
|
||||||
|
|
||||||
return item;
|
return item;
|
||||||
}
|
}
|
||||||
@@ -36,29 +38,22 @@
|
|||||||
string url = string.Empty;
|
string url = string.Empty;
|
||||||
|
|
||||||
string remark = string.Empty;
|
string remark = string.Empty;
|
||||||
if (!Utils.IsNullOrEmpty(item.remarks))
|
if (Utils.IsNotEmpty(item.Remarks))
|
||||||
{
|
{
|
||||||
remark = "#" + Utils.UrlEncode(item.remarks);
|
remark = "#" + Utils.UrlEncode(item.Remarks);
|
||||||
}
|
}
|
||||||
var dicQuery = new Dictionary<string, string>();
|
var dicQuery = new Dictionary<string, string>();
|
||||||
if (!Utils.IsNullOrEmpty(item.sni))
|
if (Utils.IsNotEmpty(item.Sni))
|
||||||
{
|
{
|
||||||
dicQuery.Add("sni", item.sni);
|
dicQuery.Add("sni", item.Sni);
|
||||||
}
|
}
|
||||||
if (!Utils.IsNullOrEmpty(item.alpn))
|
if (Utils.IsNotEmpty(item.Alpn))
|
||||||
{
|
{
|
||||||
dicQuery.Add("alpn", Utils.UrlEncode(item.alpn));
|
dicQuery.Add("alpn", Utils.UrlEncode(item.Alpn));
|
||||||
}
|
}
|
||||||
dicQuery.Add("congestion_control", item.headerType);
|
dicQuery.Add("congestion_control", item.HeaderType);
|
||||||
|
|
||||||
string query = "?" + string.Join("&", dicQuery.Select(x => x.Key + "=" + x.Value).ToArray());
|
return ToUri(EConfigType.TUIC, item.Address, item.Port, $"{item.Id}:{item.Security}", dicQuery, remark);
|
||||||
|
|
||||||
url = string.Format("{0}@{1}:{2}",
|
|
||||||
$"{item.id}:{item.security}",
|
|
||||||
GetIpv6(item.address),
|
|
||||||
item.port);
|
|
||||||
url = $"{Global.ProtocolShares[EConfigType.Tuic]}{url}{query}{remark}";
|
|
||||||
return url;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -20,9 +20,9 @@
|
|||||||
|
|
||||||
var profileIt = new ProfileItem
|
var profileIt = new ProfileItem
|
||||||
{
|
{
|
||||||
coreType = ECoreType.Xray,
|
CoreType = ECoreType.Xray,
|
||||||
address = fileName,
|
Address = fileName,
|
||||||
remarks = v2rayCon.remarks ?? subRemarks ?? "v2ray_custom",
|
Remarks = v2rayCon.remarks ?? subRemarks ?? "v2ray_custom",
|
||||||
};
|
};
|
||||||
lstResult.Add(profileIt);
|
lstResult.Add(profileIt);
|
||||||
}
|
}
|
||||||
@@ -43,9 +43,9 @@
|
|||||||
|
|
||||||
var profileItem = new ProfileItem
|
var profileItem = new ProfileItem
|
||||||
{
|
{
|
||||||
coreType = ECoreType.Xray,
|
CoreType = ECoreType.Xray,
|
||||||
address = fileName,
|
Address = fileName,
|
||||||
remarks = v2rayConfig.remarks ?? subRemarks ?? "v2ray_custom"
|
Remarks = v2rayConfig.remarks ?? subRemarks ?? "v2ray_custom"
|
||||||
};
|
};
|
||||||
|
|
||||||
return profileItem;
|
return profileItem;
|
||||||
|
|||||||
@@ -8,20 +8,21 @@
|
|||||||
|
|
||||||
ProfileItem item = new()
|
ProfileItem item = new()
|
||||||
{
|
{
|
||||||
configType = EConfigType.VLESS,
|
ConfigType = EConfigType.VLESS,
|
||||||
security = Global.None
|
Security = Global.None
|
||||||
};
|
};
|
||||||
|
|
||||||
Uri url = new(str);
|
var url = Utils.TryUri(str);
|
||||||
|
if (url == null) return null;
|
||||||
|
|
||||||
item.address = url.IdnHost;
|
item.Address = url.IdnHost;
|
||||||
item.port = url.Port;
|
item.Port = url.Port;
|
||||||
item.remarks = url.GetComponents(UriComponents.Fragment, UriFormat.Unescaped);
|
item.Remarks = url.GetComponents(UriComponents.Fragment, UriFormat.Unescaped);
|
||||||
item.id = Utils.UrlDecode(url.UserInfo);
|
item.Id = Utils.UrlDecode(url.UserInfo);
|
||||||
|
|
||||||
var query = Utils.ParseQueryString(url.Query);
|
var query = Utils.ParseQueryString(url.Query);
|
||||||
item.security = query["encryption"] ?? Global.None;
|
item.Security = query["encryption"] ?? Global.None;
|
||||||
item.streamSecurity = query["security"] ?? "";
|
item.StreamSecurity = query["security"] ?? "";
|
||||||
ResolveStdTransport(query, ref item);
|
ResolveStdTransport(query, ref item);
|
||||||
|
|
||||||
return item;
|
return item;
|
||||||
@@ -33,28 +34,22 @@
|
|||||||
string url = string.Empty;
|
string url = string.Empty;
|
||||||
|
|
||||||
string remark = string.Empty;
|
string remark = string.Empty;
|
||||||
if (!Utils.IsNullOrEmpty(item.remarks))
|
if (Utils.IsNotEmpty(item.Remarks))
|
||||||
{
|
{
|
||||||
remark = "#" + Utils.UrlEncode(item.remarks);
|
remark = "#" + Utils.UrlEncode(item.Remarks);
|
||||||
}
|
}
|
||||||
var dicQuery = new Dictionary<string, string>();
|
var dicQuery = new Dictionary<string, string>();
|
||||||
if (!Utils.IsNullOrEmpty(item.security))
|
if (Utils.IsNotEmpty(item.Security))
|
||||||
{
|
{
|
||||||
dicQuery.Add("encryption", item.security);
|
dicQuery.Add("encryption", item.Security);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
dicQuery.Add("encryption", Global.None);
|
dicQuery.Add("encryption", Global.None);
|
||||||
}
|
}
|
||||||
GetStdTransport(item, Global.None, ref dicQuery);
|
GetStdTransport(item, Global.None, ref dicQuery);
|
||||||
string query = "?" + string.Join("&", dicQuery.Select(x => x.Key + "=" + x.Value).ToArray());
|
|
||||||
|
|
||||||
url = string.Format("{0}@{1}:{2}",
|
return ToUri(EConfigType.VLESS, item.Address, item.Port, item.Id, dicQuery, remark);
|
||||||
item.id,
|
|
||||||
GetIpv6(item.address),
|
|
||||||
item.port);
|
|
||||||
url = $"{Global.ProtocolShares[EConfigType.VLESS]}{url}{query}{remark}";
|
|
||||||
return url;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -24,21 +24,21 @@
|
|||||||
|
|
||||||
VmessQRCode vmessQRCode = new()
|
VmessQRCode vmessQRCode = new()
|
||||||
{
|
{
|
||||||
v = item.configVersion,
|
v = item.ConfigVersion,
|
||||||
ps = item.remarks.TrimEx(),
|
ps = item.Remarks.TrimEx(),
|
||||||
add = item.address,
|
add = item.Address,
|
||||||
port = item.port,
|
port = item.Port,
|
||||||
id = item.id,
|
id = item.Id,
|
||||||
aid = item.alterId,
|
aid = item.AlterId,
|
||||||
scy = item.security,
|
scy = item.Security,
|
||||||
net = item.network,
|
net = item.Network,
|
||||||
type = item.headerType,
|
type = item.HeaderType,
|
||||||
host = item.requestHost,
|
host = item.RequestHost,
|
||||||
path = item.path,
|
path = item.Path,
|
||||||
tls = item.streamSecurity,
|
tls = item.StreamSecurity,
|
||||||
sni = item.sni,
|
sni = item.Sni,
|
||||||
alpn = item.alpn,
|
alpn = item.Alpn,
|
||||||
fp = item.fingerprint
|
fp = item.Fingerprint
|
||||||
};
|
};
|
||||||
|
|
||||||
url = JsonUtils.Serialize(vmessQRCode);
|
url = JsonUtils.Serialize(vmessQRCode);
|
||||||
@@ -53,13 +53,12 @@
|
|||||||
msg = string.Empty;
|
msg = string.Empty;
|
||||||
var item = new ProfileItem
|
var item = new ProfileItem
|
||||||
{
|
{
|
||||||
configType = EConfigType.VMess
|
ConfigType = EConfigType.VMess
|
||||||
};
|
};
|
||||||
|
|
||||||
result = result[Global.ProtocolShares[EConfigType.VMess].Length..];
|
result = result[Global.ProtocolShares[EConfigType.VMess].Length..];
|
||||||
result = Utils.Base64Decode(result);
|
result = Utils.Base64Decode(result);
|
||||||
|
|
||||||
//转成Json
|
|
||||||
VmessQRCode? vmessQRCode = JsonUtils.Deserialize<VmessQRCode>(result);
|
VmessQRCode? vmessQRCode = JsonUtils.Deserialize<VmessQRCode>(result);
|
||||||
if (vmessQRCode == null)
|
if (vmessQRCode == null)
|
||||||
{
|
{
|
||||||
@@ -67,33 +66,33 @@
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
item.network = Global.DefaultNetwork;
|
item.Network = Global.DefaultNetwork;
|
||||||
item.headerType = Global.None;
|
item.HeaderType = Global.None;
|
||||||
|
|
||||||
item.configVersion = Utils.ToInt(vmessQRCode.v);
|
item.ConfigVersion = vmessQRCode.v;
|
||||||
item.remarks = Utils.ToString(vmessQRCode.ps);
|
item.Remarks = Utils.ToString(vmessQRCode.ps);
|
||||||
item.address = Utils.ToString(vmessQRCode.add);
|
item.Address = Utils.ToString(vmessQRCode.add);
|
||||||
item.port = Utils.ToInt(vmessQRCode.port);
|
item.Port = vmessQRCode.port;
|
||||||
item.id = Utils.ToString(vmessQRCode.id);
|
item.Id = Utils.ToString(vmessQRCode.id);
|
||||||
item.alterId = Utils.ToInt(vmessQRCode.aid);
|
item.AlterId = vmessQRCode.aid;
|
||||||
item.security = Utils.ToString(vmessQRCode.scy);
|
item.Security = Utils.ToString(vmessQRCode.scy);
|
||||||
|
|
||||||
item.security = !Utils.IsNullOrEmpty(vmessQRCode.scy) ? vmessQRCode.scy : Global.DefaultSecurity;
|
item.Security = Utils.IsNotEmpty(vmessQRCode.scy) ? vmessQRCode.scy : Global.DefaultSecurity;
|
||||||
if (!Utils.IsNullOrEmpty(vmessQRCode.net))
|
if (Utils.IsNotEmpty(vmessQRCode.net))
|
||||||
{
|
{
|
||||||
item.network = vmessQRCode.net;
|
item.Network = vmessQRCode.net;
|
||||||
}
|
}
|
||||||
if (!Utils.IsNullOrEmpty(vmessQRCode.type))
|
if (Utils.IsNotEmpty(vmessQRCode.type))
|
||||||
{
|
{
|
||||||
item.headerType = vmessQRCode.type;
|
item.HeaderType = vmessQRCode.type;
|
||||||
}
|
}
|
||||||
|
|
||||||
item.requestHost = Utils.ToString(vmessQRCode.host);
|
item.RequestHost = Utils.ToString(vmessQRCode.host);
|
||||||
item.path = Utils.ToString(vmessQRCode.path);
|
item.Path = Utils.ToString(vmessQRCode.path);
|
||||||
item.streamSecurity = Utils.ToString(vmessQRCode.tls);
|
item.StreamSecurity = Utils.ToString(vmessQRCode.tls);
|
||||||
item.sni = Utils.ToString(vmessQRCode.sni);
|
item.Sni = Utils.ToString(vmessQRCode.sni);
|
||||||
item.alpn = Utils.ToString(vmessQRCode.alpn);
|
item.Alpn = Utils.ToString(vmessQRCode.alpn);
|
||||||
item.fingerprint = Utils.ToString(vmessQRCode.fp);
|
item.Fingerprint = Utils.ToString(vmessQRCode.fp);
|
||||||
|
|
||||||
return item;
|
return item;
|
||||||
}
|
}
|
||||||
@@ -102,16 +101,17 @@
|
|||||||
{
|
{
|
||||||
ProfileItem item = new()
|
ProfileItem item = new()
|
||||||
{
|
{
|
||||||
configType = EConfigType.VMess,
|
ConfigType = EConfigType.VMess,
|
||||||
security = "auto"
|
Security = "auto"
|
||||||
};
|
};
|
||||||
|
|
||||||
Uri url = new(str);
|
var url = Utils.TryUri(str);
|
||||||
|
if (url == null) return null;
|
||||||
|
|
||||||
item.address = url.IdnHost;
|
item.Address = url.IdnHost;
|
||||||
item.port = url.Port;
|
item.Port = url.Port;
|
||||||
item.remarks = url.GetComponents(UriComponents.Fragment, UriFormat.Unescaped);
|
item.Remarks = url.GetComponents(UriComponents.Fragment, UriFormat.Unescaped);
|
||||||
item.id = Utils.UrlDecode(url.UserInfo);
|
item.Id = Utils.UrlDecode(url.UserInfo);
|
||||||
|
|
||||||
var query = Utils.ParseQueryString(url.Query);
|
var query = Utils.ParseQueryString(url.Query);
|
||||||
ResolveStdTransport(query, ref item);
|
ResolveStdTransport(query, ref item);
|
||||||
|
|||||||
@@ -8,22 +8,23 @@
|
|||||||
|
|
||||||
ProfileItem item = new()
|
ProfileItem item = new()
|
||||||
{
|
{
|
||||||
configType = EConfigType.Wireguard
|
ConfigType = EConfigType.WireGuard
|
||||||
};
|
};
|
||||||
|
|
||||||
Uri url = new(str);
|
var url = Utils.TryUri(str);
|
||||||
|
if (url == null) return null;
|
||||||
|
|
||||||
item.address = url.IdnHost;
|
item.Address = url.IdnHost;
|
||||||
item.port = url.Port;
|
item.Port = url.Port;
|
||||||
item.remarks = url.GetComponents(UriComponents.Fragment, UriFormat.Unescaped);
|
item.Remarks = url.GetComponents(UriComponents.Fragment, UriFormat.Unescaped);
|
||||||
item.id = Utils.UrlDecode(url.UserInfo);
|
item.Id = Utils.UrlDecode(url.UserInfo);
|
||||||
|
|
||||||
var query = Utils.ParseQueryString(url.Query);
|
var query = Utils.ParseQueryString(url.Query);
|
||||||
|
|
||||||
item.publicKey = Utils.UrlDecode(query["publickey"] ?? "");
|
item.PublicKey = Utils.UrlDecode(query["publickey"] ?? "");
|
||||||
item.path = Utils.UrlDecode(query["reserved"] ?? "");
|
item.Path = Utils.UrlDecode(query["reserved"] ?? "");
|
||||||
item.requestHost = Utils.UrlDecode(query["address"] ?? "");
|
item.RequestHost = Utils.UrlDecode(query["address"] ?? "");
|
||||||
item.shortId = Utils.UrlDecode(query["mtu"] ?? "");
|
item.ShortId = Utils.UrlDecode(query["mtu"] ?? "");
|
||||||
|
|
||||||
return item;
|
return item;
|
||||||
}
|
}
|
||||||
@@ -34,36 +35,29 @@
|
|||||||
string url = string.Empty;
|
string url = string.Empty;
|
||||||
|
|
||||||
string remark = string.Empty;
|
string remark = string.Empty;
|
||||||
if (!Utils.IsNullOrEmpty(item.remarks))
|
if (Utils.IsNotEmpty(item.Remarks))
|
||||||
{
|
{
|
||||||
remark = "#" + Utils.UrlEncode(item.remarks);
|
remark = "#" + Utils.UrlEncode(item.Remarks);
|
||||||
}
|
}
|
||||||
|
|
||||||
var dicQuery = new Dictionary<string, string>();
|
var dicQuery = new Dictionary<string, string>();
|
||||||
if (!Utils.IsNullOrEmpty(item.publicKey))
|
if (Utils.IsNotEmpty(item.PublicKey))
|
||||||
{
|
{
|
||||||
dicQuery.Add("publickey", Utils.UrlEncode(item.publicKey));
|
dicQuery.Add("publickey", Utils.UrlEncode(item.PublicKey));
|
||||||
}
|
}
|
||||||
if (!Utils.IsNullOrEmpty(item.path))
|
if (Utils.IsNotEmpty(item.Path))
|
||||||
{
|
{
|
||||||
dicQuery.Add("reserved", Utils.UrlEncode(item.path));
|
dicQuery.Add("reserved", Utils.UrlEncode(item.Path));
|
||||||
}
|
}
|
||||||
if (!Utils.IsNullOrEmpty(item.requestHost))
|
if (Utils.IsNotEmpty(item.RequestHost))
|
||||||
{
|
{
|
||||||
dicQuery.Add("address", Utils.UrlEncode(item.requestHost));
|
dicQuery.Add("address", Utils.UrlEncode(item.RequestHost));
|
||||||
}
|
}
|
||||||
if (!Utils.IsNullOrEmpty(item.shortId))
|
if (Utils.IsNotEmpty(item.ShortId))
|
||||||
{
|
{
|
||||||
dicQuery.Add("mtu", Utils.UrlEncode(item.shortId));
|
dicQuery.Add("mtu", Utils.UrlEncode(item.ShortId));
|
||||||
}
|
}
|
||||||
string query = "?" + string.Join("&", dicQuery.Select(x => x.Key + "=" + x.Value).ToArray());
|
return ToUri(EConfigType.WireGuard, item.Address, item.Port, item.Id, dicQuery, remark);
|
||||||
|
|
||||||
url = string.Format("{0}@{1}:{2}",
|
|
||||||
Utils.UrlEncode(item.id),
|
|
||||||
GetIpv6(item.address),
|
|
||||||
item.port);
|
|
||||||
url = $"{Global.ProtocolShares[EConfigType.Wireguard]}{url}/{query}{remark}";
|
|
||||||
return url;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,244 +0,0 @@
|
|||||||
using System.Runtime.InteropServices;
|
|
||||||
|
|
||||||
namespace ServiceLib.Handler
|
|
||||||
{
|
|
||||||
public sealed class LazyConfig
|
|
||||||
{
|
|
||||||
private static readonly Lazy<LazyConfig> _instance = new(() => new());
|
|
||||||
private Config _config;
|
|
||||||
private int? _statePort;
|
|
||||||
private int? _statePort2;
|
|
||||||
|
|
||||||
public static LazyConfig 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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private Job? _processJob;
|
|
||||||
|
|
||||||
public LazyConfig()
|
|
||||||
{
|
|
||||||
SQLiteHelper.Instance.CreateTable<SubItem>();
|
|
||||||
SQLiteHelper.Instance.CreateTable<ProfileItem>();
|
|
||||||
SQLiteHelper.Instance.CreateTable<ServerStatItem>();
|
|
||||||
SQLiteHelper.Instance.CreateTable<RoutingItem>();
|
|
||||||
SQLiteHelper.Instance.CreateTable<ProfileExItem>();
|
|
||||||
SQLiteHelper.Instance.CreateTable<DNSItem>();
|
|
||||||
}
|
|
||||||
|
|
||||||
#region Config
|
|
||||||
|
|
||||||
public void SetConfig(Config config) => _config = 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();
|
|
||||||
_processJob?.AddProcess(processHandle);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion Config
|
|
||||||
|
|
||||||
#region SqliteHelper
|
|
||||||
|
|
||||||
public List<SubItem> SubItems()
|
|
||||||
{
|
|
||||||
return SQLiteHelper.Instance.Table<SubItem>().ToList();
|
|
||||||
}
|
|
||||||
|
|
||||||
public SubItem GetSubItem(string subid)
|
|
||||||
{
|
|
||||||
return SQLiteHelper.Instance.Table<SubItem>().FirstOrDefault(t => t.id == subid);
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<ProfileItem> ProfileItems(string subid)
|
|
||||||
{
|
|
||||||
if (Utils.IsNullOrEmpty(subid))
|
|
||||||
{
|
|
||||||
return SQLiteHelper.Instance.Table<ProfileItem>().ToList();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return SQLiteHelper.Instance.Table<ProfileItem>().Where(t => t.subid == subid).ToList();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<string> ProfileItemIndexes(string subid)
|
|
||||||
{
|
|
||||||
if (Utils.IsNullOrEmpty(subid))
|
|
||||||
{
|
|
||||||
return SQLiteHelper.Instance.Table<ProfileItem>().Select(t => t.indexId).ToList();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return SQLiteHelper.Instance.Table<ProfileItem>().Where(t => t.subid == subid).Select(t => t.indexId).ToList();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<ProfileItemModel> ProfileItems(string subid, string filter)
|
|
||||||
{
|
|
||||||
var sql = @$"select a.*
|
|
||||||
,b.remarks subRemarks
|
|
||||||
from ProfileItem a
|
|
||||||
left join SubItem b on a.subid = b.id
|
|
||||||
where 1=1 ";
|
|
||||||
if (!Utils.IsNullOrEmpty(subid))
|
|
||||||
{
|
|
||||||
sql += $" and a.subid = '{subid}'";
|
|
||||||
}
|
|
||||||
if (!Utils.IsNullOrEmpty(filter))
|
|
||||||
{
|
|
||||||
if (filter.Contains('\''))
|
|
||||||
{
|
|
||||||
filter = filter.Replace("'", "");
|
|
||||||
}
|
|
||||||
sql += String.Format(" and (a.remarks like '%{0}%' or a.address like '%{0}%') ", filter);
|
|
||||||
}
|
|
||||||
|
|
||||||
return SQLiteHelper.Instance.Query<ProfileItemModel>(sql).ToList();
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<ProfileItemModel> ProfileItemsEx(string subid, string filter)
|
|
||||||
{
|
|
||||||
var lstModel = ProfileItems(_config.subIndexId, filter);
|
|
||||||
|
|
||||||
ConfigHandler.SetDefaultServer(_config, lstModel);
|
|
||||||
|
|
||||||
var lstServerStat = (_config.guiItem.enableStatistics ? StatisticsHandler.Instance.ServerStat : null) ?? [];
|
|
||||||
var lstProfileExs = ProfileExHandler.Instance.ProfileExs;
|
|
||||||
lstModel = (from t in lstModel
|
|
||||||
join t2 in lstServerStat on t.indexId equals t2.indexId into t2b
|
|
||||||
from t22 in t2b.DefaultIfEmpty()
|
|
||||||
join t3 in lstProfileExs on t.indexId equals t3.indexId into t3b
|
|
||||||
from t33 in t3b.DefaultIfEmpty()
|
|
||||||
select new ProfileItemModel
|
|
||||||
{
|
|
||||||
indexId = t.indexId,
|
|
||||||
configType = t.configType,
|
|
||||||
remarks = t.remarks,
|
|
||||||
address = t.address,
|
|
||||||
port = t.port,
|
|
||||||
security = t.security,
|
|
||||||
network = t.network,
|
|
||||||
streamSecurity = t.streamSecurity,
|
|
||||||
subid = t.subid,
|
|
||||||
subRemarks = t.subRemarks,
|
|
||||||
isActive = t.indexId == _config.indexId,
|
|
||||||
sort = t33 == null ? 0 : t33.sort,
|
|
||||||
delay = t33 == null ? 0 : t33.delay,
|
|
||||||
delayVal = t33?.delay != 0 ? $"{t33?.delay} {Global.DelayUnit}" : string.Empty,
|
|
||||||
speedVal = t33?.speed != 0 ? $"{t33?.speed} {Global.SpeedUnit}" : string.Empty,
|
|
||||||
todayDown = t22 == null ? "" : Utils.HumanFy(t22.todayDown),
|
|
||||||
todayUp = t22 == null ? "" : Utils.HumanFy(t22.todayUp),
|
|
||||||
totalDown = t22 == null ? "" : Utils.HumanFy(t22.totalDown),
|
|
||||||
totalUp = t22 == null ? "" : Utils.HumanFy(t22.totalUp)
|
|
||||||
}).OrderBy(t => t.sort).ToList();
|
|
||||||
|
|
||||||
return lstModel;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ProfileItem? GetProfileItem(string indexId)
|
|
||||||
{
|
|
||||||
if (Utils.IsNullOrEmpty(indexId))
|
|
||||||
{
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
return SQLiteHelper.Instance.Table<ProfileItem>().FirstOrDefault(it => it.indexId == indexId);
|
|
||||||
}
|
|
||||||
|
|
||||||
public ProfileItem? GetProfileItemViaRemarks(string remarks)
|
|
||||||
{
|
|
||||||
if (Utils.IsNullOrEmpty(remarks))
|
|
||||||
{
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
return SQLiteHelper.Instance.Table<ProfileItem>().FirstOrDefault(it => it.remarks == remarks);
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<RoutingItem> RoutingItems()
|
|
||||||
{
|
|
||||||
return SQLiteHelper.Instance.Table<RoutingItem>().Where(it => it.locked == false).OrderBy(t => t.sort).ToList();
|
|
||||||
}
|
|
||||||
|
|
||||||
public RoutingItem GetRoutingItem(string id)
|
|
||||||
{
|
|
||||||
return SQLiteHelper.Instance.Table<RoutingItem>().FirstOrDefault(it => it.locked == false && it.id == id);
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<DNSItem> DNSItems()
|
|
||||||
{
|
|
||||||
return SQLiteHelper.Instance.Table<DNSItem>().ToList();
|
|
||||||
}
|
|
||||||
|
|
||||||
public DNSItem GetDNSItem(ECoreType eCoreType)
|
|
||||||
{
|
|
||||||
return SQLiteHelper.Instance.Table<DNSItem>().FirstOrDefault(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.SsSecuritiesInSagerNet;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ECoreType GetCoreType(ProfileItem profileItem, EConfigType eConfigType)
|
|
||||||
{
|
|
||||||
if (profileItem?.coreType != null)
|
|
||||||
{
|
|
||||||
return (ECoreType)profileItem.coreType;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_config.coreTypeItem == null)
|
|
||||||
{
|
|
||||||
return ECoreType.Xray;
|
|
||||||
}
|
|
||||||
var item = _config.coreTypeItem.FirstOrDefault(it => it.configType == eConfigType);
|
|
||||||
if (item == null)
|
|
||||||
{
|
|
||||||
return ECoreType.Xray;
|
|
||||||
}
|
|
||||||
return item.coreType;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion Core Type
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -4,13 +4,16 @@ 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)
|
public void Enqueue(string? content)
|
||||||
{
|
{
|
||||||
if (content.IsNullOrEmpty())
|
if (content.IsNullOrEmpty())
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
MessageBus.Current.SendMessage(content, Global.CommandSendSnackMsg);
|
MessageBus.Current.SendMessage(content, EMsgCommand.SendSnackMsg.ToString());
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SendMessage(string? content)
|
public void SendMessage(string? content)
|
||||||
@@ -19,16 +22,16 @@ namespace ServiceLib.Handler
|
|||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
MessageBus.Current.SendMessage(content, Global.CommandSendMsgView);
|
MessageBus.Current.SendMessage(content, EMsgCommand.SendMsgView.ToString());
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SendMessage(string? content, bool time)
|
public void SendMessageEx(string? content)
|
||||||
{
|
{
|
||||||
if (content.IsNullOrEmpty())
|
if (content.IsNullOrEmpty())
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
content = $"{DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss")} {content}";
|
content = $"{DateTime.Now:yyyy/MM/dd HH:mm:ss} {content}";
|
||||||
SendMessage(content);
|
SendMessage(content);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -9,52 +9,60 @@ namespace ServiceLib.Handler
|
|||||||
private static readonly Lazy<ProfileExHandler> _instance = new(() => new());
|
private static readonly Lazy<ProfileExHandler> _instance = new(() => new());
|
||||||
private ConcurrentBag<ProfileExItem> _lstProfileEx = [];
|
private ConcurrentBag<ProfileExItem> _lstProfileEx = [];
|
||||||
private Queue<string> _queIndexIds = new();
|
private Queue<string> _queIndexIds = new();
|
||||||
public ConcurrentBag<ProfileExItem> ProfileExs => _lstProfileEx;
|
|
||||||
public static ProfileExHandler Instance => _instance.Value;
|
public static ProfileExHandler Instance => _instance.Value;
|
||||||
|
|
||||||
public ProfileExHandler()
|
public ProfileExHandler()
|
||||||
{
|
{
|
||||||
Init();
|
//Init();
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task Init()
|
||||||
|
{
|
||||||
|
await InitData();
|
||||||
Task.Run(async () =>
|
Task.Run(async () =>
|
||||||
{
|
{
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
SaveQueueIndexIds();
|
|
||||||
await Task.Delay(1000 * 600);
|
await Task.Delay(1000 * 600);
|
||||||
|
await SaveQueueIndexIds();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private void Init()
|
public async Task<ConcurrentBag<ProfileExItem>> GetProfileExs()
|
||||||
{
|
{
|
||||||
SQLiteHelper.Instance.Execute($"delete from ProfileExItem where indexId not in ( select indexId from ProfileItem )");
|
return _lstProfileEx;
|
||||||
|
}
|
||||||
|
|
||||||
_lstProfileEx = new(SQLiteHelper.Instance.Table<ProfileExItem>());
|
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)
|
private void IndexIdEnqueue(string indexId)
|
||||||
{
|
{
|
||||||
if (!Utils.IsNullOrEmpty(indexId) && !_queIndexIds.Contains(indexId))
|
if (Utils.IsNotEmpty(indexId) && !_queIndexIds.Contains(indexId))
|
||||||
{
|
{
|
||||||
_queIndexIds.Enqueue(indexId);
|
_queIndexIds.Enqueue(indexId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void SaveQueueIndexIds()
|
private async Task SaveQueueIndexIds()
|
||||||
{
|
{
|
||||||
var cnt = _queIndexIds.Count;
|
var cnt = _queIndexIds.Count;
|
||||||
if (cnt > 0)
|
if (cnt > 0)
|
||||||
{
|
{
|
||||||
var lstExists = SQLiteHelper.Instance.Table<ProfileExItem>();
|
var lstExists = await SQLiteHelper.Instance.TableAsync<ProfileExItem>().ToListAsync();
|
||||||
List<ProfileExItem> lstInserts = [];
|
List<ProfileExItem> lstInserts = [];
|
||||||
List<ProfileExItem> lstUpdates = [];
|
List<ProfileExItem> lstUpdates = [];
|
||||||
|
|
||||||
for (int i = 0; i < cnt; i++)
|
for (int i = 0; i < cnt; i++)
|
||||||
{
|
{
|
||||||
var id = _queIndexIds.Dequeue();
|
var id = _queIndexIds.Dequeue();
|
||||||
var item = lstExists.FirstOrDefault(t => t.indexId == id);
|
var item = lstExists.FirstOrDefault(t => t.IndexId == id);
|
||||||
var itemNew = _lstProfileEx?.FirstOrDefault(t => t.indexId == id);
|
var itemNew = _lstProfileEx?.FirstOrDefault(t => t.IndexId == id);
|
||||||
if (itemNew is null)
|
if (itemNew is null)
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
@@ -72,10 +80,10 @@ namespace ServiceLib.Handler
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (lstInserts.Count() > 0)
|
if (lstInserts.Count() > 0)
|
||||||
SQLiteHelper.Instance.InsertAll(lstInserts);
|
await SQLiteHelper.Instance.InsertAllAsync(lstInserts);
|
||||||
|
|
||||||
if (lstUpdates.Count() > 0)
|
if (lstUpdates.Count() > 0)
|
||||||
SQLiteHelper.Instance.UpdateAll(lstUpdates);
|
await SQLiteHelper.Instance.UpdateAllAsync(lstUpdates);
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
@@ -88,26 +96,26 @@ namespace ServiceLib.Handler
|
|||||||
{
|
{
|
||||||
profileEx = new()
|
profileEx = new()
|
||||||
{
|
{
|
||||||
indexId = indexId,
|
IndexId = indexId,
|
||||||
delay = 0,
|
Delay = 0,
|
||||||
speed = 0,
|
Speed = 0,
|
||||||
sort = 0
|
Sort = 0
|
||||||
};
|
};
|
||||||
_lstProfileEx.Add(profileEx);
|
_lstProfileEx.Add(profileEx);
|
||||||
IndexIdEnqueue(indexId);
|
IndexIdEnqueue(indexId);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void ClearAll()
|
public async Task ClearAll()
|
||||||
{
|
{
|
||||||
SQLiteHelper.Instance.Execute($"delete from ProfileExItem ");
|
await SQLiteHelper.Instance.ExecuteAsync($"delete from ProfileExItem ");
|
||||||
_lstProfileEx = new();
|
_lstProfileEx = new();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SaveTo()
|
public async Task SaveTo()
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
SaveQueueIndexIds();
|
await SaveQueueIndexIds();
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
@@ -117,49 +125,49 @@ namespace ServiceLib.Handler
|
|||||||
|
|
||||||
public void SetTestDelay(string indexId, string delayVal)
|
public void SetTestDelay(string indexId, string delayVal)
|
||||||
{
|
{
|
||||||
var profileEx = _lstProfileEx.FirstOrDefault(t => t.indexId == indexId);
|
var profileEx = _lstProfileEx.FirstOrDefault(t => t.IndexId == indexId);
|
||||||
if (profileEx == null)
|
if (profileEx == null)
|
||||||
{
|
{
|
||||||
AddProfileEx(indexId, ref profileEx);
|
AddProfileEx(indexId, ref profileEx);
|
||||||
}
|
}
|
||||||
|
|
||||||
int.TryParse(delayVal, out int delay);
|
int.TryParse(delayVal, out int delay);
|
||||||
profileEx.delay = delay;
|
profileEx.Delay = delay;
|
||||||
IndexIdEnqueue(indexId);
|
IndexIdEnqueue(indexId);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetTestSpeed(string indexId, string speedVal)
|
public void SetTestSpeed(string indexId, string speedVal)
|
||||||
{
|
{
|
||||||
var profileEx = _lstProfileEx.FirstOrDefault(t => t.indexId == indexId);
|
var profileEx = _lstProfileEx.FirstOrDefault(t => t.IndexId == indexId);
|
||||||
if (profileEx == null)
|
if (profileEx == null)
|
||||||
{
|
{
|
||||||
AddProfileEx(indexId, ref profileEx);
|
AddProfileEx(indexId, ref profileEx);
|
||||||
}
|
}
|
||||||
|
|
||||||
decimal.TryParse(speedVal, out decimal speed);
|
decimal.TryParse(speedVal, out decimal speed);
|
||||||
profileEx.speed = speed;
|
profileEx.Speed = speed;
|
||||||
IndexIdEnqueue(indexId);
|
IndexIdEnqueue(indexId);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetSort(string indexId, int sort)
|
public void SetSort(string indexId, int sort)
|
||||||
{
|
{
|
||||||
var profileEx = _lstProfileEx.FirstOrDefault(t => t.indexId == indexId);
|
var profileEx = _lstProfileEx.FirstOrDefault(t => t.IndexId == indexId);
|
||||||
if (profileEx == null)
|
if (profileEx == null)
|
||||||
{
|
{
|
||||||
AddProfileEx(indexId, ref profileEx);
|
AddProfileEx(indexId, ref profileEx);
|
||||||
}
|
}
|
||||||
profileEx.sort = sort;
|
profileEx.Sort = sort;
|
||||||
IndexIdEnqueue(indexId);
|
IndexIdEnqueue(indexId);
|
||||||
}
|
}
|
||||||
|
|
||||||
public int GetSort(string indexId)
|
public int GetSort(string indexId)
|
||||||
{
|
{
|
||||||
var profileEx = _lstProfileEx.FirstOrDefault(t => t.indexId == indexId);
|
var profileEx = _lstProfileEx.FirstOrDefault(t => t.IndexId == indexId);
|
||||||
if (profileEx == null)
|
if (profileEx == null)
|
||||||
{
|
{
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
return profileEx.sort;
|
return profileEx.Sort;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int GetMaxSort()
|
public int GetMaxSort()
|
||||||
@@ -168,7 +176,7 @@ namespace ServiceLib.Handler
|
|||||||
{
|
{
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
return _lstProfileEx.Max(t => t == null ? 0 : t.sort);
|
return _lstProfileEx.Max(t => t == null ? 0 : t.Sort);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,136 +0,0 @@
|
|||||||
namespace ServiceLib.Handler.Statistics
|
|
||||||
{
|
|
||||||
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 StatisticsV2ray? _statisticsV2Ray;
|
|
||||||
private StatisticsSingbox? _statisticsSingbox;
|
|
||||||
|
|
||||||
public List<ServerStatItem> ServerStat => _lstServerStat;
|
|
||||||
|
|
||||||
public void Init(Config config, Action<ServerSpeedItem> update)
|
|
||||||
{
|
|
||||||
_config = config;
|
|
||||||
_updateFunc = update;
|
|
||||||
if (!config.guiItem.enableStatistics)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
InitData();
|
|
||||||
|
|
||||||
_statisticsV2Ray = new StatisticsV2ray(config, UpdateServerStat);
|
|
||||||
_statisticsSingbox = new StatisticsSingbox(config, UpdateServerStat);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Close()
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
_statisticsV2Ray?.Close();
|
|
||||||
_statisticsSingbox?.Close();
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
Logging.SaveLog(ex.Message, ex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void ClearAllServerStatistics()
|
|
||||||
{
|
|
||||||
SQLiteHelper.Instance.Execute($"delete from ServerStatItem ");
|
|
||||||
_serverStatItem = null;
|
|
||||||
_lstServerStat = new();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void SaveTo()
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
if (_lstServerStat != null)
|
|
||||||
{
|
|
||||||
SQLiteHelper.Instance.UpdateAll(_lstServerStat);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
Logging.SaveLog(ex.Message, ex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void InitData()
|
|
||||||
{
|
|
||||||
SQLiteHelper.Instance.Execute($"delete from ServerStatItem where indexId not in ( select indexId from ProfileItem )");
|
|
||||||
|
|
||||||
long ticks = DateTime.Now.Date.Ticks;
|
|
||||||
SQLiteHelper.Instance.Execute($"update ServerStatItem set todayUp = 0,todayDown=0,dateNow={ticks} where dateNow<>{ticks}");
|
|
||||||
|
|
||||||
_lstServerStat = SQLiteHelper.Instance.Table<ServerStatItem>().ToList();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void UpdateServerStat(ServerSpeedItem server)
|
|
||||||
{
|
|
||||||
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(server);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void 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
|
|
||||||
};
|
|
||||||
SQLiteHelper.Instance.Replace(_serverStatItem);
|
|
||||||
_lstServerStat.Add(_serverStatItem);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_serverStatItem.dateNow != ticks)
|
|
||||||
{
|
|
||||||
_serverStatItem.todayUp = 0;
|
|
||||||
_serverStatItem.todayDown = 0;
|
|
||||||
_serverStatItem.dateNow = ticks;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
141
v2rayN/ServiceLib/Handler/StatisticsHandler.cs
Normal file
141
v2rayN/ServiceLib/Handler/StatisticsHandler.cs
Normal file
@@ -0,0 +1,141 @@
|
|||||||
|
namespace ServiceLib.Handler
|
||||||
|
{
|
||||||
|
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 StatisticsV2rayService? _statisticsV2Ray;
|
||||||
|
private StatisticsSingboxService? _statisticsSingbox;
|
||||||
|
|
||||||
|
public List<ServerStatItem> ServerStat => _lstServerStat;
|
||||||
|
|
||||||
|
public async Task Init(Config config, Action<ServerSpeedItem> updateFunc)
|
||||||
|
{
|
||||||
|
_config = config;
|
||||||
|
_updateFunc = updateFunc;
|
||||||
|
if (!config.GuiItem.EnableStatistics)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
await InitData();
|
||||||
|
|
||||||
|
_statisticsV2Ray = new StatisticsV2rayService(config, UpdateServerStatHandler);
|
||||||
|
_statisticsSingbox = new StatisticsSingboxService(config, UpdateServerStatHandler);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Close()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
_statisticsV2Ray?.Close();
|
||||||
|
_statisticsSingbox?.Close();
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Logging.SaveLog(ex.Message, 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(ex.Message, ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
152
v2rayN/ServiceLib/Handler/SysProxy/ProxySettingLinux.cs
Normal file
152
v2rayN/ServiceLib/Handler/SysProxy/ProxySettingLinux.cs
Normal file
@@ -0,0 +1,152 @@
|
|||||||
|
namespace ServiceLib.Handler.SysProxy
|
||||||
|
{
|
||||||
|
public class ProxySettingLinux
|
||||||
|
{
|
||||||
|
public static async Task SetProxy(string host, int port)
|
||||||
|
{
|
||||||
|
var lstCmd = GetSetCmds(host, port);
|
||||||
|
|
||||||
|
await ExecCmd(lstCmd);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static async Task UnsetProxy()
|
||||||
|
{
|
||||||
|
var lstCmd = GetUnsetCmds();
|
||||||
|
|
||||||
|
await ExecCmd(lstCmd);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static async Task ExecCmd(List<CmdItem> lstCmd)
|
||||||
|
{
|
||||||
|
foreach (var cmd in lstCmd)
|
||||||
|
{
|
||||||
|
if (cmd is null || cmd.Cmd.IsNullOrEmpty() || cmd.Arguments is null)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
await Task.Delay(10);
|
||||||
|
await Utils.GetCliWrapOutput(cmd.Cmd, cmd.Arguments);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static List<CmdItem> GetSetCmds(string host, int port)
|
||||||
|
{
|
||||||
|
var isKde = IsKde(out var configDir);
|
||||||
|
List<string> lstType = ["", "http", "https", "socks", "ftp"];
|
||||||
|
List<CmdItem> lstCmd = [];
|
||||||
|
|
||||||
|
if (isKde)
|
||||||
|
{
|
||||||
|
foreach (var type in lstType)
|
||||||
|
{
|
||||||
|
lstCmd.AddRange(GetSetCmd4Kde(type, host, port, configDir));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
foreach (var type in lstType)
|
||||||
|
{
|
||||||
|
lstCmd.AddRange(GetSetCmd4Gnome(type, host, port));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return lstCmd;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static List<CmdItem> GetUnsetCmds()
|
||||||
|
{
|
||||||
|
var isKde = IsKde(out var configDir);
|
||||||
|
List<CmdItem> lstCmd = [];
|
||||||
|
|
||||||
|
if (isKde)
|
||||||
|
{
|
||||||
|
lstCmd.Add(new CmdItem()
|
||||||
|
{
|
||||||
|
Cmd = "kwriteconfig5",
|
||||||
|
Arguments = ["--file", $"{configDir}/kioslaverc", "--group", "Proxy Settings", "--key", "ProxyType", "0"]
|
||||||
|
});
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
lstCmd.Add(new CmdItem()
|
||||||
|
{
|
||||||
|
Cmd = "gsettings",
|
||||||
|
Arguments = ["set", "org.gnome.system.proxy", "mode", "none"]
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return lstCmd;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static List<CmdItem> GetSetCmd4Kde(string type, string host, int port, string configDir)
|
||||||
|
{
|
||||||
|
List<CmdItem> lstCmd = [];
|
||||||
|
|
||||||
|
if (type.IsNullOrEmpty())
|
||||||
|
{
|
||||||
|
lstCmd.Add(new()
|
||||||
|
{
|
||||||
|
Cmd = "kwriteconfig5",
|
||||||
|
Arguments = ["--file", $"{configDir}/kioslaverc", "--group", "Proxy Settings", "--key", "ProxyType", "1"]
|
||||||
|
});
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var type2 = type.Equals("https") ? "http" : type;
|
||||||
|
lstCmd.Add(new CmdItem()
|
||||||
|
{
|
||||||
|
Cmd = "kwriteconfig5",
|
||||||
|
Arguments = ["--file", $"{configDir}/kioslaverc", "--group", "Proxy Settings", "--key", $"{type}Proxy", $"{type2}://{host}:{port}"]
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return lstCmd;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static List<CmdItem> GetSetCmd4Gnome(string type, string host, int port)
|
||||||
|
{
|
||||||
|
List<CmdItem> lstCmd = [];
|
||||||
|
|
||||||
|
if (type.IsNullOrEmpty())
|
||||||
|
{
|
||||||
|
lstCmd.Add(new()
|
||||||
|
{
|
||||||
|
Cmd = "gsettings",
|
||||||
|
Arguments = ["set", "org.gnome.system.proxy", "mode", "manual"]
|
||||||
|
});
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
lstCmd.Add(new()
|
||||||
|
{
|
||||||
|
Cmd = "gsettings",
|
||||||
|
Arguments = ["set", $"org.gnome.system.proxy.{type}", "host", host]
|
||||||
|
});
|
||||||
|
|
||||||
|
lstCmd.Add(new()
|
||||||
|
{
|
||||||
|
Cmd = "gsettings",
|
||||||
|
Arguments = ["set", $"org.gnome.system.proxy.{type}", "port", $"{port}"]
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return lstCmd;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static bool IsKde(out string configDir)
|
||||||
|
{
|
||||||
|
configDir = "/home";
|
||||||
|
var desktop = Environment.GetEnvironmentVariable("XDG_CURRENT_DESKTOP");
|
||||||
|
var isKde = string.Equals(desktop, "KDE", StringComparison.OrdinalIgnoreCase);
|
||||||
|
if (isKde)
|
||||||
|
{
|
||||||
|
var homeDir = Environment.GetEnvironmentVariable("HOME");
|
||||||
|
if (homeDir != null)
|
||||||
|
{
|
||||||
|
configDir = Path.Combine(homeDir, ".config");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return isKde;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
82
v2rayN/ServiceLib/Handler/SysProxy/ProxySettingOSX.cs
Normal file
82
v2rayN/ServiceLib/Handler/SysProxy/ProxySettingOSX.cs
Normal file
@@ -0,0 +1,82 @@
|
|||||||
|
namespace ServiceLib.Handler.SysProxy
|
||||||
|
{
|
||||||
|
public class ProxySettingOSX
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* 仅测试了,MacOS 13.7.1 x86 版本,其他版本有待确认
|
||||||
|
*/
|
||||||
|
/// <summary>
|
||||||
|
/// 应用接口类型
|
||||||
|
/// </summary>
|
||||||
|
private static readonly List<string> LstInterface = ["Ethernet", "Wi-Fi", "Thunderbolt Bridge"];
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 代理类型,对应 http,https,socks
|
||||||
|
/// </summary>
|
||||||
|
private static readonly List<string> LstTypes = ["setwebproxy", "setsecurewebproxy", "setsocksfirewallproxy"];
|
||||||
|
|
||||||
|
public static async Task SetProxy(string host, int port)
|
||||||
|
{
|
||||||
|
var lstCmd = GetSetCmds(host, port);
|
||||||
|
await ExecCmd(lstCmd);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static async Task UnsetProxy()
|
||||||
|
{
|
||||||
|
var lstCmd = GetUnsetCmds();
|
||||||
|
await ExecCmd(lstCmd);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private static async Task ExecCmd(List<CmdItem> lstCmd)
|
||||||
|
{
|
||||||
|
foreach (var cmd in lstCmd)
|
||||||
|
{
|
||||||
|
if (cmd is null || cmd.Cmd.IsNullOrEmpty() || cmd.Arguments is null)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
await Task.Delay(10);
|
||||||
|
await Utils.GetCliWrapOutput(cmd.Cmd, cmd.Arguments);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static List<CmdItem> GetSetCmds(string host, int port)
|
||||||
|
{
|
||||||
|
List<CmdItem> lstCmd = [];
|
||||||
|
foreach (var interf in LstInterface)
|
||||||
|
{
|
||||||
|
foreach (var type in LstTypes)
|
||||||
|
{
|
||||||
|
lstCmd.Add(new CmdItem()
|
||||||
|
{
|
||||||
|
Cmd = "networksetup",
|
||||||
|
Arguments = [$"-{type}", interf, host, (type.Contains("socks") ? (port - 1) : port).ToString()]
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return lstCmd;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static List<CmdItem> GetUnsetCmds()
|
||||||
|
{
|
||||||
|
List<CmdItem> lstCmd = [];
|
||||||
|
foreach (var interf in LstInterface)
|
||||||
|
{
|
||||||
|
foreach (var type in LstTypes)
|
||||||
|
{
|
||||||
|
lstCmd.Add(new CmdItem()
|
||||||
|
{
|
||||||
|
Cmd = "networksetup",
|
||||||
|
Arguments = [$"-{type}state", interf, "off"]
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return lstCmd;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,9 +1,9 @@
|
|||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
using static v2rayN.Common.ProxySetting.InternetConnectionOption;
|
using static ServiceLib.Handler.SysProxy.ProxySettingWindows.InternetConnectionOption;
|
||||||
|
|
||||||
namespace v2rayN.Common
|
namespace ServiceLib.Handler.SysProxy
|
||||||
{
|
{
|
||||||
internal class ProxySetting
|
public class ProxySettingWindows
|
||||||
{
|
{
|
||||||
private const string _regPath = @"Software\Microsoft\Windows\CurrentVersion\Internet Settings";
|
private const string _regPath = @"Software\Microsoft\Windows\CurrentVersion\Internet Settings";
|
||||||
|
|
||||||
@@ -72,7 +72,7 @@ namespace v2rayN.Common
|
|||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
SetProxyFallback(strProxy, exceptions, type);
|
SetProxyFallback(strProxy, exceptions, type);
|
||||||
Logging.SaveLog(ex.Message, ex);
|
//Logging.SaveLog(ex.Message, ex);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -88,7 +88,7 @@ namespace v2rayN.Common
|
|||||||
}
|
}
|
||||||
else if (type is 2 or 4) // named proxy or autoproxy script URL
|
else if (type is 2 or 4) // named proxy or autoproxy script URL
|
||||||
{
|
{
|
||||||
optionCount = Utils.IsNullOrEmpty(exceptions) ? 2 : 3;
|
optionCount = string.IsNullOrEmpty(exceptions) ? 2 : 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
int m_Int = (int)PerConnFlags.PROXY_TYPE_DIRECT;
|
int m_Int = (int)PerConnFlags.PROXY_TYPE_DIRECT;
|
||||||
@@ -144,12 +144,12 @@ namespace v2rayN.Common
|
|||||||
{
|
{
|
||||||
if (Environment.Is64BitOperatingSystem)
|
if (Environment.Is64BitOperatingSystem)
|
||||||
{
|
{
|
||||||
nint opt = new(optionsPtr.ToInt64() + i * optSize);
|
nint opt = new(optionsPtr.ToInt64() + (i * optSize));
|
||||||
Marshal.StructureToPtr(options[i], opt, false);
|
Marshal.StructureToPtr(options[i], opt, false);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
nint opt = new(optionsPtr.ToInt32() + i * optSize);
|
nint opt = new(optionsPtr.ToInt32() + (i * optSize));
|
||||||
Marshal.StructureToPtr(options[i], opt, false);
|
Marshal.StructureToPtr(options[i], opt, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -247,7 +247,7 @@ namespace v2rayN.Common
|
|||||||
|
|
||||||
//[MarshalAs(UnmanagedType.)]
|
//[MarshalAs(UnmanagedType.)]
|
||||||
public nint options;
|
public nint options;
|
||||||
};
|
}
|
||||||
|
|
||||||
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
|
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
|
||||||
public struct InternetConnectionOption
|
public struct InternetConnectionOption
|
||||||
106
v2rayN/ServiceLib/Handler/SysProxy/SysProxyHandler.cs
Normal file
106
v2rayN/ServiceLib/Handler/SysProxy/SysProxyHandler.cs
Normal file
@@ -0,0 +1,106 @@
|
|||||||
|
using PacLib;
|
||||||
|
|
||||||
|
namespace ServiceLib.Handler.SysProxy
|
||||||
|
{
|
||||||
|
public static class SysProxyHandler
|
||||||
|
{
|
||||||
|
public static async Task<bool> UpdateSysProxy(Config config, bool forceDisable)
|
||||||
|
{
|
||||||
|
var type = config.SystemProxyItem.SysProxyType;
|
||||||
|
|
||||||
|
if (forceDisable && type != ESysProxyType.Unchanged)
|
||||||
|
{
|
||||||
|
type = ESysProxyType.ForcedClear;
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var port = AppHandler.Instance.GetLocalPort(EInboundProtocol.http);
|
||||||
|
var portSocks = AppHandler.Instance.GetLocalPort(EInboundProtocol.socks);
|
||||||
|
if (port <= 0)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
switch (type)
|
||||||
|
{
|
||||||
|
case ESysProxyType.ForcedChange when Utils.IsWindows():
|
||||||
|
{
|
||||||
|
GetWindowsProxyString(config, port, portSocks, out var strProxy, out var strExceptions);
|
||||||
|
ProxySettingWindows.SetProxy(strProxy, strExceptions, 2);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case ESysProxyType.ForcedChange when Utils.IsLinux():
|
||||||
|
await ProxySettingLinux.SetProxy(Global.Loopback, port);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ESysProxyType.ForcedChange:
|
||||||
|
{
|
||||||
|
if (Utils.IsOSX())
|
||||||
|
{
|
||||||
|
await ProxySettingOSX.SetProxy(Global.Loopback, port);
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case ESysProxyType.ForcedClear when Utils.IsWindows():
|
||||||
|
ProxySettingWindows.UnsetProxy();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ESysProxyType.ForcedClear when Utils.IsLinux():
|
||||||
|
await ProxySettingLinux.UnsetProxy();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ESysProxyType.ForcedClear:
|
||||||
|
{
|
||||||
|
if (Utils.IsOSX())
|
||||||
|
{
|
||||||
|
await ProxySettingOSX.UnsetProxy();
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case ESysProxyType.Pac when Utils.IsWindows():
|
||||||
|
{
|
||||||
|
var portPac = AppHandler.Instance.GetLocalPort(EInboundProtocol.pac);
|
||||||
|
PacHandler.Start(Utils.GetConfigPath(), port, portPac);
|
||||||
|
var strProxy = $"{Global.HttpProtocol}{Global.Loopback}:{portPac}/pac?t={DateTime.Now.Ticks}";
|
||||||
|
ProxySettingWindows.SetProxy(strProxy, "", 4);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (type != ESysProxyType.Pac && Utils.IsWindows())
|
||||||
|
{
|
||||||
|
PacHandler.Stop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Logging.SaveLog(ex.Message, ex);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void GetWindowsProxyString(Config config, int port, int portSocks, out string strProxy, out string strExceptions)
|
||||||
|
{
|
||||||
|
strExceptions = "";
|
||||||
|
if (config.SystemProxyItem.NotProxyLocalAddress)
|
||||||
|
{
|
||||||
|
strExceptions = $"<local>;{config.ConstItem.DefIEProxyExceptions};{config.SystemProxyItem.SystemProxyExceptions}";
|
||||||
|
}
|
||||||
|
|
||||||
|
strProxy = string.Empty;
|
||||||
|
if (Utils.IsNullOrEmpty(config.SystemProxyItem.SystemProxyAdvancedProtocol))
|
||||||
|
{
|
||||||
|
strProxy = $"{Global.Loopback}:{port}";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
strProxy = config.SystemProxyItem.SystemProxyAdvancedProtocol
|
||||||
|
.Replace("{ip}", Global.Loopback)
|
||||||
|
.Replace("{http_port}", port.ToString())
|
||||||
|
.Replace("{socks_port}", portSocks.ToString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -5,40 +5,36 @@
|
|||||||
private static readonly Lazy<TaskHandler> _instance = new(() => new());
|
private static readonly Lazy<TaskHandler> _instance = new(() => new());
|
||||||
public static TaskHandler Instance => _instance.Value;
|
public static TaskHandler Instance => _instance.Value;
|
||||||
|
|
||||||
public TaskHandler()
|
public void RegUpdateTask(Config config, Action<bool, string> updateFunc)
|
||||||
{
|
{
|
||||||
|
Task.Run(() => UpdateTaskRunSubscription(config, updateFunc));
|
||||||
|
Task.Run(() => UpdateTaskRunGeo(config, updateFunc));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void RegUpdateTask(Config config, Action<bool, string> update)
|
private async Task UpdateTaskRunSubscription(Config config, Action<bool, string> updateFunc)
|
||||||
{
|
|
||||||
Task.Run(() => UpdateTaskRunSubscription(config, update));
|
|
||||||
Task.Run(() => UpdateTaskRunGeo(config, update));
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task UpdateTaskRunSubscription(Config config, Action<bool, string> update)
|
|
||||||
{
|
{
|
||||||
await Task.Delay(60000);
|
await Task.Delay(60000);
|
||||||
Logging.SaveLog("UpdateTaskRunSubscription");
|
Logging.SaveLog("UpdateTaskRunSubscription");
|
||||||
|
|
||||||
var updateHandle = new UpdateHandler();
|
var updateHandle = new UpdateService();
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
var updateTime = ((DateTimeOffset)DateTime.Now).ToUnixTimeSeconds();
|
var updateTime = ((DateTimeOffset)DateTime.Now).ToUnixTimeSeconds();
|
||||||
var lstSubs = LazyConfig.Instance.SubItems()
|
var lstSubs = (await AppHandler.Instance.SubItems())
|
||||||
.Where(t => t.autoUpdateInterval > 0)
|
.Where(t => t.AutoUpdateInterval > 0)
|
||||||
.Where(t => updateTime - t.updateTime >= t.autoUpdateInterval * 60)
|
.Where(t => updateTime - t.UpdateTime >= t.AutoUpdateInterval * 60)
|
||||||
.ToList();
|
.ToList();
|
||||||
|
|
||||||
foreach (var item in lstSubs)
|
foreach (var item in lstSubs)
|
||||||
{
|
{
|
||||||
updateHandle.UpdateSubscriptionProcess(config, item.id, true, (bool success, string msg) =>
|
await updateHandle.UpdateSubscriptionProcess(config, item.Id, true, (bool success, string msg) =>
|
||||||
{
|
{
|
||||||
update(success, msg);
|
updateFunc?.Invoke(success, msg);
|
||||||
if (success)
|
if (success)
|
||||||
Logging.SaveLog("subscription" + msg);
|
Logging.SaveLog("subscription" + msg);
|
||||||
});
|
});
|
||||||
item.updateTime = updateTime;
|
item.UpdateTime = updateTime;
|
||||||
ConfigHandler.AddSubItem(config, item);
|
await ConfigHandler.AddSubItem(config, item);
|
||||||
|
|
||||||
await Task.Delay(5000);
|
await Task.Delay(5000);
|
||||||
}
|
}
|
||||||
@@ -46,30 +42,30 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task UpdateTaskRunGeo(Config config, Action<bool, string> update)
|
private async Task UpdateTaskRunGeo(Config config, Action<bool, string> updateFunc)
|
||||||
{
|
{
|
||||||
var autoUpdateGeoTime = DateTime.Now;
|
var autoUpdateGeoTime = DateTime.Now;
|
||||||
|
|
||||||
await Task.Delay(1000 * 120);
|
//await Task.Delay(1000 * 120);
|
||||||
Logging.SaveLog("UpdateTaskRunGeo");
|
Logging.SaveLog("UpdateTaskRunGeo");
|
||||||
|
|
||||||
var updateHandle = new UpdateHandler();
|
var updateHandle = new UpdateService();
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
|
await Task.Delay(1000 * 3600);
|
||||||
|
|
||||||
var dtNow = DateTime.Now;
|
var dtNow = DateTime.Now;
|
||||||
if (config.guiItem.autoUpdateInterval > 0)
|
if (config.GuiItem.AutoUpdateInterval > 0)
|
||||||
{
|
{
|
||||||
if ((dtNow - autoUpdateGeoTime).Hours % config.guiItem.autoUpdateInterval == 0)
|
if ((dtNow - autoUpdateGeoTime).Hours % config.GuiItem.AutoUpdateInterval == 0)
|
||||||
{
|
{
|
||||||
updateHandle.UpdateGeoFileAll(config, (bool success, string msg) =>
|
await updateHandle.UpdateGeoFileAll(config, (bool success, string msg) =>
|
||||||
{
|
{
|
||||||
update(false, msg);
|
updateFunc?.Invoke(false, msg);
|
||||||
});
|
});
|
||||||
autoUpdateGeoTime = dtNow;
|
autoUpdateGeoTime = dtNow;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
await Task.Delay(1000 * 3600);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,539 +0,0 @@
|
|||||||
using System.Diagnostics;
|
|
||||||
using System.Runtime.InteropServices;
|
|
||||||
using System.Text;
|
|
||||||
using System.Text.RegularExpressions;
|
|
||||||
|
|
||||||
namespace ServiceLib.Handler
|
|
||||||
{
|
|
||||||
public class UpdateHandler
|
|
||||||
{
|
|
||||||
private Action<bool, string> _updateFunc;
|
|
||||||
private Config _config;
|
|
||||||
|
|
||||||
public event EventHandler<ResultEventArgs> AbsoluteCompleted;
|
|
||||||
|
|
||||||
public class ResultEventArgs : EventArgs
|
|
||||||
{
|
|
||||||
public bool Success;
|
|
||||||
public string Msg;
|
|
||||||
public string Url;
|
|
||||||
|
|
||||||
public ResultEventArgs(bool success, string msg, string url = "")
|
|
||||||
{
|
|
||||||
Success = success;
|
|
||||||
Msg = msg;
|
|
||||||
Url = url;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void CheckUpdateGuiN(Config config, Action<bool, string> update, bool preRelease)
|
|
||||||
{
|
|
||||||
_config = config;
|
|
||||||
_updateFunc = update;
|
|
||||||
var url = string.Empty;
|
|
||||||
|
|
||||||
DownloadHandler downloadHandle = new();
|
|
||||||
downloadHandle.UpdateCompleted += (sender2, args) =>
|
|
||||||
{
|
|
||||||
if (args.Success)
|
|
||||||
{
|
|
||||||
_updateFunc(false, ResUI.MsgDownloadV2rayCoreSuccessfully);
|
|
||||||
string fileName = Utils.GetTempPath(Utils.GetDownloadFileName(url));
|
|
||||||
fileName = Utils.UrlEncode(fileName);
|
|
||||||
_updateFunc(true, fileName);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
_updateFunc(false, args.Msg);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
downloadHandle.Error += (sender2, args) =>
|
|
||||||
{
|
|
||||||
_updateFunc(false, args.GetException().Message);
|
|
||||||
_updateFunc(false, "");
|
|
||||||
};
|
|
||||||
AbsoluteCompleted += (sender2, args) =>
|
|
||||||
{
|
|
||||||
if (args.Success)
|
|
||||||
{
|
|
||||||
_updateFunc(false, string.Format(ResUI.MsgParsingSuccessfully, ECoreType.v2rayN));
|
|
||||||
_updateFunc(false, args.Msg);
|
|
||||||
|
|
||||||
url = args.Url;
|
|
||||||
AskToDownload(downloadHandle, url, true).ContinueWith(task =>
|
|
||||||
{
|
|
||||||
_updateFunc(false, "");
|
|
||||||
});
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
_updateFunc(false, args.Msg);
|
|
||||||
_updateFunc(false, "");
|
|
||||||
}
|
|
||||||
};
|
|
||||||
_updateFunc(false, string.Format(ResUI.MsgStartUpdating, ECoreType.v2rayN));
|
|
||||||
CheckUpdateAsync(downloadHandle, ECoreType.v2rayN, preRelease);
|
|
||||||
}
|
|
||||||
|
|
||||||
public async void CheckUpdateCore(ECoreType type, Config config, Action<bool, string> update, bool preRelease)
|
|
||||||
{
|
|
||||||
_config = config;
|
|
||||||
_updateFunc = update;
|
|
||||||
var url = string.Empty;
|
|
||||||
|
|
||||||
DownloadHandler downloadHandle = new();
|
|
||||||
downloadHandle.UpdateCompleted += (sender2, args) =>
|
|
||||||
{
|
|
||||||
if (args.Success)
|
|
||||||
{
|
|
||||||
_updateFunc(false, ResUI.MsgDownloadV2rayCoreSuccessfully);
|
|
||||||
_updateFunc(false, ResUI.MsgUnpacking);
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
_updateFunc(true, url);
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
_updateFunc(false, ex.Message);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
_updateFunc(false, args.Msg);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
downloadHandle.Error += (sender2, args) =>
|
|
||||||
{
|
|
||||||
_updateFunc(false, args.GetException().Message);
|
|
||||||
_updateFunc(false, "");
|
|
||||||
};
|
|
||||||
|
|
||||||
AbsoluteCompleted += (sender2, args) =>
|
|
||||||
{
|
|
||||||
if (args.Success)
|
|
||||||
{
|
|
||||||
_updateFunc(false, string.Format(ResUI.MsgParsingSuccessfully, type));
|
|
||||||
_updateFunc(false, args.Msg);
|
|
||||||
|
|
||||||
url = args.Url;
|
|
||||||
AskToDownload(downloadHandle, url, true).ContinueWith(task =>
|
|
||||||
{
|
|
||||||
_updateFunc(false, "");
|
|
||||||
});
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
_updateFunc(false, args.Msg);
|
|
||||||
_updateFunc(false, "");
|
|
||||||
}
|
|
||||||
};
|
|
||||||
_updateFunc(false, string.Format(ResUI.MsgStartUpdating, type));
|
|
||||||
CheckUpdateAsync(downloadHandle, type, preRelease);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void UpdateSubscriptionProcess(Config config, string subId, bool blProxy, Action<bool, string> update)
|
|
||||||
{
|
|
||||||
_config = config;
|
|
||||||
_updateFunc = update;
|
|
||||||
|
|
||||||
_updateFunc(false, ResUI.MsgUpdateSubscriptionStart);
|
|
||||||
var subItem = LazyConfig.Instance.SubItems().OrderBy(t => t.sort).ToList();
|
|
||||||
|
|
||||||
if (subItem == null || subItem.Count <= 0)
|
|
||||||
{
|
|
||||||
_updateFunc(false, ResUI.MsgNoValidSubscription);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
Task.Run(async () =>
|
|
||||||
{
|
|
||||||
foreach (var item in subItem)
|
|
||||||
{
|
|
||||||
string id = item.id.TrimEx();
|
|
||||||
string url = item.url.TrimEx();
|
|
||||||
string userAgent = item.userAgent.TrimEx();
|
|
||||||
string hashCode = $"{item.remarks}->";
|
|
||||||
if (Utils.IsNullOrEmpty(id) || Utils.IsNullOrEmpty(url) || (!Utils.IsNullOrEmpty(subId) && item.id != subId))
|
|
||||||
{
|
|
||||||
//_updateFunc(false, $"{hashCode}{ResUI.MsgNoValidSubscription}");
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (!url.StartsWith(Global.HttpsProtocol) && !url.StartsWith(Global.HttpProtocol))
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (item.enabled == false)
|
|
||||||
{
|
|
||||||
_updateFunc(false, $"{hashCode}{ResUI.MsgSkipSubscriptionUpdate}");
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
var downloadHandle = new DownloadHandler();
|
|
||||||
downloadHandle.Error += (sender2, args) =>
|
|
||||||
{
|
|
||||||
_updateFunc(false, $"{hashCode}{args.GetException().Message}");
|
|
||||||
};
|
|
||||||
|
|
||||||
_updateFunc(false, $"{hashCode}{ResUI.MsgStartGettingSubscriptions}");
|
|
||||||
|
|
||||||
//one url
|
|
||||||
url = Utils.GetPunycode(url);
|
|
||||||
//convert
|
|
||||||
if (!Utils.IsNullOrEmpty(item.convertTarget))
|
|
||||||
{
|
|
||||||
var subConvertUrl = Utils.IsNullOrEmpty(config.constItem.subConvertUrl) ? Global.SubConvertUrls.FirstOrDefault() : config.constItem.subConvertUrl;
|
|
||||||
url = string.Format(subConvertUrl!, Utils.UrlEncode(url));
|
|
||||||
if (!url.Contains("target="))
|
|
||||||
{
|
|
||||||
url += string.Format("&target={0}", item.convertTarget);
|
|
||||||
}
|
|
||||||
if (!url.Contains("config="))
|
|
||||||
{
|
|
||||||
url += string.Format("&config={0}", Global.SubConvertConfig.FirstOrDefault());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
var result = await downloadHandle.TryDownloadString(url, blProxy, userAgent);
|
|
||||||
if (blProxy && Utils.IsNullOrEmpty(result))
|
|
||||||
{
|
|
||||||
result = await downloadHandle.TryDownloadString(url, false, userAgent);
|
|
||||||
}
|
|
||||||
|
|
||||||
//more url
|
|
||||||
if (Utils.IsNullOrEmpty(item.convertTarget) && !Utils.IsNullOrEmpty(item.moreUrl.TrimEx()))
|
|
||||||
{
|
|
||||||
if (!Utils.IsNullOrEmpty(result) && Utils.IsBase64String(result!))
|
|
||||||
{
|
|
||||||
result = Utils.Base64Decode(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
var lstUrl = item.moreUrl.TrimEx().Split(",") ?? [];
|
|
||||||
foreach (var it in lstUrl)
|
|
||||||
{
|
|
||||||
var url2 = Utils.GetPunycode(it);
|
|
||||||
if (Utils.IsNullOrEmpty(url2))
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
var result2 = await downloadHandle.TryDownloadString(url2, blProxy, userAgent);
|
|
||||||
if (blProxy && Utils.IsNullOrEmpty(result2))
|
|
||||||
{
|
|
||||||
result2 = await downloadHandle.TryDownloadString(url2, false, userAgent);
|
|
||||||
}
|
|
||||||
if (!Utils.IsNullOrEmpty(result2))
|
|
||||||
{
|
|
||||||
if (Utils.IsBase64String(result2!))
|
|
||||||
{
|
|
||||||
result += Utils.Base64Decode(result2);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
result += result2;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Utils.IsNullOrEmpty(result))
|
|
||||||
{
|
|
||||||
_updateFunc(false, $"{hashCode}{ResUI.MsgSubscriptionDecodingFailed}");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
_updateFunc(false, $"{hashCode}{ResUI.MsgGetSubscriptionSuccessfully}");
|
|
||||||
if (result?.Length < 99)
|
|
||||||
{
|
|
||||||
_updateFunc(false, $"{hashCode}{result}");
|
|
||||||
}
|
|
||||||
|
|
||||||
int ret = ConfigHandler.AddBatchServers(config, result, id, true);
|
|
||||||
if (ret <= 0)
|
|
||||||
{
|
|
||||||
Logging.SaveLog("FailedImportSubscription");
|
|
||||||
Logging.SaveLog(result);
|
|
||||||
}
|
|
||||||
_updateFunc(false,
|
|
||||||
ret > 0
|
|
||||||
? $"{hashCode}{ResUI.MsgUpdateSubscriptionEnd}"
|
|
||||||
: $"{hashCode}{ResUI.MsgFailedImportSubscription}");
|
|
||||||
}
|
|
||||||
_updateFunc(false, "-------------------------------------------------------");
|
|
||||||
}
|
|
||||||
|
|
||||||
_updateFunc(true, $"{ResUI.MsgUpdateSubscriptionEnd}");
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
public void UpdateGeoFileAll(Config config, Action<bool, string> update)
|
|
||||||
{
|
|
||||||
Task.Run(async () =>
|
|
||||||
{
|
|
||||||
await UpdateGeoFile("geosite", _config, update);
|
|
||||||
await UpdateGeoFile("geoip", _config, update);
|
|
||||||
_updateFunc(true, string.Format(ResUI.MsgDownloadGeoFileSuccessfully, "geo"));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
public void RunAvailabilityCheck(Action<bool, string> update)
|
|
||||||
{
|
|
||||||
Task.Run(async () =>
|
|
||||||
{
|
|
||||||
var time = await (new DownloadHandler()).RunAvailabilityCheck(null);
|
|
||||||
|
|
||||||
update(false, string.Format(ResUI.TestMeOutput, time));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
#region private
|
|
||||||
|
|
||||||
private async void CheckUpdateAsync(DownloadHandler downloadHandle, ECoreType type, bool preRelease)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
var coreInfo = CoreInfoHandler.Instance.GetCoreInfo(type);
|
|
||||||
string url = coreInfo.coreReleaseApiUrl;
|
|
||||||
|
|
||||||
var result = await downloadHandle.DownloadStringAsync(url, true, Global.AppName);
|
|
||||||
if (!Utils.IsNullOrEmpty(result))
|
|
||||||
{
|
|
||||||
ResponseHandler(type, result, preRelease);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Logging.SaveLog("StatusCode error: " + url);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
Logging.SaveLog(ex.Message, ex);
|
|
||||||
_updateFunc(false, ex.Message);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 获取Core版本
|
|
||||||
/// </summary>
|
|
||||||
private SemanticVersion GetCoreVersion(ECoreType type)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
var coreInfo = CoreInfoHandler.Instance.GetCoreInfo(type);
|
|
||||||
string filePath = string.Empty;
|
|
||||||
foreach (string name in coreInfo.coreExes)
|
|
||||||
{
|
|
||||||
string vName = Utils.GetExeName(name);
|
|
||||||
vName = Utils.GetBinPath(vName, coreInfo.coreType.ToString());
|
|
||||||
if (File.Exists(vName))
|
|
||||||
{
|
|
||||||
filePath = vName;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!File.Exists(filePath))
|
|
||||||
{
|
|
||||||
string msg = string.Format(ResUI.NotFoundCore, @"", "", "");
|
|
||||||
//ShowMsg(true, msg);
|
|
||||||
return new SemanticVersion("");
|
|
||||||
}
|
|
||||||
|
|
||||||
using Process p = new();
|
|
||||||
p.StartInfo.FileName = filePath.AppendQuotes();
|
|
||||||
p.StartInfo.Arguments = coreInfo.versionArg;
|
|
||||||
p.StartInfo.WorkingDirectory = Utils.StartupPath();
|
|
||||||
p.StartInfo.UseShellExecute = false;
|
|
||||||
p.StartInfo.RedirectStandardOutput = true;
|
|
||||||
p.StartInfo.CreateNoWindow = true;
|
|
||||||
p.StartInfo.StandardOutputEncoding = Encoding.UTF8;
|
|
||||||
p.Start();
|
|
||||||
p.WaitForExit(5000);
|
|
||||||
string echo = p.StandardOutput.ReadToEnd();
|
|
||||||
string version = string.Empty;
|
|
||||||
switch (type)
|
|
||||||
{
|
|
||||||
case ECoreType.v2fly:
|
|
||||||
case ECoreType.SagerNet:
|
|
||||||
case ECoreType.Xray:
|
|
||||||
case ECoreType.v2fly_v5:
|
|
||||||
version = Regex.Match(echo, $"{coreInfo.match} ([0-9.]+) \\(").Groups[1].Value;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case ECoreType.clash:
|
|
||||||
case ECoreType.clash_meta:
|
|
||||||
case ECoreType.mihomo:
|
|
||||||
version = Regex.Match(echo, $"v[0-9.]+").Groups[0].Value;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case ECoreType.sing_box:
|
|
||||||
version = Regex.Match(echo, $"([0-9.]+)").Groups[1].Value;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return new SemanticVersion(version);
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
Logging.SaveLog(ex.Message, ex);
|
|
||||||
_updateFunc(false, ex.Message);
|
|
||||||
return new SemanticVersion("");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void ResponseHandler(ECoreType type, string gitHubReleaseApi, bool preRelease)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
var gitHubReleases = JsonUtils.Deserialize<List<GitHubRelease>>(gitHubReleaseApi);
|
|
||||||
var gitHubRelease = preRelease ? gitHubReleases?.First() : gitHubReleases?.First(r => r.Prerelease == false);
|
|
||||||
var version = new SemanticVersion(gitHubRelease?.TagName!);
|
|
||||||
var body = gitHubRelease?.Body;
|
|
||||||
|
|
||||||
var coreInfo = CoreInfoHandler.Instance.GetCoreInfo(type);
|
|
||||||
SemanticVersion curVersion;
|
|
||||||
string message;
|
|
||||||
string? url;
|
|
||||||
switch (type)
|
|
||||||
{
|
|
||||||
case ECoreType.v2fly:
|
|
||||||
case ECoreType.SagerNet:
|
|
||||||
case ECoreType.Xray:
|
|
||||||
case ECoreType.v2fly_v5:
|
|
||||||
{
|
|
||||||
curVersion = GetCoreVersion(type);
|
|
||||||
message = string.Format(ResUI.IsLatestCore, type, curVersion.ToVersionString("v"));
|
|
||||||
url = string.Format(GetUrlFromCore(coreInfo), version.ToVersionString("v"));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case ECoreType.clash:
|
|
||||||
case ECoreType.clash_meta:
|
|
||||||
case ECoreType.mihomo:
|
|
||||||
{
|
|
||||||
curVersion = GetCoreVersion(type);
|
|
||||||
message = string.Format(ResUI.IsLatestCore, type, curVersion);
|
|
||||||
url = string.Format(GetUrlFromCore(coreInfo), version.ToVersionString("v"));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case ECoreType.sing_box:
|
|
||||||
{
|
|
||||||
curVersion = GetCoreVersion(type);
|
|
||||||
message = string.Format(ResUI.IsLatestCore, type, curVersion.ToVersionString("v"));
|
|
||||||
url = string.Format(GetUrlFromCore(coreInfo), version.ToVersionString("v"), version);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case ECoreType.v2rayN:
|
|
||||||
{
|
|
||||||
curVersion = new SemanticVersion(Utils.GetVersionInfo());
|
|
||||||
message = string.Format(ResUI.IsLatestN, type, curVersion);
|
|
||||||
url = string.Format(GetUrlFromCore(coreInfo), version);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
throw new ArgumentException("Type");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (curVersion >= version && version != new SemanticVersion(0, 0, 0))
|
|
||||||
{
|
|
||||||
AbsoluteCompleted?.Invoke(this, new ResultEventArgs(false, message));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
AbsoluteCompleted?.Invoke(this, new ResultEventArgs(true, body, url));
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
Logging.SaveLog(ex.Message, ex);
|
|
||||||
_updateFunc(false, ex.Message);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private string? GetUrlFromCore(CoreInfo? coreInfo)
|
|
||||||
{
|
|
||||||
if (Utils.IsWindows())
|
|
||||||
{
|
|
||||||
return RuntimeInformation.ProcessArchitecture switch
|
|
||||||
{
|
|
||||||
Architecture.Arm64 => coreInfo?.coreDownloadUrlArm64,
|
|
||||||
Architecture.X86 => coreInfo?.coreDownloadUrl32,
|
|
||||||
Architecture.X64 => coreInfo?.coreDownloadUrl64,
|
|
||||||
_ => null,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
else if (Utils.IsLinux())
|
|
||||||
{
|
|
||||||
return RuntimeInformation.ProcessArchitecture switch
|
|
||||||
{
|
|
||||||
Architecture.Arm64 => coreInfo?.coreDownloadUrlLinuxArm64,
|
|
||||||
Architecture.X86 => coreInfo?.coreDownloadUrlLinux32,
|
|
||||||
Architecture.X64 => coreInfo?.coreDownloadUrlLinux64,
|
|
||||||
_ => null,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task AskToDownload(DownloadHandler downloadHandle, string url, bool blAsk)
|
|
||||||
{
|
|
||||||
//bool blDownload = false;
|
|
||||||
//if (blAsk)
|
|
||||||
//{
|
|
||||||
// if (UI.ShowYesNo(string.Format(ResUI.DownloadYesNo, url)) == MessageBoxResult.Yes)
|
|
||||||
// {
|
|
||||||
// blDownload = true;
|
|
||||||
// }
|
|
||||||
//}
|
|
||||||
//else
|
|
||||||
//{
|
|
||||||
// blDownload = true;
|
|
||||||
//}
|
|
||||||
//if (blDownload)
|
|
||||||
//{
|
|
||||||
await downloadHandle.DownloadFileAsync(url, true, 60);
|
|
||||||
//}
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task UpdateGeoFile(string geoName, Config config, Action<bool, string> update)
|
|
||||||
{
|
|
||||||
_config = config;
|
|
||||||
_updateFunc = update;
|
|
||||||
var url = string.Format(Global.GeoUrl, geoName);
|
|
||||||
|
|
||||||
DownloadHandler downloadHandle = new();
|
|
||||||
downloadHandle.UpdateCompleted += (sender2, args) =>
|
|
||||||
{
|
|
||||||
if (args.Success)
|
|
||||||
{
|
|
||||||
_updateFunc(false, string.Format(ResUI.MsgDownloadGeoFileSuccessfully, geoName));
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
string fileName = Utils.GetTempPath(Utils.GetDownloadFileName(url));
|
|
||||||
if (File.Exists(fileName))
|
|
||||||
{
|
|
||||||
string targetPath = Utils.GetBinPath($"{geoName}.dat");
|
|
||||||
File.Copy(fileName, targetPath, true);
|
|
||||||
|
|
||||||
File.Delete(fileName);
|
|
||||||
//_updateFunc(true, "");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
_updateFunc(false, ex.Message);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
_updateFunc(false, args.Msg);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
downloadHandle.Error += (sender2, args) =>
|
|
||||||
{
|
|
||||||
_updateFunc(false, args.GetException().Message);
|
|
||||||
};
|
|
||||||
await AskToDownload(downloadHandle, url, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion private
|
|
||||||
}
|
|
||||||
}
|
|
||||||
179
v2rayN/ServiceLib/Handler/WebDavHandler.cs
Normal file
179
v2rayN/ServiceLib/Handler/WebDavHandler.cs
Normal file
@@ -0,0 +1,179 @@
|
|||||||
|
using System.Net;
|
||||||
|
using WebDav;
|
||||||
|
|
||||||
|
namespace ServiceLib.Handler
|
||||||
|
{
|
||||||
|
public sealed class WebDavHandler
|
||||||
|
{
|
||||||
|
private static readonly Lazy<WebDavHandler> _instance = new(() => new());
|
||||||
|
public static WebDavHandler Instance => _instance.Value;
|
||||||
|
|
||||||
|
private Config? _config;
|
||||||
|
private WebDavClient? _client;
|
||||||
|
private string? _lastDescription;
|
||||||
|
private string _webDir = Global.AppName + "_backup";
|
||||||
|
private readonly string _webFileName = "backup.zip";
|
||||||
|
private string _logTitle = "WebDav--";
|
||||||
|
|
||||||
|
public WebDavHandler()
|
||||||
|
{
|
||||||
|
_config = AppHandler.Instance.Config;
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task<bool> GetClient()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (_config.WebDavItem.Url.IsNullOrEmpty()
|
||||||
|
|| _config.WebDavItem.UserName.IsNullOrEmpty()
|
||||||
|
|| _config.WebDavItem.Password.IsNullOrEmpty())
|
||||||
|
{
|
||||||
|
throw new ArgumentException("webdav parameter error or null");
|
||||||
|
}
|
||||||
|
if (_client != null)
|
||||||
|
{
|
||||||
|
_client?.Dispose();
|
||||||
|
_client = null;
|
||||||
|
}
|
||||||
|
if (_config.WebDavItem.DirName.IsNullOrEmpty())
|
||||||
|
{
|
||||||
|
_webDir = Global.AppName + "_backup";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_webDir = _config.WebDavItem.DirName.TrimEx();
|
||||||
|
}
|
||||||
|
|
||||||
|
var clientParams = new WebDavClientParams
|
||||||
|
{
|
||||||
|
BaseAddress = new Uri(_config.WebDavItem.Url),
|
||||||
|
Credentials = new NetworkCredential(_config.WebDavItem.UserName, _config.WebDavItem.Password)
|
||||||
|
};
|
||||||
|
_client = new WebDavClient(clientParams);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
SaveLog(ex);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return await Task.FromResult(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task<bool> TryCreateDir()
|
||||||
|
{
|
||||||
|
if (_client is null) return false;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var result2 = await _client.Mkcol(_webDir);
|
||||||
|
if (result2.IsSuccessful)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
SaveLog(result2.Description);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
SaveLog(ex);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void SaveLog(string desc)
|
||||||
|
{
|
||||||
|
_lastDescription = desc;
|
||||||
|
Logging.SaveLog(_logTitle + desc);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void SaveLog(Exception ex)
|
||||||
|
{
|
||||||
|
_lastDescription = ex.Message;
|
||||||
|
Logging.SaveLog(_logTitle, ex);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<bool> CheckConnection()
|
||||||
|
{
|
||||||
|
if (await GetClient() == false)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
await TryCreateDir();
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var testName = "readme_test";
|
||||||
|
var myContent = new StringContent(testName);
|
||||||
|
var result = await _client.PutFile($"{_webDir}/{testName}", myContent);
|
||||||
|
if (result.IsSuccessful)
|
||||||
|
{
|
||||||
|
await _client.Delete($"{_webDir}/{testName}");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
SaveLog(result.Description);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
SaveLog(ex);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<bool> PutFile(string fileName)
|
||||||
|
{
|
||||||
|
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,17 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace ServiceLib.Models
|
|
||||||
{
|
|
||||||
public class CheckUpdateItem
|
|
||||||
{
|
|
||||||
public bool? isSelected { get; set; }
|
|
||||||
public string coreType { get; set; }
|
|
||||||
public string? remarks { get; set; }
|
|
||||||
public string? fileName { get; set; }
|
|
||||||
public bool? isFinished { get; set; }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
11
v2rayN/ServiceLib/Models/CheckUpdateModel.cs
Normal file
11
v2rayN/ServiceLib/Models/CheckUpdateModel.cs
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
namespace ServiceLib.Models
|
||||||
|
{
|
||||||
|
public class CheckUpdateModel
|
||||||
|
{
|
||||||
|
public bool? IsSelected { get; set; }
|
||||||
|
public string? CoreType { get; set; }
|
||||||
|
public string? Remarks { get; set; }
|
||||||
|
public string? FileName { get; set; }
|
||||||
|
public bool? IsFinished { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -2,16 +2,16 @@
|
|||||||
{
|
{
|
||||||
public class ClashConnectionModel
|
public class ClashConnectionModel
|
||||||
{
|
{
|
||||||
public string id { get; set; }
|
public string? Id { get; set; }
|
||||||
public string network { get; set; }
|
public string? Network { get; set; }
|
||||||
public string type { get; set; }
|
public string? Type { get; set; }
|
||||||
public string host { get; set; }
|
public string? Host { get; set; }
|
||||||
public ulong upload { get; set; }
|
public ulong Upload { get; set; }
|
||||||
public ulong download { get; set; }
|
public ulong Download { get; set; }
|
||||||
public string uploadTraffic { get; set; }
|
public string? UploadTraffic { get; set; }
|
||||||
public string downloadTraffic { get; set; }
|
public string? DownloadTraffic { get; set; }
|
||||||
public double time { get; set; }
|
public double Time { get; set; }
|
||||||
public string elapsed { get; set; }
|
public string? Elapsed { get; set; }
|
||||||
public string chain { get; set; }
|
public string? Chain { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -9,29 +9,29 @@
|
|||||||
|
|
||||||
public class ConnectionItem
|
public class ConnectionItem
|
||||||
{
|
{
|
||||||
public string id { get; set; } = string.Empty;
|
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; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -4,14 +4,14 @@ 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 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; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2,22 +2,22 @@
|
|||||||
{
|
{
|
||||||
public class ClashProxies
|
public class ClashProxies
|
||||||
{
|
{
|
||||||
public Dictionary<String, ProxiesItem> proxies { get; set; }
|
public Dictionary<string, ProxiesItem>? proxies { get; set; }
|
||||||
|
|
||||||
public class ProxiesItem
|
public class ProxiesItem
|
||||||
{
|
{
|
||||||
public string[] all { get; set; }
|
public List<string>? all { get; set; }
|
||||||
public List<HistoryItem> history { get; set; }
|
public List<HistoryItem>? history { get; set; }
|
||||||
public string name { get; set; }
|
public string? name { get; set; }
|
||||||
public string type { get; set; }
|
public string? type { get; set; }
|
||||||
public bool udp { get; set; }
|
public bool udp { get; set; }
|
||||||
public string now { get; set; }
|
public string? now { get; set; }
|
||||||
public int delay { get; set; }
|
public int delay { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public class HistoryItem
|
public class HistoryItem
|
||||||
{
|
{
|
||||||
public string time { get; set; }
|
public string? time { get; set; }
|
||||||
public int delay { get; set; }
|
public int delay { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,16 +3,16 @@
|
|||||||
[Serializable]
|
[Serializable]
|
||||||
public class ClashProxyModel
|
public class ClashProxyModel
|
||||||
{
|
{
|
||||||
public string name { get; set; }
|
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; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
8
v2rayN/ServiceLib/Models/CmdItem.cs
Normal file
8
v2rayN/ServiceLib/Models/CmdItem.cs
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
namespace ServiceLib.Models
|
||||||
|
{
|
||||||
|
public class CmdItem
|
||||||
|
{
|
||||||
|
public string? Cmd { get; set; }
|
||||||
|
public List<string>? Arguments { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -2,12 +2,12 @@
|
|||||||
{
|
{
|
||||||
public class ComboItem
|
public class ComboItem
|
||||||
{
|
{
|
||||||
public string ID
|
public string? ID
|
||||||
{
|
{
|
||||||
get; set;
|
get; set;
|
||||||
}
|
}
|
||||||
|
|
||||||
public string Text
|
public string? Text
|
||||||
{
|
{
|
||||||
get; set;
|
get; set;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,47 +8,47 @@
|
|||||||
{
|
{
|
||||||
#region property
|
#region property
|
||||||
|
|
||||||
public string indexId { get; set; }
|
public string IndexId { get; set; }
|
||||||
public string subIndexId { get; set; }
|
public string SubIndexId { get; set; }
|
||||||
public string systemProxyExceptions { get; set; }
|
|
||||||
public string systemProxyAdvancedProtocol { get; set; }
|
|
||||||
|
|
||||||
public ECoreType runningCoreType { get; set; }
|
public ECoreType RunningCoreType { get; set; }
|
||||||
|
|
||||||
public bool IsRunningCore(ECoreType type)
|
public bool IsRunningCore(ECoreType type)
|
||||||
{
|
{
|
||||||
if (type == ECoreType.Xray && runningCoreType is ECoreType.Xray or ECoreType.v2fly or ECoreType.v2fly_v5 or ECoreType.SagerNet)
|
switch (type)
|
||||||
{
|
{
|
||||||
return true;
|
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:
|
||||||
|
return true;
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
if (type == ECoreType.clash && runningCoreType is ECoreType.sing_box or ECoreType.clash or ECoreType.clash_meta or ECoreType.mihomo)
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion property
|
#endregion property
|
||||||
|
|
||||||
#region other entities
|
#region other entities
|
||||||
|
|
||||||
public CoreBasicItem coreBasicItem { get; set; }
|
public CoreBasicItem CoreBasicItem { get; set; }
|
||||||
public TunModeItem tunModeItem { get; set; }
|
public TunModeItem TunModeItem { get; set; }
|
||||||
public KcpItem kcpItem { get; set; }
|
public KcpItem KcpItem { get; set; }
|
||||||
public GrpcItem grpcItem { get; set; }
|
public GrpcItem GrpcItem { get; set; }
|
||||||
public RoutingBasicItem routingBasicItem { get; set; }
|
public RoutingBasicItem RoutingBasicItem { get; set; }
|
||||||
public GUIItem guiItem { get; set; }
|
public GUIItem GuiItem { get; set; }
|
||||||
public UIItem uiItem { get; set; }
|
public MsgUIItem MsgUIItem { get; set; }
|
||||||
public ConstItem constItem { get; set; }
|
public UIItem UiItem { get; set; }
|
||||||
public SpeedTestItem speedTestItem { get; set; }
|
public ConstItem ConstItem { get; set; }
|
||||||
public Mux4RayItem mux4RayItem { get; set; }
|
public SpeedTestItem SpeedTestItem { get; set; }
|
||||||
public Mux4SboxItem mux4SboxItem { get; set; }
|
public Mux4RayItem Mux4RayItem { get; set; }
|
||||||
public HysteriaItem hysteriaItem { get; set; }
|
public Mux4SboxItem Mux4SboxItem { get; set; }
|
||||||
public ClashUIItem clashUIItem { get; set; }
|
public HysteriaItem HysteriaItem { get; set; }
|
||||||
public SystemProxyItem systemProxyItem { get; set; }
|
public ClashUIItem ClashUIItem { get; set; }
|
||||||
public List<InItem> inbound { get; set; }
|
public SystemProxyItem SystemProxyItem { get; set; }
|
||||||
public List<KeyEventItem> globalHotkeys { get; set; }
|
public WebDavItem WebDavItem { get; set; }
|
||||||
public List<CoreTypeItem> coreTypeItem { get; set; }
|
public CheckUpdateItem CheckUpdateItem { get; set; }
|
||||||
|
public List<InItem> Inbound { get; set; }
|
||||||
|
public List<KeyEventItem> GlobalHotkeys { get; set; }
|
||||||
|
public List<CoreTypeItem> CoreTypeItem { get; set; }
|
||||||
|
|
||||||
#endregion other entities
|
#endregion other entities
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,145 +3,137 @@
|
|||||||
[Serializable]
|
[Serializable]
|
||||||
public class CoreBasicItem
|
public class CoreBasicItem
|
||||||
{
|
{
|
||||||
/// <summary>
|
public bool LogEnabled { get; set; }
|
||||||
/// 允许日志
|
|
||||||
/// </summary>
|
|
||||||
public bool logEnabled { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
public string Loglevel { get; set; }
|
||||||
/// 日志等级
|
|
||||||
/// </summary>
|
|
||||||
public string loglevel { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
public bool MuxEnabled { get; set; }
|
||||||
/// 允许Mux多路复用
|
|
||||||
/// </summary>
|
|
||||||
public bool muxEnabled { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
public bool DefAllowInsecure { get; set; }
|
||||||
/// 是否允许不安全连接
|
|
||||||
/// </summary>
|
|
||||||
public bool defAllowInsecure { get; set; }
|
|
||||||
|
|
||||||
public string defFingerprint { get; set; }
|
public string DefFingerprint { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
public string DefUserAgent { get; set; }
|
||||||
/// 默认用户代理
|
|
||||||
/// </summary>
|
|
||||||
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; }
|
||||||
}
|
}
|
||||||
|
|
||||||
[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 idle_timeout { get; set; }
|
public int? IdleTimeout { get; set; }
|
||||||
public int health_check_timeout { get; set; }
|
public int? HealthCheckTimeout { get; set; }
|
||||||
public bool permit_without_stream { get; set; }
|
public bool? PermitWithoutStream { get; set; }
|
||||||
public int initial_windows_size { 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 keepOlderDedupl { get; set; }
|
public bool KeepOlderDedupl { get; set; }
|
||||||
|
|
||||||
public bool ignoreGeoUpdateCore { get; set; } = true;
|
public bool IgnoreGeoUpdateCore { get; set; } = true;
|
||||||
|
|
||||||
public int autoUpdateInterval { get; set; } = 10;
|
public int AutoUpdateInterval { get; set; }
|
||||||
|
|
||||||
|
public bool EnableSecurityProtocolTls13 { get; set; }
|
||||||
|
|
||||||
public bool checkPreReleaseUpdate { get; set; } = false;
|
public int TrayMenuServersLimit { get; set; } = 20;
|
||||||
|
|
||||||
public bool enableSecurityProtocolTls13 { get; set; }
|
public bool EnableHWA { get; set; } = false;
|
||||||
|
|
||||||
public int trayMenuServersLimit { get; set; } = 20;
|
public bool EnableLog { get; set; } = true;
|
||||||
|
}
|
||||||
|
|
||||||
public bool enableHWA { get; set; } = false;
|
[Serializable]
|
||||||
|
public class MsgUIItem
|
||||||
public bool enableLog { get; set; } = true;
|
{
|
||||||
|
public string? MainMsgFilter { 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 bool colorModeDark { get; set; }
|
public bool ColorModeDark { get; set; }
|
||||||
public bool followSystemTheme { get; set; }
|
public bool FollowSystemTheme { get; set; }
|
||||||
public string? colorPrimaryName { get; set; }
|
public string? ColorPrimaryName { 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 string mainMsgFilter { 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 defIEProxyExceptions { get; set; }
|
public string DefIEProxyExceptions { get; set; }
|
||||||
public string subConvertUrl { get; set; } = string.Empty;
|
public string SubConvertUrl { get; set; } = string.Empty;
|
||||||
|
public string? GeoSourceUrl { get; set; }
|
||||||
|
public string? SrsSourceUrl { 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; }
|
||||||
|
|
||||||
@@ -155,38 +147,38 @@
|
|||||||
[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; }
|
||||||
}
|
}
|
||||||
|
|
||||||
[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; }
|
||||||
}
|
}
|
||||||
|
|
||||||
[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; }
|
||||||
public bool enableRoutingAdvanced { get; set; }
|
public bool EnableRoutingAdvanced { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
[Serializable]
|
[Serializable]
|
||||||
@@ -200,46 +192,62 @@
|
|||||||
[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 max_connections { 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 up_mbps { get; set; }
|
public int UpMbps { get; set; }
|
||||||
public int down_mbps { get; set; }
|
public int DownMbps { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
[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 int connectionsSorting { get; set; }
|
public int ConnectionsSorting { get; set; }
|
||||||
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]
|
||||||
|
public class WebDavItem
|
||||||
|
{
|
||||||
|
public string? Url { get; set; }
|
||||||
|
public string? UserName { get; set; }
|
||||||
|
public string? Password { get; set; }
|
||||||
|
public string? DirName { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
[Serializable]
|
||||||
|
public class CheckUpdateItem
|
||||||
|
{
|
||||||
|
public bool CheckPreReleaseUpdate { get; set; }
|
||||||
|
public List<string>? SelectedCoreTypes { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -3,28 +3,17 @@
|
|||||||
[Serializable]
|
[Serializable]
|
||||||
public class CoreInfo
|
public class CoreInfo
|
||||||
{
|
{
|
||||||
public ECoreType coreType { get; set; }
|
public ECoreType CoreType { get; set; }
|
||||||
|
public List<string>? CoreExes { get; set; }
|
||||||
public List<string> coreExes { get; set; }
|
public string? Arguments { get; set; }
|
||||||
|
public string? Url { get; set; }
|
||||||
public string arguments { get; set; }
|
public string? ReleaseApiUrl { get; set; }
|
||||||
|
public string? DownloadUrlWin64 { get; set; }
|
||||||
public string coreUrl { get; set; }
|
public string? DownloadUrlWinArm64 { get; set; }
|
||||||
|
public string? DownloadUrlLinux64 { get; set; }
|
||||||
public string coreReleaseApiUrl { get; set; }
|
public string? DownloadUrlLinuxArm64 { get; set; }
|
||||||
|
public string? Match { get; set; }
|
||||||
public string coreDownloadUrl32 { get; set; }
|
public string? VersionArg { get; set; }
|
||||||
|
public bool RedirectInfo { get; set; }
|
||||||
public string coreDownloadUrl64 { get; set; }
|
|
||||||
|
|
||||||
public string coreDownloadUrlArm64 { get; set; }
|
|
||||||
public string? coreDownloadUrlLinux32 { get; set; }
|
|
||||||
public string? coreDownloadUrlLinux64 { get; set; }
|
|
||||||
public string? coreDownloadUrlLinuxArm64 { get; set; }
|
|
||||||
|
|
||||||
public string match { get; set; }
|
|
||||||
public string versionArg { get; set; }
|
|
||||||
|
|
||||||
public bool redirectInfo { get; set; }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -6,15 +6,15 @@ namespace ServiceLib.Models
|
|||||||
public class DNSItem
|
public class DNSItem
|
||||||
{
|
{
|
||||||
[PrimaryKey]
|
[PrimaryKey]
|
||||||
public string id { get; set; }
|
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; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -4,19 +4,19 @@ 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; }
|
||||||
|
|
||||||
@@ -26,28 +26,28 @@ namespace ServiceLib.Models
|
|||||||
|
|
||||||
[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; }
|
||||||
|
|
||||||
@@ -59,10 +59,10 @@ namespace ServiceLib.Models
|
|||||||
|
|
||||||
[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; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -6,10 +6,10 @@ namespace ServiceLib.Models
|
|||||||
public class ProfileExItem
|
public class ProfileExItem
|
||||||
{
|
{
|
||||||
[PrimaryKey]
|
[PrimaryKey]
|
||||||
public string indexId { get; set; }
|
public string IndexId { get; set; }
|
||||||
|
|
||||||
public int delay { get; set; }
|
public int Delay { get; set; }
|
||||||
public decimal speed { get; set; }
|
public decimal Speed { get; set; }
|
||||||
public int sort { get; set; }
|
public int Sort { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -7,184 +7,108 @@ namespace ServiceLib.Models
|
|||||||
{
|
{
|
||||||
public ProfileItem()
|
public ProfileItem()
|
||||||
{
|
{
|
||||||
indexId = string.Empty;
|
IndexId = string.Empty;
|
||||||
configType = EConfigType.VMess;
|
ConfigType = EConfigType.VMess;
|
||||||
configVersion = 2;
|
ConfigVersion = 2;
|
||||||
address = string.Empty;
|
Address = string.Empty;
|
||||||
port = 0;
|
Port = 0;
|
||||||
id = string.Empty;
|
Id = string.Empty;
|
||||||
alterId = 0;
|
AlterId = 0;
|
||||||
security = string.Empty;
|
Security = string.Empty;
|
||||||
network = string.Empty;
|
Network = string.Empty;
|
||||||
remarks = string.Empty;
|
Remarks = string.Empty;
|
||||||
headerType = string.Empty;
|
HeaderType = string.Empty;
|
||||||
requestHost = string.Empty;
|
RequestHost = string.Empty;
|
||||||
path = string.Empty;
|
Path = string.Empty;
|
||||||
streamSecurity = string.Empty;
|
StreamSecurity = string.Empty;
|
||||||
allowInsecure = string.Empty;
|
AllowInsecure = string.Empty;
|
||||||
subid = string.Empty;
|
Subid = string.Empty;
|
||||||
flow = string.Empty;
|
Flow = string.Empty;
|
||||||
}
|
}
|
||||||
|
|
||||||
#region function
|
#region function
|
||||||
|
|
||||||
public string GetSummary()
|
public string GetSummary()
|
||||||
{
|
{
|
||||||
string summary = string.Format("[{0}] ", (configType).ToString());
|
string summary = string.Format("[{0}] ", (ConfigType).ToString());
|
||||||
string[] arrAddr = address.Split('.');
|
string[] arrAddr = Address.Split('.');
|
||||||
string addr;
|
string addr;
|
||||||
if (arrAddr.Length > 2)
|
if (arrAddr.Length > 2)
|
||||||
{
|
{
|
||||||
addr = $"{arrAddr[0]}***{arrAddr[arrAddr.Length - 1]}";
|
addr = $"{arrAddr.First()}***{arrAddr.Last()}";
|
||||||
}
|
}
|
||||||
else if (arrAddr.Length > 1)
|
else if (arrAddr.Length > 1)
|
||||||
{
|
{
|
||||||
addr = $"***{arrAddr[arrAddr.Length - 1]}";
|
addr = $"***{arrAddr.Last()}";
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
addr = address;
|
addr = Address;
|
||||||
}
|
}
|
||||||
switch (configType)
|
switch (ConfigType)
|
||||||
{
|
{
|
||||||
case EConfigType.Custom:
|
case EConfigType.Custom:
|
||||||
summary += string.Format("[{1}]{0}", remarks, coreType.ToString());
|
summary += string.Format("[{1}]{0}", Remarks, CoreType.ToString());
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
summary += string.Format("{0}({1}:{2})", remarks, addr, port);
|
summary += string.Format("{0}({1}:{2})", Remarks, addr, Port);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
return summary;
|
return summary;
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<string> GetAlpn()
|
public List<string>? GetAlpn()
|
||||||
{
|
{
|
||||||
if (Utils.IsNullOrEmpty(alpn))
|
if (Utils.IsNullOrEmpty(Alpn))
|
||||||
{
|
{
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
return Utils.String2List(alpn);
|
return Utils.String2List(Alpn);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public string GetNetwork()
|
public string GetNetwork()
|
||||||
{
|
{
|
||||||
if (Utils.IsNullOrEmpty(network) || !Global.Networks.Contains(network))
|
if (Utils.IsNullOrEmpty(Network) || !Global.Networks.Contains(Network))
|
||||||
{
|
{
|
||||||
return Global.DefaultNetwork;
|
return Global.DefaultNetwork;
|
||||||
}
|
}
|
||||||
return network.TrimEx();
|
return Network.TrimEx();
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion function
|
#endregion function
|
||||||
|
|
||||||
[PrimaryKey]
|
[PrimaryKey]
|
||||||
public string indexId { get; set; }
|
public string IndexId { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
public EConfigType ConfigType { get; set; }
|
||||||
/// config type(1=normal,2=custom)
|
public int ConfigVersion { get; set; }
|
||||||
/// </summary>
|
public string Address { get; set; }
|
||||||
public EConfigType configType { get; set; }
|
public int Port { get; set; }
|
||||||
|
public string Id { get; set; }
|
||||||
/// <summary>
|
public int AlterId { get; set; }
|
||||||
/// 版本(现在=2)
|
public string Security { get; set; }
|
||||||
/// </summary>
|
public string Network { get; set; }
|
||||||
public int configVersion { get; set; }
|
public string Remarks { get; set; }
|
||||||
|
public string HeaderType { get; set; }
|
||||||
/// <summary>
|
public string RequestHost { get; set; }
|
||||||
/// 远程服务器地址
|
public string Path { get; set; }
|
||||||
/// </summary>
|
public string StreamSecurity { get; set; }
|
||||||
public string address { get; set; }
|
public string AllowInsecure { get; set; }
|
||||||
|
public string Subid { get; set; }
|
||||||
/// <summary>
|
public bool IsSub { get; set; } = true;
|
||||||
/// 远程服务器端口
|
public string Flow { get; set; }
|
||||||
/// </summary>
|
public string Sni { get; set; }
|
||||||
public int port { get; set; }
|
public string Alpn { get; set; } = string.Empty;
|
||||||
|
public ECoreType? CoreType { get; set; }
|
||||||
/// <summary>
|
public int? PreSocksPort { get; set; }
|
||||||
/// 远程服务器ID
|
public string Fingerprint { get; set; }
|
||||||
/// </summary>
|
public bool DisplayLog { get; set; } = true;
|
||||||
public string id { get; set; }
|
public string PublicKey { get; set; }
|
||||||
|
public string ShortId { get; set; }
|
||||||
/// <summary>
|
public string SpiderX { get; set; }
|
||||||
/// 远程服务器额外ID
|
|
||||||
/// </summary>
|
|
||||||
public int alterId { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 本地安全策略
|
|
||||||
/// </summary>
|
|
||||||
public string security { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// tcp,kcp,ws,h2,quic
|
|
||||||
/// </summary>
|
|
||||||
public string network { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
///
|
|
||||||
/// </summary>
|
|
||||||
public string remarks { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 伪装类型
|
|
||||||
/// </summary>
|
|
||||||
public string headerType { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 伪装的域名
|
|
||||||
/// </summary>
|
|
||||||
public string requestHost { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// ws h2 path
|
|
||||||
/// </summary>
|
|
||||||
public string path { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 传输层安全
|
|
||||||
/// </summary>
|
|
||||||
public string streamSecurity { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 是否允许不安全连接(用于客户端)
|
|
||||||
/// </summary>
|
|
||||||
public string allowInsecure { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// SubItem id
|
|
||||||
/// </summary>
|
|
||||||
public string subid { get; set; }
|
|
||||||
|
|
||||||
public bool isSub { get; set; } = true;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// VLESS flow
|
|
||||||
/// </summary>
|
|
||||||
public string flow { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// tls sni
|
|
||||||
/// </summary>
|
|
||||||
public string sni { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// tls alpn
|
|
||||||
/// </summary>
|
|
||||||
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; }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -3,16 +3,16 @@
|
|||||||
[Serializable]
|
[Serializable]
|
||||||
public class ProfileItemModel : ProfileItem
|
public class ProfileItemModel : ProfileItem
|
||||||
{
|
{
|
||||||
public bool isActive { get; set; }
|
public bool IsActive { get; set; }
|
||||||
public string subRemarks { get; set; }
|
public string SubRemarks { get; set; }
|
||||||
public int delay { get; set; }
|
public int Delay { get; set; }
|
||||||
public decimal speed { get; set; }
|
public decimal Speed { get; set; }
|
||||||
public int sort { get; set; }
|
public int Sort { get; set; }
|
||||||
public string delayVal { get; set; }
|
public string DelayVal { get; set; }
|
||||||
public string speedVal { get; set; }
|
public string SpeedVal { get; set; }
|
||||||
public string todayUp { get; set; }
|
public string TodayUp { get; set; }
|
||||||
public string todayDown { get; set; }
|
public string TodayDown { get; set; }
|
||||||
public string totalUp { get; set; }
|
public string TotalUp { get; set; }
|
||||||
public string totalDown { get; set; }
|
public string TotalDown { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
27
v2rayN/ServiceLib/Models/RetResult.cs
Normal file
27
v2rayN/ServiceLib/Models/RetResult.cs
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
namespace ServiceLib.Models
|
||||||
|
{
|
||||||
|
public class RetResult
|
||||||
|
{
|
||||||
|
public bool Success { get; set; }
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -6,18 +6,18 @@ namespace ServiceLib.Models
|
|||||||
public class RoutingItem
|
public class RoutingItem
|
||||||
{
|
{
|
||||||
[PrimaryKey]
|
[PrimaryKey]
|
||||||
public string id { get; set; }
|
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; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -3,6 +3,6 @@
|
|||||||
[Serializable]
|
[Serializable]
|
||||||
public class RoutingItemModel : RoutingItem
|
public class RoutingItemModel : RoutingItem
|
||||||
{
|
{
|
||||||
public bool isActive { get; set; }
|
public bool IsActive { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
9
v2rayN/ServiceLib/Models/RoutingTemplate.cs
Normal file
9
v2rayN/ServiceLib/Models/RoutingTemplate.cs
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
namespace ServiceLib.Models
|
||||||
|
{
|
||||||
|
[Serializable]
|
||||||
|
public class RoutingTemplate
|
||||||
|
{
|
||||||
|
public string Version { get; set; }
|
||||||
|
public RoutingItem[] RoutingItems { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -3,24 +3,17 @@
|
|||||||
[Serializable]
|
[Serializable]
|
||||||
public class RulesItem
|
public class RulesItem
|
||||||
{
|
{
|
||||||
public string id { get; set; }
|
public string Id { get; set; }
|
||||||
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 string? OutboundTag { get; set; }
|
||||||
public List<string>? inboundTag { get; set; }
|
public List<string>? Ip { get; set; }
|
||||||
|
public List<string>? Domain { get; set; }
|
||||||
public string? outboundTag { get; set; }
|
public List<string>? Protocol { get; set; }
|
||||||
|
public List<string>? Process { get; set; }
|
||||||
public List<string>? ip { get; set; }
|
public bool Enabled { get; set; } = true;
|
||||||
|
public string? Remarks { get; set; }
|
||||||
public List<string>? domain { get; set; }
|
|
||||||
|
|
||||||
public List<string>? protocol { get; set; }
|
|
||||||
|
|
||||||
public List<string>? process { get; set; }
|
|
||||||
|
|
||||||
public bool enabled { get; set; } = true;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -3,12 +3,9 @@
|
|||||||
[Serializable]
|
[Serializable]
|
||||||
public class RulesItemModel : RulesItem
|
public class RulesItemModel : RulesItem
|
||||||
{
|
{
|
||||||
public string inboundTags { get; set; }
|
public string InboundTags { get; set; }
|
||||||
|
public string Ips { get; set; }
|
||||||
public string ips { get; set; }
|
public string Domains { get; set; }
|
||||||
|
public string Protocols { get; set; }
|
||||||
public string domains { get; set; }
|
|
||||||
|
|
||||||
public string protocols { get; set; }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -3,38 +3,20 @@
|
|||||||
[Serializable]
|
[Serializable]
|
||||||
public class ServerSpeedItem : ServerStatItem
|
public class ServerSpeedItem : ServerStatItem
|
||||||
{
|
{
|
||||||
public long proxyUp
|
public long ProxyUp { get; set; }
|
||||||
{
|
|
||||||
get; set;
|
|
||||||
}
|
|
||||||
|
|
||||||
public long proxyDown
|
public long ProxyDown { get; set; }
|
||||||
{
|
|
||||||
get; set;
|
|
||||||
}
|
|
||||||
|
|
||||||
public long directUp
|
public long DirectUp { get; set; }
|
||||||
{
|
|
||||||
get; set;
|
|
||||||
}
|
|
||||||
|
|
||||||
public long directDown
|
public long DirectDown { get; set; }
|
||||||
{
|
|
||||||
get; set;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[Serializable]
|
[Serializable]
|
||||||
public class TrafficItem
|
public class TrafficItem
|
||||||
{
|
{
|
||||||
public ulong up
|
public ulong Up { get; set; }
|
||||||
{
|
|
||||||
get; set;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ulong down
|
public ulong Down { get; set; }
|
||||||
{
|
|
||||||
get; set;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -6,34 +6,16 @@ namespace ServiceLib.Models
|
|||||||
public class ServerStatItem
|
public class ServerStatItem
|
||||||
{
|
{
|
||||||
[PrimaryKey]
|
[PrimaryKey]
|
||||||
public string indexId
|
public string IndexId { get; set; }
|
||||||
{
|
|
||||||
get; set;
|
|
||||||
}
|
|
||||||
|
|
||||||
public long totalUp
|
public long TotalUp { get; set; }
|
||||||
{
|
|
||||||
get; set;
|
|
||||||
}
|
|
||||||
|
|
||||||
public long totalDown
|
public long TotalDown { get; set; }
|
||||||
{
|
|
||||||
get; set;
|
|
||||||
}
|
|
||||||
|
|
||||||
public long todayUp
|
public long TodayUp { get; set; }
|
||||||
{
|
|
||||||
get; set;
|
|
||||||
}
|
|
||||||
|
|
||||||
public long todayDown
|
public long TodayDown { get; set; }
|
||||||
{
|
|
||||||
get; set;
|
|
||||||
}
|
|
||||||
|
|
||||||
public long dateNow
|
public long DateNow { get; set; }
|
||||||
{
|
|
||||||
get; set;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -3,11 +3,11 @@
|
|||||||
[Serializable]
|
[Serializable]
|
||||||
public class ServerTestItem
|
public class ServerTestItem
|
||||||
{
|
{
|
||||||
public string indexId { get; set; }
|
public string? IndexId { get; set; }
|
||||||
public string address { get; set; }
|
public string? Address { get; set; }
|
||||||
public int port { get; set; }
|
public int Port { get; set; }
|
||||||
public EConfigType configType { get; set; }
|
public EConfigType ConfigType { get; set; }
|
||||||
public bool allowTest { get; set; }
|
public bool AllowTest { get; set; }
|
||||||
public int delay { get; set; }
|
public int Delay { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -120,10 +120,10 @@
|
|||||||
public string? version { get; set; }
|
public string? version { get; set; }
|
||||||
public string? network { get; set; }
|
public string? network { get; set; }
|
||||||
public string? packet_encoding { get; set; }
|
public string? packet_encoding { get; set; }
|
||||||
public string[]? local_address { get; set; }
|
public List<string>? local_address { get; set; }
|
||||||
public string? private_key { get; set; }
|
public string? private_key { get; set; }
|
||||||
public string? peer_public_key { get; set; }
|
public string? peer_public_key { get; set; }
|
||||||
public int[]? reserved { get; set; }
|
public List<int>? reserved { get; set; }
|
||||||
public int? mtu { get; set; }
|
public int? mtu { get; set; }
|
||||||
public string? plugin { get; set; }
|
public string? plugin { get; set; }
|
||||||
public string? plugin_opts { get; set; }
|
public string? plugin_opts { get; set; }
|
||||||
@@ -138,11 +138,11 @@
|
|||||||
public class Tls4Sbox
|
public class Tls4Sbox
|
||||||
{
|
{
|
||||||
public bool enabled { get; set; }
|
public bool enabled { get; set; }
|
||||||
public string server_name { get; set; }
|
public string? server_name { get; set; }
|
||||||
public bool? insecure { get; set; }
|
public bool? insecure { get; set; }
|
||||||
public List<string> alpn { get; set; }
|
public List<string>? alpn { get; set; }
|
||||||
public Utls4Sbox utls { get; set; }
|
public Utls4Sbox? utls { get; set; }
|
||||||
public Reality4Sbox reality { get; set; }
|
public Reality4Sbox? reality { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public class Multiplex4Sbox
|
public class Multiplex4Sbox
|
||||||
|
|||||||
@@ -2,17 +2,17 @@
|
|||||||
{
|
{
|
||||||
public class SsSIP008
|
public class SsSIP008
|
||||||
{
|
{
|
||||||
public List<SsServer> servers { get; set; }
|
public List<SsServer>? servers { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
[Serializable]
|
[Serializable]
|
||||||
public class SsServer
|
public class SsServer
|
||||||
{
|
{
|
||||||
public string remarks { get; set; }
|
public string? remarks { get; set; }
|
||||||
public string server { get; set; }
|
public string? server { get; set; }
|
||||||
public string server_port { get; set; }
|
public string? server_port { get; set; }
|
||||||
public string method { get; set; }
|
public string? method { get; set; }
|
||||||
public string password { get; set; }
|
public string? password { get; set; }
|
||||||
public string plugin { get; set; }
|
public string? plugin { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -6,32 +6,34 @@ namespace ServiceLib.Models
|
|||||||
public class SubItem
|
public class SubItem
|
||||||
{
|
{
|
||||||
[PrimaryKey]
|
[PrimaryKey]
|
||||||
public string id { get; set; }
|
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; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,20 +0,0 @@
|
|||||||
namespace ServiceLib.Models
|
|
||||||
{
|
|
||||||
public class SysProxyConfig
|
|
||||||
{
|
|
||||||
public bool UserSettingsRecorded;
|
|
||||||
public string Flags;
|
|
||||||
public string ProxyServer;
|
|
||||||
public string BypassList;
|
|
||||||
public string PacUrl;
|
|
||||||
|
|
||||||
public SysProxyConfig()
|
|
||||||
{
|
|
||||||
UserSettingsRecorded = false;
|
|
||||||
Flags = "1";
|
|
||||||
ProxyServer = "";
|
|
||||||
BypassList = "";
|
|
||||||
PacUrl = "";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
using System.Text.Json.Serialization;
|
using System.Text.Json.Serialization;
|
||||||
|
|
||||||
namespace ServiceLib.Models
|
namespace ServiceLib.Models
|
||||||
{
|
{
|
||||||
@@ -50,7 +50,7 @@ namespace ServiceLib.Models
|
|||||||
}
|
}
|
||||||
|
|
||||||
public class Stats4Ray
|
public class Stats4Ray
|
||||||
{ };
|
{ }
|
||||||
|
|
||||||
public class API4Ray
|
public class API4Ray
|
||||||
{
|
{
|
||||||
@@ -647,12 +647,12 @@ namespace ServiceLib.Models
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
///
|
///
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public string path { get; set; }
|
public string? path { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
///
|
///
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public List<string> host { get; set; }
|
public List<string>? host { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public class QuicSettings4Ray
|
public class QuicSettings4Ray
|
||||||
@@ -678,10 +678,10 @@ namespace ServiceLib.Models
|
|||||||
public string? authority { get; set; }
|
public string? authority { get; set; }
|
||||||
public string? serviceName { get; set; }
|
public string? serviceName { get; set; }
|
||||||
public bool multiMode { get; set; }
|
public bool multiMode { get; set; }
|
||||||
public int idle_timeout { get; set; }
|
public int? idle_timeout { get; set; }
|
||||||
public int health_check_timeout { get; set; }
|
public int? health_check_timeout { get; set; }
|
||||||
public bool permit_without_stream { get; set; }
|
public bool? permit_without_stream { get; set; }
|
||||||
public int initial_windows_size { get; set; }
|
public int? initial_windows_size { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public class AccountsItem4Ray
|
public class AccountsItem4Ray
|
||||||
|
|||||||
282
v2rayN/ServiceLib/Resx/ResUI.Designer.cs
generated
282
v2rayN/ServiceLib/Resx/ResUI.Designer.cs
generated
@@ -105,6 +105,15 @@ namespace ServiceLib.Resx {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 查找类似 Host filter 的本地化字符串。
|
||||||
|
/// </summary>
|
||||||
|
public static string ConnectionsHostFilterTitle {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("ConnectionsHostFilterTitle", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 查找类似 Note that custom configuration relies entirely on your own configuration and does not work with all settings. If you want to use the system proxy, please modify the listening port manually. 的本地化字符串。
|
/// 查找类似 Note that custom configuration relies entirely on your own configuration and does not work with all settings. If you want to use the system proxy, please modify the listening port manually. 的本地化字符串。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -285,6 +294,24 @@ namespace ServiceLib.Resx {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 查找类似 Please do not use the insecure HTTP protocol subscription address 的本地化字符串。
|
||||||
|
/// </summary>
|
||||||
|
public static string InsecureUrlProtocol {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("InsecureUrlProtocol", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 查找类似 Invalid address (Url) 的本地化字符串。
|
||||||
|
/// </summary>
|
||||||
|
public static string InvalidUrlTip {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("InvalidUrlTip", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 查找类似 {0} {1} already up to date. 的本地化字符串。
|
/// 查找类似 {0} {1} already up to date. 的本地化字符串。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -321,6 +348,15 @@ namespace ServiceLib.Resx {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 查找类似 Invalid backup file 的本地化字符串。
|
||||||
|
/// </summary>
|
||||||
|
public static string LocalRestoreInvalidZipTips {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("LocalRestoreInvalidZipTips", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 查找类似 Address 的本地化字符串。
|
/// 查找类似 Address 的本地化字符串。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -411,6 +447,15 @@ namespace ServiceLib.Resx {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 查找类似 Remarks Memo 的本地化字符串。
|
||||||
|
/// </summary>
|
||||||
|
public static string LvMemo {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("LvMemo", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 查找类似 More URLs, separated by commas; Subscription conversion will be invalid 的本地化字符串。
|
/// 查找类似 More URLs, separated by commas; Subscription conversion will be invalid 的本地化字符串。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -582,6 +627,51 @@ namespace ServiceLib.Resx {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 查找类似 WebDav Check 的本地化字符串。
|
||||||
|
/// </summary>
|
||||||
|
public static string LvWebDavCheck {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("LvWebDavCheck", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 查找类似 Remote folder name (optional) 的本地化字符串。
|
||||||
|
/// </summary>
|
||||||
|
public static string LvWebDavDirName {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("LvWebDavDirName", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 查找类似 WebDav Password 的本地化字符串。
|
||||||
|
/// </summary>
|
||||||
|
public static string LvWebDavPassword {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("LvWebDavPassword", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 查找类似 WebDav Url 的本地化字符串。
|
||||||
|
/// </summary>
|
||||||
|
public static string LvWebDavUrl {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("LvWebDavUrl", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 查找类似 WebDav User Name 的本地化字符串。
|
||||||
|
/// </summary>
|
||||||
|
public static string LvWebDavUserName {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("LvWebDavUserName", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 查找类似 Add a custom configuration server 的本地化字符串。
|
/// 查找类似 Add a custom configuration server 的本地化字符串。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -592,7 +682,7 @@ namespace ServiceLib.Resx {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 查找类似 Add [Http] server 的本地化字符串。
|
/// 查找类似 Add [HTTP] server 的本地化字符串。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static string menuAddHttpServer {
|
public static string menuAddHttpServer {
|
||||||
get {
|
get {
|
||||||
@@ -610,7 +700,7 @@ namespace ServiceLib.Resx {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 查找类似 Importing Share Links from clipboard (Ctrl+V) 的本地化字符串。
|
/// 查找类似 Import Share Links from clipboard (Ctrl+V) 的本地化字符串。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static string menuAddServerViaClipboard {
|
public static string menuAddServerViaClipboard {
|
||||||
get {
|
get {
|
||||||
@@ -618,6 +708,15 @@ namespace ServiceLib.Resx {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 查找类似 Scan QR code in the image 的本地化字符串。
|
||||||
|
/// </summary>
|
||||||
|
public static string menuAddServerViaImage {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("menuAddServerViaImage", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 查找类似 Scan QR code on the screen (Ctrl+S) 的本地化字符串。
|
/// 查找类似 Scan QR code on the screen (Ctrl+S) 的本地化字符串。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -637,7 +736,7 @@ namespace ServiceLib.Resx {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 查找类似 Add [Socks] server 的本地化字符串。
|
/// 查找类似 Add [SOCKS] server 的本地化字符串。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static string menuAddSocksServer {
|
public static string menuAddSocksServer {
|
||||||
get {
|
get {
|
||||||
@@ -655,7 +754,7 @@ namespace ServiceLib.Resx {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 查找类似 Add [Tuic] server 的本地化字符串。
|
/// 查找类似 Add [TUIC] server 的本地化字符串。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static string menuAddTuicServer {
|
public static string menuAddTuicServer {
|
||||||
get {
|
get {
|
||||||
@@ -682,7 +781,7 @@ namespace ServiceLib.Resx {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 查找类似 Add [Wireguard] server 的本地化字符串。
|
/// 查找类似 Add [WireGuard] server 的本地化字符串。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static string menuAddWireguardServer {
|
public static string menuAddWireguardServer {
|
||||||
get {
|
get {
|
||||||
@@ -690,6 +789,15 @@ namespace ServiceLib.Resx {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 查找类似 Backup and Restore 的本地化字符串。
|
||||||
|
/// </summary>
|
||||||
|
public static string menuBackupAndRestore {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("menuBackupAndRestore", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 查找类似 Check Update 的本地化字符串。
|
/// 查找类似 Check Update 的本地化字符串。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -771,6 +879,15 @@ namespace ServiceLib.Resx {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 查找类似 Are you sure to exit? 的本地化字符串。
|
||||||
|
/// </summary>
|
||||||
|
public static string menuExitTips {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("menuExitTips", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 查找类似 Export selected server for complete configuration 的本地化字符串。
|
/// 查找类似 Export selected server for complete configuration 的本地化字符串。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -861,6 +978,33 @@ namespace ServiceLib.Resx {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 查找类似 Backup to local 的本地化字符串。
|
||||||
|
/// </summary>
|
||||||
|
public static string menuLocalBackup {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("menuLocalBackup", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 查找类似 Local 的本地化字符串。
|
||||||
|
/// </summary>
|
||||||
|
public static string menuLocalBackupAndRestore {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("menuLocalBackupAndRestore", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 查找类似 Restore from local 的本地化字符串。
|
||||||
|
/// </summary>
|
||||||
|
public static string menuLocalRestore {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("menuLocalRestore", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 查找类似 One-click multi test Latency and speed (Ctrl+E) 的本地化字符串。
|
/// 查找类似 One-click multi test Latency and speed (Ctrl+E) 的本地化字符串。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -1086,6 +1230,33 @@ namespace ServiceLib.Resx {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 查找类似 Regional presets setting 的本地化字符串。
|
||||||
|
/// </summary>
|
||||||
|
public static string menuRegionalPresets {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("menuRegionalPresets", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 查找类似 Default 的本地化字符串。
|
||||||
|
/// </summary>
|
||||||
|
public static string menuRegionalPresetsDefault {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("menuRegionalPresetsDefault", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 查找类似 Russia 的本地化字符串。
|
||||||
|
/// </summary>
|
||||||
|
public static string menuRegionalPresetsRussia {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("menuRegionalPresetsRussia", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 查找类似 Reload 的本地化字符串。
|
/// 查找类似 Reload 的本地化字符串。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -1095,6 +1266,33 @@ namespace ServiceLib.Resx {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 查找类似 Backup to remote (WebDAV) 的本地化字符串。
|
||||||
|
/// </summary>
|
||||||
|
public static string menuRemoteBackup {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("menuRemoteBackup", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 查找类似 Remote (WebDAV) 的本地化字符串。
|
||||||
|
/// </summary>
|
||||||
|
public static string menuRemoteBackupAndRestore {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("menuRemoteBackupAndRestore", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 查找类似 Restore from remote (WebDAV) 的本地化字符串。
|
||||||
|
/// </summary>
|
||||||
|
public static string menuRemoteRestore {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("menuRemoteRestore", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 查找类似 Remove duplicate servers 的本地化字符串。
|
/// 查找类似 Remove duplicate servers 的本地化字符串。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -1347,6 +1545,15 @@ namespace ServiceLib.Resx {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 查找类似 Save Interface Layout 的本地化字符串。
|
||||||
|
/// </summary>
|
||||||
|
public static string menuStorageUI {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("menuStorageUI", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 查找类似 Add 的本地化字符串。
|
/// 查找类似 Add 的本地化字符串。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -1591,7 +1798,7 @@ namespace ServiceLib.Resx {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 查找类似 Servers Filter, press Enter to execute 的本地化字符串。
|
/// 查找类似 Server filter, press Enter to execute 的本地化字符串。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static string MsgServerTitle {
|
public static string MsgServerTitle {
|
||||||
get {
|
get {
|
||||||
@@ -2590,6 +2797,15 @@ namespace ServiceLib.Resx {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 查找类似 Users in China region can ignore this item 的本地化字符串。
|
||||||
|
/// </summary>
|
||||||
|
public static string TbSettingsChinaUserTip {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("TbSettingsChinaUserTip", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 查找类似 Color 的本地化字符串。
|
/// 查找类似 Color 的本地化字符串。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -2662,6 +2878,15 @@ namespace ServiceLib.Resx {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 查找类似 Install the font to the system and restart the settings 的本地化字符串。
|
||||||
|
/// </summary>
|
||||||
|
public static string TbSettingsCurrentFontFamilyLinuxTip {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("TbSettingsCurrentFontFamilyLinuxTip", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 查找类似 Copy the font TTF/TTC file to the directory guiFonts, restart the settings 的本地化字符串。
|
/// 查找类似 Copy the font TTF/TTC file to the directory guiFonts, restart the settings 的本地化字符串。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -2869,6 +3094,15 @@ namespace ServiceLib.Resx {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 查找类似 Geo files source (optional) 的本地化字符串。
|
||||||
|
/// </summary>
|
||||||
|
public static string TbSettingsGeoFilesSource {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("TbSettingsGeoFilesSource", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 查找类似 HTTP Port 的本地化字符串。
|
/// 查找类似 HTTP Port 的本地化字符串。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -3022,6 +3256,15 @@ namespace ServiceLib.Resx {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 查找类似 Routing rules source (optional) 的本地化字符串。
|
||||||
|
/// </summary>
|
||||||
|
public static string TbSettingsRoutingRulesSource {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("TbSettingsRoutingRulesSource", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 查找类似 Set Win10 UWP Loopback 的本地化字符串。
|
/// 查找类似 Set Win10 UWP Loopback 的本地化字符串。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -3085,6 +3328,15 @@ namespace ServiceLib.Resx {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 查找类似 sing-box ruleset files source (optional) 的本地化字符串。
|
||||||
|
/// </summary>
|
||||||
|
public static string TbSettingsSrsFilesSource {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("TbSettingsSrsFilesSource", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 查找类似 Start on boot 的本地化字符串。
|
/// 查找类似 Start on boot 的本地化字符串。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -3355,6 +3607,15 @@ namespace ServiceLib.Resx {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 查找类似 Active 的本地化字符串。
|
||||||
|
/// </summary>
|
||||||
|
public static string TipActiveServer {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("TipActiveServer", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 查找类似 Routing setting is changed 的本地化字符串。
|
/// 查找类似 Routing setting is changed 的本地化字符串。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -3543,5 +3804,14 @@ namespace ServiceLib.Resx {
|
|||||||
return ResourceManager.GetString("UpdateStandalonePackageTip", resourceCulture);
|
return ResourceManager.GetString("UpdateStandalonePackageTip", resourceCulture);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 查找类似 UpgradeApp does not exist 的本地化字符串。
|
||||||
|
/// </summary>
|
||||||
|
public static string UpgradeAppNotExistTip {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("UpgradeAppNotExistTip", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -410,7 +410,7 @@
|
|||||||
<value>Local</value>
|
<value>Local</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="MsgServerTitle" xml:space="preserve">
|
<data name="MsgServerTitle" xml:space="preserve">
|
||||||
<value>Servers Filter, press Enter to execute</value>
|
<value>Server filter, press Enter to execute</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuCheckUpdate" xml:space="preserve">
|
<data name="menuCheckUpdate" xml:space="preserve">
|
||||||
<value>Check Update</value>
|
<value>Check Update</value>
|
||||||
@@ -491,7 +491,7 @@
|
|||||||
<value>Language (Restart)</value>
|
<value>Language (Restart)</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuAddServerViaClipboard" xml:space="preserve">
|
<data name="menuAddServerViaClipboard" xml:space="preserve">
|
||||||
<value>Importing Share Links from clipboard (Ctrl+V)</value>
|
<value>Import Share Links from clipboard (Ctrl+V)</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuAddServerViaScan" xml:space="preserve">
|
<data name="menuAddServerViaScan" xml:space="preserve">
|
||||||
<value>Scan QR code on the screen (Ctrl+S)</value>
|
<value>Scan QR code on the screen (Ctrl+S)</value>
|
||||||
@@ -536,7 +536,7 @@
|
|||||||
<value>Add [Shadowsocks] server</value>
|
<value>Add [Shadowsocks] server</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuAddSocksServer" xml:space="preserve">
|
<data name="menuAddSocksServer" xml:space="preserve">
|
||||||
<value>Add [Socks] server</value>
|
<value>Add [SOCKS] server</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuAddTrojanServer" xml:space="preserve">
|
<data name="menuAddTrojanServer" xml:space="preserve">
|
||||||
<value>Add [Trojan] server</value>
|
<value>Add [Trojan] server</value>
|
||||||
@@ -1094,7 +1094,7 @@
|
|||||||
<value>Use System Hosts</value>
|
<value>Use System Hosts</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuAddTuicServer" xml:space="preserve">
|
<data name="menuAddTuicServer" xml:space="preserve">
|
||||||
<value>Add [Tuic] server</value>
|
<value>Add [TUIC] server</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbHeaderType8" xml:space="preserve">
|
<data name="TbHeaderType8" xml:space="preserve">
|
||||||
<value>Congestion control</value>
|
<value>Congestion control</value>
|
||||||
@@ -1115,7 +1115,7 @@
|
|||||||
<value>Enable IPv6 Address</value>
|
<value>Enable IPv6 Address</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuAddWireguardServer" xml:space="preserve">
|
<data name="menuAddWireguardServer" xml:space="preserve">
|
||||||
<value>Add [Wireguard] server</value>
|
<value>Add [WireGuard] server</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbPrivateKey" xml:space="preserve">
|
<data name="TbPrivateKey" xml:space="preserve">
|
||||||
<value>PrivateKey</value>
|
<value>PrivateKey</value>
|
||||||
@@ -1148,7 +1148,7 @@
|
|||||||
<value>*grpc Authority</value>
|
<value>*grpc Authority</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuAddHttpServer" xml:space="preserve">
|
<data name="menuAddHttpServer" xml:space="preserve">
|
||||||
<value>Add [Http] server</value>
|
<value>Add [HTTP] server</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSettingsEnableFragmentTips" xml:space="preserve">
|
<data name="TbSettingsEnableFragmentTips" xml:space="preserve">
|
||||||
<value>Use Xray and enable non-Tun mode, which conflicts with the group previous proxy</value>
|
<value>Use Xray and enable non-Tun mode, which conflicts with the group previous proxy</value>
|
||||||
@@ -1279,4 +1279,94 @@
|
|||||||
<data name="TbPreSocksPort4Sub" xml:space="preserve">
|
<data name="TbPreSocksPort4Sub" xml:space="preserve">
|
||||||
<value>Custom config socks port</value>
|
<value>Custom config socks port</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="menuBackupAndRestore" xml:space="preserve">
|
||||||
|
<value>Backup and Restore</value>
|
||||||
|
</data>
|
||||||
|
<data name="menuLocalBackup" xml:space="preserve">
|
||||||
|
<value>Backup to local</value>
|
||||||
|
</data>
|
||||||
|
<data name="menuLocalRestore" xml:space="preserve">
|
||||||
|
<value>Restore from local</value>
|
||||||
|
</data>
|
||||||
|
<data name="menuRemoteBackup" xml:space="preserve">
|
||||||
|
<value>Backup to remote (WebDAV)</value>
|
||||||
|
</data>
|
||||||
|
<data name="menuRemoteRestore" xml:space="preserve">
|
||||||
|
<value>Restore from remote (WebDAV)</value>
|
||||||
|
</data>
|
||||||
|
<data name="menuLocalBackupAndRestore" xml:space="preserve">
|
||||||
|
<value>Local</value>
|
||||||
|
</data>
|
||||||
|
<data name="menuRemoteBackupAndRestore" xml:space="preserve">
|
||||||
|
<value>Remote (WebDAV)</value>
|
||||||
|
</data>
|
||||||
|
<data name="LvWebDavUrl" xml:space="preserve">
|
||||||
|
<value>WebDav Url</value>
|
||||||
|
</data>
|
||||||
|
<data name="LvWebDavUserName" xml:space="preserve">
|
||||||
|
<value>WebDav User Name</value>
|
||||||
|
</data>
|
||||||
|
<data name="LvWebDavPassword" xml:space="preserve">
|
||||||
|
<value>WebDav Password</value>
|
||||||
|
</data>
|
||||||
|
<data name="LvWebDavCheck" xml:space="preserve">
|
||||||
|
<value>WebDav Check</value>
|
||||||
|
</data>
|
||||||
|
<data name="LvWebDavDirName" xml:space="preserve">
|
||||||
|
<value>Remote folder name (optional)</value>
|
||||||
|
</data>
|
||||||
|
<data name="LocalRestoreInvalidZipTips" xml:space="preserve">
|
||||||
|
<value>Invalid backup file</value>
|
||||||
|
</data>
|
||||||
|
<data name="ConnectionsHostFilterTitle" xml:space="preserve">
|
||||||
|
<value>Host filter</value>
|
||||||
|
</data>
|
||||||
|
<data name="TipActiveServer" xml:space="preserve">
|
||||||
|
<value>Active</value>
|
||||||
|
</data>
|
||||||
|
<data name="menuStorageUI" xml:space="preserve">
|
||||||
|
<value>Save Interface Layout</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbSettingsGeoFilesSource" xml:space="preserve">
|
||||||
|
<value>Geo files source (optional)</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbSettingsSrsFilesSource" xml:space="preserve">
|
||||||
|
<value>sing-box ruleset files source (optional)</value>
|
||||||
|
</data>
|
||||||
|
<data name="UpgradeAppNotExistTip" xml:space="preserve">
|
||||||
|
<value>UpgradeApp does not exist</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbSettingsRoutingRulesSource" xml:space="preserve">
|
||||||
|
<value>Routing rules source (optional)</value>
|
||||||
|
</data>
|
||||||
|
<data name="menuRegionalPresets" xml:space="preserve">
|
||||||
|
<value>Regional presets setting</value>
|
||||||
|
</data>
|
||||||
|
<data name="menuRegionalPresetsDefault" xml:space="preserve">
|
||||||
|
<value>Default</value>
|
||||||
|
</data>
|
||||||
|
<data name="menuRegionalPresetsRussia" xml:space="preserve">
|
||||||
|
<value>Russia</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbSettingsChinaUserTip" xml:space="preserve">
|
||||||
|
<value>Users in China region can ignore this item</value>
|
||||||
|
</data>
|
||||||
|
<data name="menuAddServerViaImage" xml:space="preserve">
|
||||||
|
<value>Scan QR code in the image</value>
|
||||||
|
</data>
|
||||||
|
<data name="InvalidUrlTip" xml:space="preserve">
|
||||||
|
<value>Invalid address (Url)</value>
|
||||||
|
</data>
|
||||||
|
<data name="InsecureUrlProtocol" xml:space="preserve">
|
||||||
|
<value>Please do not use the insecure HTTP protocol subscription address</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbSettingsCurrentFontFamilyLinuxTip" xml:space="preserve">
|
||||||
|
<value>Install the font to the system and restart the settings</value>
|
||||||
|
</data>
|
||||||
|
<data name="menuExitTips" xml:space="preserve">
|
||||||
|
<value>Are you sure to exit?</value>
|
||||||
|
</data>
|
||||||
|
<data name="LvMemo" xml:space="preserve">
|
||||||
|
<value>Remarks Memo</value>
|
||||||
|
</data>
|
||||||
</root>
|
</root>
|
||||||
@@ -536,7 +536,7 @@
|
|||||||
<value>Добавить сервер [Shadowsocks]</value>
|
<value>Добавить сервер [Shadowsocks]</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuAddSocksServer" xml:space="preserve">
|
<data name="menuAddSocksServer" xml:space="preserve">
|
||||||
<value>Добавить сервер [Socks]</value>
|
<value>Добавить сервер [SOCKS]</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuAddTrojanServer" xml:space="preserve">
|
<data name="menuAddTrojanServer" xml:space="preserve">
|
||||||
<value>Добавить сервер [Trojan]</value>
|
<value>Добавить сервер [Trojan]</value>
|
||||||
@@ -1027,4 +1027,25 @@
|
|||||||
<data name="TbSettingsSpeedTestUrl" xml:space="preserve">
|
<data name="TbSettingsSpeedTestUrl" xml:space="preserve">
|
||||||
<value>URL спидтеста</value>
|
<value>URL спидтеста</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="TbSettingsGeoFilesSource" xml:space="preserve">
|
||||||
|
<value>Источник geo файлов</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbSettingsSrsFilesSource" xml:space="preserve">
|
||||||
|
<value>Источник sing-box srs файлов</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbSettingsRoutingRulesSource" xml:space="preserve">
|
||||||
|
<value>Источник правил маршрутизации</value>
|
||||||
|
</data>
|
||||||
|
<data name="menuRegionalPresets" xml:space="preserve">
|
||||||
|
<value>Региональные пресеты</value>
|
||||||
|
</data>
|
||||||
|
<data name="menuRegionalPresetsDefault" xml:space="preserve">
|
||||||
|
<value>По умолчанию (Китай)</value>
|
||||||
|
</data>
|
||||||
|
<data name="menuRegionalPresetsRussia" xml:space="preserve">
|
||||||
|
<value>Россия</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbSettingsChinaUserTip" xml:space="preserve">
|
||||||
|
<value>Используйте Настройки -> Региональные пресеты вместо изменения этого поля</value>
|
||||||
|
</data>
|
||||||
</root>
|
</root>
|
||||||
@@ -536,7 +536,7 @@
|
|||||||
<value>添加[Shadowsocks]服务器</value>
|
<value>添加[Shadowsocks]服务器</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuAddSocksServer" xml:space="preserve">
|
<data name="menuAddSocksServer" xml:space="preserve">
|
||||||
<value>添加[Socks]服务器</value>
|
<value>添加[SOCKS]服务器</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuAddTrojanServer" xml:space="preserve">
|
<data name="menuAddTrojanServer" xml:space="preserve">
|
||||||
<value>添加[Trojan]服务器</value>
|
<value>添加[Trojan]服务器</value>
|
||||||
@@ -953,7 +953,7 @@
|
|||||||
<value>导入旧的配置文件guiNConfig</value>
|
<value>导入旧的配置文件guiNConfig</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbEnableTunAs" xml:space="preserve">
|
<data name="TbEnableTunAs" xml:space="preserve">
|
||||||
<value>启用Tun模式</value>
|
<value>启用Tun</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSettingsNewPort4LAN" xml:space="preserve">
|
<data name="TbSettingsNewPort4LAN" xml:space="preserve">
|
||||||
<value>为局域网开启新的端口</value>
|
<value>为局域网开启新的端口</value>
|
||||||
@@ -1091,7 +1091,7 @@
|
|||||||
<value>使用系统hosts</value>
|
<value>使用系统hosts</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuAddTuicServer" xml:space="preserve">
|
<data name="menuAddTuicServer" xml:space="preserve">
|
||||||
<value>添加[Tuic]服务器</value>
|
<value>添加[TUIC]服务器</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbHeaderType8" xml:space="preserve">
|
<data name="TbHeaderType8" xml:space="preserve">
|
||||||
<value>拥塞控制算法</value>
|
<value>拥塞控制算法</value>
|
||||||
@@ -1112,7 +1112,7 @@
|
|||||||
<value>启用IPv6</value>
|
<value>启用IPv6</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuAddWireguardServer" xml:space="preserve">
|
<data name="menuAddWireguardServer" xml:space="preserve">
|
||||||
<value>添加[Wireguard]服务器</value>
|
<value>添加[WireGuard]服务器</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbPrivateKey" xml:space="preserve">
|
<data name="TbPrivateKey" xml:space="preserve">
|
||||||
<value>PrivateKey</value>
|
<value>PrivateKey</value>
|
||||||
@@ -1145,7 +1145,7 @@
|
|||||||
<value>*grpc Authority</value>
|
<value>*grpc Authority</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuAddHttpServer" xml:space="preserve">
|
<data name="menuAddHttpServer" xml:space="preserve">
|
||||||
<value>添加[Http]服务器</value>
|
<value>添加[HTTP]服务器</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSettingsEnableFragment" xml:space="preserve">
|
<data name="TbSettingsEnableFragment" xml:space="preserve">
|
||||||
<value>启用分片(Fragment)</value>
|
<value>启用分片(Fragment)</value>
|
||||||
@@ -1276,4 +1276,94 @@
|
|||||||
<data name="TbPreSocksPort4Sub" xml:space="preserve">
|
<data name="TbPreSocksPort4Sub" xml:space="preserve">
|
||||||
<value>自定义配置的Socks端口</value>
|
<value>自定义配置的Socks端口</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="menuBackupAndRestore" xml:space="preserve">
|
||||||
|
<value>备份和还原</value>
|
||||||
|
</data>
|
||||||
|
<data name="menuLocalBackup" xml:space="preserve">
|
||||||
|
<value>备份到本地</value>
|
||||||
|
</data>
|
||||||
|
<data name="menuLocalRestore" xml:space="preserve">
|
||||||
|
<value>从本地恢复</value>
|
||||||
|
</data>
|
||||||
|
<data name="menuRemoteBackup" xml:space="preserve">
|
||||||
|
<value>备份到远程 (WebDAV)</value>
|
||||||
|
</data>
|
||||||
|
<data name="menuRemoteRestore" xml:space="preserve">
|
||||||
|
<value>从远程恢复 (WebDAV)</value>
|
||||||
|
</data>
|
||||||
|
<data name="menuLocalBackupAndRestore" xml:space="preserve">
|
||||||
|
<value>本地</value>
|
||||||
|
</data>
|
||||||
|
<data name="menuRemoteBackupAndRestore" xml:space="preserve">
|
||||||
|
<value>远程 (WebDAV)</value>
|
||||||
|
</data>
|
||||||
|
<data name="LvWebDavUserName" xml:space="preserve">
|
||||||
|
<value>WebDav 账户</value>
|
||||||
|
</data>
|
||||||
|
<data name="LvWebDavCheck" xml:space="preserve">
|
||||||
|
<value>WebDav 可用检查</value>
|
||||||
|
</data>
|
||||||
|
<data name="LvWebDavPassword" xml:space="preserve">
|
||||||
|
<value>WebDav 密码</value>
|
||||||
|
</data>
|
||||||
|
<data name="LvWebDavUrl" xml:space="preserve">
|
||||||
|
<value>WebDav 服务器地址</value>
|
||||||
|
</data>
|
||||||
|
<data name="LvWebDavDirName" xml:space="preserve">
|
||||||
|
<value>远程文件夹名称(可选)</value>
|
||||||
|
</data>
|
||||||
|
<data name="LocalRestoreInvalidZipTips" xml:space="preserve">
|
||||||
|
<value>无效备份文件</value>
|
||||||
|
</data>
|
||||||
|
<data name="ConnectionsHostFilterTitle" xml:space="preserve">
|
||||||
|
<value>主机过滤器</value>
|
||||||
|
</data>
|
||||||
|
<data name="TipActiveServer" xml:space="preserve">
|
||||||
|
<value>活动</value>
|
||||||
|
</data>
|
||||||
|
<data name="menuStorageUI" xml:space="preserve">
|
||||||
|
<value>保存界面布局</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbSettingsGeoFilesSource" xml:space="preserve">
|
||||||
|
<value>Geo文件来源(可选)</value>
|
||||||
|
</data>
|
||||||
|
<data name="UpgradeAppNotExistTip" xml:space="preserve">
|
||||||
|
<value>升级工具App不存在</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbSettingsSrsFilesSource" xml:space="preserve">
|
||||||
|
<value>sing-box ruleset文件来源(可选)</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbSettingsRoutingRulesSource" xml:space="preserve">
|
||||||
|
<value>路由规则集来源(可选)</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbSettingsChinaUserTip" xml:space="preserve">
|
||||||
|
<value>中国区域用户可忽略此项</value>
|
||||||
|
</data>
|
||||||
|
<data name="menuRegionalPresets" xml:space="preserve">
|
||||||
|
<value>区域预置设置</value>
|
||||||
|
</data>
|
||||||
|
<data name="menuRegionalPresetsDefault" xml:space="preserve">
|
||||||
|
<value>默认区域</value>
|
||||||
|
</data>
|
||||||
|
<data name="menuRegionalPresetsRussia" xml:space="preserve">
|
||||||
|
<value>俄罗斯</value>
|
||||||
|
</data>
|
||||||
|
<data name="menuAddServerViaImage" xml:space="preserve">
|
||||||
|
<value>扫描图片中的二维码</value>
|
||||||
|
</data>
|
||||||
|
<data name="InvalidUrlTip" xml:space="preserve">
|
||||||
|
<value>地址(Url)无效</value>
|
||||||
|
</data>
|
||||||
|
<data name="InsecureUrlProtocol" xml:space="preserve">
|
||||||
|
<value>请不要使用不安全的HTTP协议订阅地址</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbSettingsCurrentFontFamilyLinuxTip" xml:space="preserve">
|
||||||
|
<value>安装字体到系统中,重启设置</value>
|
||||||
|
</data>
|
||||||
|
<data name="menuExitTips" xml:space="preserve">
|
||||||
|
<value>是否确定退出?</value>
|
||||||
|
</data>
|
||||||
|
<data name="LvMemo" xml:space="preserve">
|
||||||
|
<value>备注备忘</value>
|
||||||
|
</data>
|
||||||
</root>
|
</root>
|
||||||
@@ -124,10 +124,10 @@
|
|||||||
<value>請先檢查伺服器設定</value>
|
<value>請先檢查伺服器設定</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="ConfigurationFormatIncorrect" xml:space="preserve">
|
<data name="ConfigurationFormatIncorrect" xml:space="preserve">
|
||||||
<value>配置格式不正確</value>
|
<value>設定格式不正確</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="CustomServerTips" xml:space="preserve">
|
<data name="CustomServerTips" xml:space="preserve">
|
||||||
<value>注意,自訂配置完全依賴您自己的配置,不能使用所有設定功能。如需使用系統代理請手動修改監聽埠。</value>
|
<value>注意,自訂設定完全依賴您自己的設定,不能使用所有設定功能。如需使用系統代理請手動修改監聽埠。</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="Downloading" xml:space="preserve">
|
<data name="Downloading" xml:space="preserve">
|
||||||
<value>下載開始...</value>
|
<value>下載開始...</value>
|
||||||
@@ -139,19 +139,19 @@
|
|||||||
<value>是否下載? {0}</value>
|
<value>是否下載? {0}</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="FailedConversionConfiguration" xml:space="preserve">
|
<data name="FailedConversionConfiguration" xml:space="preserve">
|
||||||
<value>轉換配置檔案失敗</value>
|
<value>轉換設定檔失敗</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="FailedGenDefaultConfiguration" xml:space="preserve">
|
<data name="FailedGenDefaultConfiguration" xml:space="preserve">
|
||||||
<value>生成預設配置檔案失敗</value>
|
<value>生成預設設定檔失敗</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="FailedGetDefaultConfiguration" xml:space="preserve">
|
<data name="FailedGetDefaultConfiguration" xml:space="preserve">
|
||||||
<value>獲取預設配置失敗</value>
|
<value>獲取預設設定失敗</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="FailedImportedCustomServer" xml:space="preserve">
|
<data name="FailedImportedCustomServer" xml:space="preserve">
|
||||||
<value>匯入自訂配置伺服器失敗</value>
|
<value>匯入自訂設定伺服器失敗</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="FailedReadConfiguration" xml:space="preserve">
|
<data name="FailedReadConfiguration" xml:space="preserve">
|
||||||
<value>讀取配置檔案失敗</value>
|
<value>讀取設定檔失敗</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="FillCorrectServerPort" xml:space="preserve">
|
<data name="FillCorrectServerPort" xml:space="preserve">
|
||||||
<value>請填寫正確格式伺服器埠</value>
|
<value>請填寫正確格式伺服器埠</value>
|
||||||
@@ -169,10 +169,10 @@
|
|||||||
<value>請填寫使用者ID</value>
|
<value>請填寫使用者ID</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="Incorrectconfiguration" xml:space="preserve">
|
<data name="Incorrectconfiguration" xml:space="preserve">
|
||||||
<value>不是正確的配置,請檢查</value>
|
<value>不是正確的設定,請檢查</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="InitialConfiguration" xml:space="preserve">
|
<data name="InitialConfiguration" xml:space="preserve">
|
||||||
<value>初始化配置</value>
|
<value>初始化設定</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="IsLatestCore" xml:space="preserve">
|
<data name="IsLatestCore" xml:space="preserve">
|
||||||
<value>{0} {1} 已是最新版本。</value>
|
<value>{0} {1} 已是最新版本。</value>
|
||||||
@@ -256,7 +256,7 @@
|
|||||||
<value>非VMess或SS協定</value>
|
<value>非VMess或SS協定</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="NotFoundCore" xml:space="preserve">
|
<data name="NotFoundCore" xml:space="preserve">
|
||||||
<value>在資料夾 ({0}) 下未找到Core文件 (檔案名:{1}),請下載後放入資料夾、,下載網址: {2}</value>
|
<value>在資料夾 ({0}) 下未找到Core檔案 (檔案名:{1}),請下載後放入資料夾,下載網址: {2}</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="NoValidQRcodeFound" xml:space="preserve">
|
<data name="NoValidQRcodeFound" xml:space="preserve">
|
||||||
<value>掃描完成,未發現有效二維碼</value>
|
<value>掃描完成,未發現有效二維碼</value>
|
||||||
@@ -283,16 +283,16 @@
|
|||||||
<value>是否確定移除伺服器?</value>
|
<value>是否確定移除伺服器?</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="SaveClientConfigurationIn" xml:space="preserve">
|
<data name="SaveClientConfigurationIn" xml:space="preserve">
|
||||||
<value>用戶端配置檔案儲存在:{0}</value>
|
<value>用戶端設定檔儲存在:{0}</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="StartService" xml:space="preserve">
|
<data name="StartService" xml:space="preserve">
|
||||||
<value>啟動服務({0})...</value>
|
<value>啟動服務({0})...</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="SuccessfulConfiguration" xml:space="preserve">
|
<data name="SuccessfulConfiguration" xml:space="preserve">
|
||||||
<value>配置成功{0}</value>
|
<value>設定成功{0}</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="SuccessfullyImportedCustomServer" xml:space="preserve">
|
<data name="SuccessfullyImportedCustomServer" xml:space="preserve">
|
||||||
<value>成功匯入自訂配置伺服器</value>
|
<value>成功匯入自訂設定伺服器</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="SuccessfullyImportedServerViaClipboard" xml:space="preserve">
|
<data name="SuccessfullyImportedServerViaClipboard" xml:space="preserve">
|
||||||
<value>成功從剪貼簿匯入 {0} 個伺服器</value>
|
<value>成功從剪貼簿匯入 {0} 個伺服器</value>
|
||||||
@@ -364,7 +364,7 @@
|
|||||||
<value>*h2 host中間逗號(,)分隔</value>
|
<value>*h2 host中間逗號(,)分隔</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TransportRequestHostTip4" xml:space="preserve">
|
<data name="TransportRequestHostTip4" xml:space="preserve">
|
||||||
<value>*QUIC 加密方式</value>
|
<value>*QUIC加密方式</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TransportHeaderTypeTip1" xml:space="preserve">
|
<data name="TransportHeaderTypeTip1" xml:space="preserve">
|
||||||
<value>*TCP偽裝類型</value>
|
<value>*TCP偽裝類型</value>
|
||||||
@@ -376,7 +376,7 @@
|
|||||||
<value>*QUIC偽裝類型</value>
|
<value>*QUIC偽裝類型</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TransportHeaderTypeTip4" xml:space="preserve">
|
<data name="TransportHeaderTypeTip4" xml:space="preserve">
|
||||||
<value>*GRPC 模式</value>
|
<value>*GRPC模式</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="LvTLS" xml:space="preserve">
|
<data name="LvTLS" xml:space="preserve">
|
||||||
<value>TLS</value>
|
<value>TLS</value>
|
||||||
@@ -397,7 +397,7 @@
|
|||||||
<value>所有</value>
|
<value>所有</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="FillServerAddressCustom" xml:space="preserve">
|
<data name="FillServerAddressCustom" xml:space="preserve">
|
||||||
<value>請瀏覽匯入伺服器配置</value>
|
<value>請瀏覽匯入伺服器設定</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="Speedtesting" xml:space="preserve">
|
<data name="Speedtesting" xml:space="preserve">
|
||||||
<value>測試中...</value>
|
<value>測試中...</value>
|
||||||
@@ -409,7 +409,7 @@
|
|||||||
<value>本機</value>
|
<value>本機</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="MsgServerTitle" xml:space="preserve">
|
<data name="MsgServerTitle" xml:space="preserve">
|
||||||
<value>伺服器過濾器,按Enter執行</value>
|
<value>伺服器過濾,按Enter執行</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuCheckUpdate" xml:space="preserve">
|
<data name="menuCheckUpdate" xml:space="preserve">
|
||||||
<value>檢查更新</value>
|
<value>檢查更新</value>
|
||||||
@@ -475,7 +475,7 @@
|
|||||||
<value>PAC模式</value>
|
<value>PAC模式</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuSystemProxySet" xml:space="preserve">
|
<data name="menuSystemProxySet" xml:space="preserve">
|
||||||
<value>自動配置系統代理</value>
|
<value>自動設定系統代理</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSettingsColor" xml:space="preserve">
|
<data name="TbSettingsColor" xml:space="preserve">
|
||||||
<value>顏色</value>
|
<value>顏色</value>
|
||||||
@@ -523,19 +523,19 @@
|
|||||||
<value>測試伺服器延遲Tcping(多選) (Ctrl+O)</value>
|
<value>測試伺服器延遲Tcping(多選) (Ctrl+O)</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuExport2ClientConfig" xml:space="preserve">
|
<data name="menuExport2ClientConfig" xml:space="preserve">
|
||||||
<value>匯出所選伺服器完整配置</value>
|
<value>匯出所選伺服器完整設定</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuExport2ShareUrl" xml:space="preserve">
|
<data name="menuExport2ShareUrl" xml:space="preserve">
|
||||||
<value>匯出分享链接至剪貼簿(多選) (Ctrl+C)</value>
|
<value>匯出分享链接至剪貼簿(多選) (Ctrl+C)</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuAddCustomServer" xml:space="preserve">
|
<data name="menuAddCustomServer" xml:space="preserve">
|
||||||
<value>新增自訂配置伺服器</value>
|
<value>新增自訂設定伺服器</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuAddShadowsocksServer" xml:space="preserve">
|
<data name="menuAddShadowsocksServer" xml:space="preserve">
|
||||||
<value>新增[Shadowsocks]伺服器</value>
|
<value>新增[Shadowsocks]伺服器</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuAddSocksServer" xml:space="preserve">
|
<data name="menuAddSocksServer" xml:space="preserve">
|
||||||
<value>新增[Socks]伺服器</value>
|
<value>新增[SOCKS]伺服器</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuAddTrojanServer" xml:space="preserve">
|
<data name="menuAddTrojanServer" xml:space="preserve">
|
||||||
<value>新增[Trojan]伺服器</value>
|
<value>新增[Trojan]伺服器</value>
|
||||||
@@ -670,7 +670,7 @@
|
|||||||
<value>SOCKS埠</value>
|
<value>SOCKS埠</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TipPreSocksPort" xml:space="preserve">
|
<data name="TipPreSocksPort" xml:space="preserve">
|
||||||
<value>* 自訂配置的Socks埠值,可不設定;當設定此值後,將使用Xray/sing-box(Tun)額外啟動一個前置Socks服務,提供分流和速度顯示等功能</value>
|
<value>* 自訂設定的Socks埠值,可不設定;當設定此值後,將使用Xray/sing-box(Tun)額外啟動一個前置Socks服務,提供分流和速度顯示等功能</value>
|
||||||
</data>
|
</data>
|
||||||
<!--********************************************-->
|
<!--********************************************-->
|
||||||
<data name="TbBrowse" xml:space="preserve">
|
<data name="TbBrowse" xml:space="preserve">
|
||||||
@@ -689,7 +689,7 @@
|
|||||||
<value>啟動後隱藏視窗</value>
|
<value>啟動後隱藏視窗</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSettingsAutoUpdateInterval" xml:space="preserve">
|
<data name="TbSettingsAutoUpdateInterval" xml:space="preserve">
|
||||||
<value>自動更新Geo文件的間隔(單位小時)</value>
|
<value>自動更新Geo檔案的間隔(單位小時)</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSettingsCore" xml:space="preserve">
|
<data name="TbSettingsCore" xml:space="preserve">
|
||||||
<value>Core: 基礎設定</value>
|
<value>Core: 基礎設定</value>
|
||||||
@@ -719,7 +719,7 @@
|
|||||||
<value>例外</value>
|
<value>例外</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSettingsExceptionTip" xml:space="preserve">
|
<data name="TbSettingsExceptionTip" xml:space="preserve">
|
||||||
<value>例外. 對於下列字元開頭的位址不使用代理配置檔案:使用分號(;)分隔</value>
|
<value>例外. 對於下列字元開頭的位址不使用代理設定檔:使用分號(;)分隔</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSettingsHttpPort" xml:space="preserve">
|
<data name="TbSettingsHttpPort" xml:space="preserve">
|
||||||
<value>本機HTTP監聽埠</value>
|
<value>本機HTTP監聽埠</value>
|
||||||
@@ -800,7 +800,7 @@
|
|||||||
<value>重設</value>
|
<value>重設</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSetSystemProxy" xml:space="preserve">
|
<data name="TbSetSystemProxy" xml:space="preserve">
|
||||||
<value>自動配置系統代理</value>
|
<value>自動設定系統代理</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSystemProxyPac" xml:space="preserve">
|
<data name="TbSystemProxyPac" xml:space="preserve">
|
||||||
<value>PAC模式</value>
|
<value>PAC模式</value>
|
||||||
@@ -830,7 +830,7 @@
|
|||||||
<value>上移 (U)</value>
|
<value>上移 (U)</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="MsgFilterTitle" xml:space="preserve">
|
<data name="MsgFilterTitle" xml:space="preserve">
|
||||||
<value>過濾器, 支援正則</value>
|
<value>過濾, 支援正則</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuWebsiteItem" xml:space="preserve">
|
<data name="menuWebsiteItem" xml:space="preserve">
|
||||||
<value>{0} 官網</value>
|
<value>{0} 官網</value>
|
||||||
@@ -884,7 +884,7 @@
|
|||||||
<value>從剪貼簿中匯入規則</value>
|
<value>從剪貼簿中匯入規則</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuImportRulesFromFile" xml:space="preserve">
|
<data name="menuImportRulesFromFile" xml:space="preserve">
|
||||||
<value>從文件中匯入規則</value>
|
<value>從檔案中匯入規則</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuImportRulesFromUrl" xml:space="preserve">
|
<data name="menuImportRulesFromUrl" xml:space="preserve">
|
||||||
<value>從訂閱URL中匯入規則</value>
|
<value>從訂閱URL中匯入規則</value>
|
||||||
@@ -911,10 +911,10 @@
|
|||||||
<value>儲存時Domain, IP, 行程名 自動排序</value>
|
<value>儲存時Domain, IP, 行程名 自動排序</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbRuleobjectDoc" xml:space="preserve">
|
<data name="TbRuleobjectDoc" xml:space="preserve">
|
||||||
<value>規則詳細說明文件</value>
|
<value>規則詳細說明檔案</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbDnsObjectDoc" xml:space="preserve">
|
<data name="TbDnsObjectDoc" xml:space="preserve">
|
||||||
<value>支援填寫DnsObject,JSON格式,點擊查看文件</value>
|
<value>支援填寫DnsObject,JSON格式,點擊查看檔案</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="SubUrlTips" xml:space="preserve">
|
<data name="SubUrlTips" xml:space="preserve">
|
||||||
<value>普通分組此處請留空</value>
|
<value>普通分組此處請留空</value>
|
||||||
@@ -950,10 +950,10 @@
|
|||||||
<value>顯示日誌</value>
|
<value>顯示日誌</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuImportOldGuiConfig" xml:space="preserve">
|
<data name="menuImportOldGuiConfig" xml:space="preserve">
|
||||||
<value>匯入舊的配置檔案guiNConfig</value>
|
<value>匯入舊的設定檔guiNConfig</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbEnableTunAs" xml:space="preserve">
|
<data name="TbEnableTunAs" xml:space="preserve">
|
||||||
<value>啟用TUN模式</value>
|
<value>啟用TUN</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSettingsNewPort4LAN" xml:space="preserve">
|
<data name="TbSettingsNewPort4LAN" xml:space="preserve">
|
||||||
<value>為區域網路開啟新的埠</value>
|
<value>為區域網路開啟新的埠</value>
|
||||||
@@ -995,7 +995,7 @@
|
|||||||
<value>目前字型(需重啟)</value>
|
<value>目前字型(需重啟)</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSettingsCurrentFontFamilyTip" xml:space="preserve">
|
<data name="TbSettingsCurrentFontFamilyTip" xml:space="preserve">
|
||||||
<value>複製字型TTF/TTC文件到目錄guiFonts,重啟設定</value>
|
<value>複製字型TTF/TTC檔案到目錄guiFonts,重啟設定</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSettingsSocksPortTip" xml:space="preserve">
|
<data name="TbSettingsSocksPortTip" xml:space="preserve">
|
||||||
<value>http端口= +1;Pac端口= +4;*ray API端口= +5;mihomo API端口= +6;</value>
|
<value>http端口= +1;Pac端口= +4;*ray API端口= +5;mihomo API端口= +6;</value>
|
||||||
@@ -1046,7 +1046,7 @@
|
|||||||
<value>自動更新間隔(分鐘)</value>
|
<value>自動更新間隔(分鐘)</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSettingsLogEnabledToFile" xml:space="preserve">
|
<data name="TbSettingsLogEnabledToFile" xml:space="preserve">
|
||||||
<value>啟動日誌存到文件</value>
|
<value>啟動日誌存到檔案</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="LvConvertTarget" xml:space="preserve">
|
<data name="LvConvertTarget" xml:space="preserve">
|
||||||
<value>訂閱轉換目標類型</value>
|
<value>訂閱轉換目標類型</value>
|
||||||
@@ -1061,10 +1061,10 @@
|
|||||||
<value>sing-box DNS設定</value>
|
<value>sing-box DNS設定</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbDnsSingboxObjectDoc" xml:space="preserve">
|
<data name="TbDnsSingboxObjectDoc" xml:space="preserve">
|
||||||
<value>請填寫 DNS JSON 結構,點擊查看文件</value>
|
<value>請填寫 DNS JSON 結構,點擊查看檔案</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSettingDnsImportDefConfig" xml:space="preserve">
|
<data name="TbSettingDnsImportDefConfig" xml:space="preserve">
|
||||||
<value>點擊匯入預設DNS配置</value>
|
<value>點擊匯入預設DNS設定</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbdomainStrategy4Singbox" xml:space="preserve">
|
<data name="TbdomainStrategy4Singbox" xml:space="preserve">
|
||||||
<value>sing-box域名解析策略</value>
|
<value>sing-box域名解析策略</value>
|
||||||
@@ -1082,7 +1082,7 @@
|
|||||||
<value>IP 或 IP CIDR</value>
|
<value>IP 或 IP CIDR</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuAddTuicServer" xml:space="preserve">
|
<data name="menuAddTuicServer" xml:space="preserve">
|
||||||
<value>新增[Tuic]伺服器</value>
|
<value>新增[TUIC]伺服器</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="LvPrevProfile" xml:space="preserve">
|
<data name="LvPrevProfile" xml:space="preserve">
|
||||||
<value>前置代理別名</value>
|
<value>前置代理別名</value>
|
||||||
@@ -1118,7 +1118,7 @@
|
|||||||
<value>*grpc Authority</value>
|
<value>*grpc Authority</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuAddHttpServer" xml:space="preserve">
|
<data name="menuAddHttpServer" xml:space="preserve">
|
||||||
<value>新增[Http]伺服器</value>
|
<value>新增[HTTP]伺服器</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSettingsEnableFragment" xml:space="preserve">
|
<data name="TbSettingsEnableFragment" xml:space="preserve">
|
||||||
<value>啟用分片(Fragment)</value>
|
<value>啟用分片(Fragment)</value>
|
||||||
@@ -1127,7 +1127,7 @@
|
|||||||
<value>使用Xray且非Tun模式啟用,和分組前置代理衝突</value>
|
<value>使用Xray且非Tun模式啟用,和分組前置代理衝突</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSettingsEnableCacheFile4Sbox" xml:space="preserve">
|
<data name="TbSettingsEnableCacheFile4Sbox" xml:space="preserve">
|
||||||
<value>啟用sing-box(規則集文件)的緩存文件</value>
|
<value>啟用sing-box(規則集檔案)的快取檔案</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="LvCustomRulesetPath4Singbox" xml:space="preserve">
|
<data name="LvCustomRulesetPath4Singbox" xml:space="preserve">
|
||||||
<value>自訂sing-box rule-set</value>
|
<value>自訂sing-box rule-set</value>
|
||||||
@@ -1145,7 +1145,7 @@
|
|||||||
<value>匯出分享链接至剪貼簿(多選) Base64编码</value>
|
<value>匯出分享链接至剪貼簿(多選) Base64编码</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuExport2ClientConfigClipboard" xml:space="preserve">
|
<data name="menuExport2ClientConfigClipboard" xml:space="preserve">
|
||||||
<value>匯出所選伺服器完整配置至剪貼簿</value>
|
<value>匯出所選伺服器完整設定至剪貼簿</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuShowOrHideMainWindow" xml:space="preserve">
|
<data name="menuShowOrHideMainWindow" xml:space="preserve">
|
||||||
<value>顯示或隱藏主介面</value>
|
<value>顯示或隱藏主介面</value>
|
||||||
@@ -1154,6 +1154,96 @@
|
|||||||
<value>您目前運行的是獨立包,請手動下載 SelfContained.7z檔案解壓縮覆蓋</value>
|
<value>您目前運行的是獨立包,請手動下載 SelfContained.7z檔案解壓縮覆蓋</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbPreSocksPort4Sub" xml:space="preserve">
|
<data name="TbPreSocksPort4Sub" xml:space="preserve">
|
||||||
<value>自訂配置的Socks端口</value>
|
<value>自訂設定的Socks端口</value>
|
||||||
|
</data>
|
||||||
|
<data name="menuBackupAndRestore" xml:space="preserve">
|
||||||
|
<value>備份和還原</value>
|
||||||
|
</data>
|
||||||
|
<data name="menuLocalBackup" xml:space="preserve">
|
||||||
|
<value>備份到本地</value>
|
||||||
|
</data>
|
||||||
|
<data name="menuLocalRestore" xml:space="preserve">
|
||||||
|
<value>從本地恢復</value>
|
||||||
|
</data>
|
||||||
|
<data name="menuRemoteBackup" xml:space="preserve">
|
||||||
|
<value>備份到遠端 (WebDAV)</value>
|
||||||
|
</data>
|
||||||
|
<data name="menuRemoteRestore" xml:space="preserve">
|
||||||
|
<value>從遠端恢復 (WebDAV)</value>
|
||||||
|
</data>
|
||||||
|
<data name="menuLocalBackupAndRestore" xml:space="preserve">
|
||||||
|
<value>本地</value>
|
||||||
|
</data>
|
||||||
|
<data name="menuRemoteBackupAndRestore" xml:space="preserve">
|
||||||
|
<value>遠端 (WebDAV)</value>
|
||||||
|
</data>
|
||||||
|
<data name="LvWebDavUserName" xml:space="preserve">
|
||||||
|
<value>WebDav 賬戶</value>
|
||||||
|
</data>
|
||||||
|
<data name="LvWebDavCheck" xml:space="preserve">
|
||||||
|
<value>WebDav 可用檢查</value>
|
||||||
|
</data>
|
||||||
|
<data name="LvWebDavPassword" xml:space="preserve">
|
||||||
|
<value>WebDav 密碼</value>
|
||||||
|
</data>
|
||||||
|
<data name="LvWebDavUrl" xml:space="preserve">
|
||||||
|
<value>WebDav 伺服器地址</value>
|
||||||
|
</data>
|
||||||
|
<data name="LvWebDavDirName" xml:space="preserve">
|
||||||
|
<value>遠端資料夾名稱(可選)</value>
|
||||||
|
</data>
|
||||||
|
<data name="LocalRestoreInvalidZipTips" xml:space="preserve">
|
||||||
|
<value>無效備份檔案</value>
|
||||||
|
</data>
|
||||||
|
<data name="ConnectionsHostFilterTitle" xml:space="preserve">
|
||||||
|
<value>主機過濾</value>
|
||||||
|
</data>
|
||||||
|
<data name="TipActiveServer" xml:space="preserve">
|
||||||
|
<value>活動</value>
|
||||||
|
</data>
|
||||||
|
<data name="menuStorageUI" xml:space="preserve">
|
||||||
|
<value>儲存介面佈局</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbSettingsGeoFilesSource" xml:space="preserve">
|
||||||
|
<value>Geo文件來源(可選)</value>
|
||||||
|
</data>
|
||||||
|
<data name="UpgradeAppNotExistTip" xml:space="preserve">
|
||||||
|
<value>升级工具App不存在</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbSettingsSrsFilesSource" xml:space="preserve">
|
||||||
|
<value>sing-box ruleset文件來源(可選)</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbSettingsRoutingRulesSource" xml:space="preserve">
|
||||||
|
<value>路由规则集来源(可选)</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbSettingsChinaUserTip" xml:space="preserve">
|
||||||
|
<value>中国区域用户可忽略此项</value>
|
||||||
|
</data>
|
||||||
|
<data name="menuRegionalPresets" xml:space="preserve">
|
||||||
|
<value>区域预置设置</value>
|
||||||
|
</data>
|
||||||
|
<data name="menuRegionalPresetsDefault" xml:space="preserve">
|
||||||
|
<value>默认区域</value>
|
||||||
|
</data>
|
||||||
|
<data name="menuRegionalPresetsRussia" xml:space="preserve">
|
||||||
|
<value>俄羅斯</value>
|
||||||
|
</data>
|
||||||
|
<data name="menuAddServerViaImage" xml:space="preserve">
|
||||||
|
<value>掃描圖片中的二維碼</value>
|
||||||
|
</data>
|
||||||
|
<data name="InvalidUrlTip" xml:space="preserve">
|
||||||
|
<value>地址(Url)無效</value>
|
||||||
|
</data>
|
||||||
|
<data name="InsecureUrlProtocol" xml:space="preserve">
|
||||||
|
<value>請不要使用不安全的HTTP協定訂閱位址</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbSettingsCurrentFontFamilyLinuxTip" xml:space="preserve">
|
||||||
|
<value>安裝字體到系統中,重新啟動設定</value>
|
||||||
|
</data>
|
||||||
|
<data name="menuExitTips" xml:space="preserve">
|
||||||
|
<value>是否確定退出?</value>
|
||||||
|
</data>
|
||||||
|
<data name="LvMemo" xml:space="preserve">
|
||||||
|
<value>備註備忘</value>
|
||||||
</data>
|
</data>
|
||||||
</root>
|
</root>
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user