diff --git a/v2rayN/PacLib/PacLib.csproj b/v2rayN/PacLib/PacLib.csproj
index ed5be34b..ef8e4cda 100644
--- a/v2rayN/PacLib/PacLib.csproj
+++ b/v2rayN/PacLib/PacLib.csproj
@@ -1,20 +1,17 @@
-
- net6.0-windows
+ net7.0
enable
-
True
True
Resources.resx
-
+
ResXFileCodeGenerator
Resources.Designer.cs
-
-
+
\ No newline at end of file
diff --git a/v2rayN/ProtosLib/ProtosLib.csproj b/v2rayN/ProtosLib/ProtosLib.csproj
index fac333e5..697457b9 100644
--- a/v2rayN/ProtosLib/ProtosLib.csproj
+++ b/v2rayN/ProtosLib/ProtosLib.csproj
@@ -1,20 +1,17 @@
- net6.0-windows
- enable
+ net7.0
+ enable
-
-
-
-
-
-
-
-
-
- all
- runtime; build; native; contentfiles; analyzers; buildtransitive
-
-
-
-
+
+
+
+
+
+
+
+ all
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+
+
+
\ No newline at end of file
diff --git a/v2rayN/ProtosLib/Tests.cs b/v2rayN/ProtosLib/Tests.cs
index e1eb85b1..62a19b0f 100644
--- a/v2rayN/ProtosLib/Tests.cs
+++ b/v2rayN/ProtosLib/Tests.cs
@@ -1,13 +1,12 @@
using ProtosLib.Statistics;
-namespace ProtosLib
-{
- public class Tests
- {
- private StatsService.StatsServiceClient client_;
+namespace ProtosLib;
- public Tests()
- {
- }
+public class Tests
+{
+ private StatsService.StatsServiceClient client_;
+
+ public Tests()
+ {
}
}
\ No newline at end of file
diff --git a/v2rayN/v2rayN/App.xaml.cs b/v2rayN/v2rayN/App.xaml.cs
index 37ca3478..75ede10d 100644
--- a/v2rayN/v2rayN/App.xaml.cs
+++ b/v2rayN/v2rayN/App.xaml.cs
@@ -4,87 +4,86 @@ using v2rayN.Handler;
using v2rayN.Mode;
using v2rayN.Tool;
-namespace v2rayN
+namespace v2rayN;
+
+///
+/// Interaction logic for App.xaml
+///
+public partial class App : Application
{
- ///
- /// Interaction logic for App.xaml
- ///
- public partial class App : Application
+ public static EventWaitHandle ProgramStarted;
+ private static Config _config;
+
+ public App()
{
- public static EventWaitHandle ProgramStarted;
- private static Config _config;
+ // Locator.CurrentMutable.RegisterViewsForViewModels(Assembly.GetCallingAssembly());
+ this.DispatcherUnhandledException += App_DispatcherUnhandledException;
+ AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException;
+ TaskScheduler.UnobservedTaskException += TaskScheduler_UnobservedTaskException;
+ }
- public App()
+ ///
+ /// 只打开一个进程
+ ///
+ ///
+ protected override void OnStartup(StartupEventArgs e)
+ {
+ Global.ExePathKey = Utils.GetMD5(Utils.GetExePath());
+
+ var rebootas = (e.Args ?? new string[] { }).Any(t => t == Global.RebootAs);
+ ProgramStarted = new EventWaitHandle(false, EventResetMode.AutoReset, Global.ExePathKey, out bool bCreatedNew);
+ if (!rebootas && !bCreatedNew)
{
- // Locator.CurrentMutable.RegisterViewsForViewModels(Assembly.GetCallingAssembly());
- this.DispatcherUnhandledException += App_DispatcherUnhandledException;
- AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException;
- TaskScheduler.UnobservedTaskException += TaskScheduler_UnobservedTaskException;
+ ProgramStarted.Set();
+ Current.Shutdown();
+ Environment.Exit(0);
+ return;
}
- ///
- /// 只打开一个进程
- ///
- ///
- protected override void OnStartup(StartupEventArgs e)
+ Global.processJob = new Job();
+
+ Logging.Setup();
+ Init();
+ Logging.LoggingEnabled(_config.guiItem.enableLog);
+ Utils.SaveLog($"v2rayN start up | {Utils.GetVersion()} | {Utils.GetExePath()}");
+ Logging.ClearLogs();
+
+ Thread.CurrentThread.CurrentUICulture = new(_config.uiItem.currentLanguage);
+
+ base.OnStartup(e);
+ }
+
+ private void Init()
+ {
+ if (ConfigHandler.LoadConfig(ref _config) != 0)
{
- Global.ExePathKey = Utils.GetMD5(Utils.GetExePath());
-
- var rebootas = (e.Args ?? new string[] { }).Any(t => t == Global.RebootAs);
- ProgramStarted = new EventWaitHandle(false, EventResetMode.AutoReset, Global.ExePathKey, out bool bCreatedNew);
- if (!rebootas && !bCreatedNew)
- {
- ProgramStarted.Set();
- Current.Shutdown();
- Environment.Exit(0);
- return;
- }
-
- Global.processJob = new Job();
-
- Logging.Setup();
- Init();
- Logging.LoggingEnabled(_config.guiItem.enableLog);
- Utils.SaveLog($"v2rayN start up | {Utils.GetVersion()} | {Utils.GetExePath()}");
- Logging.ClearLogs();
-
- Thread.CurrentThread.CurrentUICulture = new(_config.uiItem.currentLanguage);
-
- base.OnStartup(e);
+ UI.ShowWarning($"Loading GUI configuration file is abnormal,please restart the application{Environment.NewLine}加载GUI配置文件异常,请重启应用");
+ Application.Current.Shutdown();
+ Environment.Exit(0);
+ return;
}
+ //if (RuntimeInformation.ProcessArchitecture != Architecture.X86 && RuntimeInformation.ProcessArchitecture != Architecture.X64)
+ //{
+ // _config.guiItem.enableStatistics = false;
+ //}
+ }
- private void Init()
- {
- if (ConfigHandler.LoadConfig(ref _config) != 0)
- {
- UI.ShowWarning($"Loading GUI configuration file is abnormal,please restart the application{Environment.NewLine}加载GUI配置文件异常,请重启应用");
- Application.Current.Shutdown();
- Environment.Exit(0);
- return;
- }
- //if (RuntimeInformation.ProcessArchitecture != Architecture.X86 && RuntimeInformation.ProcessArchitecture != Architecture.X64)
- //{
- // _config.guiItem.enableStatistics = false;
- //}
- }
+ private void App_DispatcherUnhandledException(object sender, DispatcherUnhandledExceptionEventArgs e)
+ {
+ Utils.SaveLog("App_DispatcherUnhandledException", e.Exception);
+ e.Handled = true;
+ }
- private void App_DispatcherUnhandledException(object sender, DispatcherUnhandledExceptionEventArgs e)
+ private void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
+ {
+ if (e.ExceptionObject != null)
{
- Utils.SaveLog("App_DispatcherUnhandledException", e.Exception);
- e.Handled = true;
- }
-
- private void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
- {
- if (e.ExceptionObject != null)
- {
- Utils.SaveLog("CurrentDomain_UnhandledException", (Exception)e.ExceptionObject!);
- }
- }
-
- private void TaskScheduler_UnobservedTaskException(object? sender, UnobservedTaskExceptionEventArgs e)
- {
- Utils.SaveLog("TaskScheduler_UnobservedTaskException", e.Exception);
+ Utils.SaveLog("CurrentDomain_UnhandledException", (Exception)e.ExceptionObject!);
}
}
+
+ private void TaskScheduler_UnobservedTaskException(object? sender, UnobservedTaskExceptionEventArgs e)
+ {
+ Utils.SaveLog("TaskScheduler_UnobservedTaskException", e.Exception);
+ }
}
\ No newline at end of file
diff --git a/v2rayN/v2rayN/Base/DownloaderHelper.cs b/v2rayN/v2rayN/Base/DownloaderHelper.cs
index 51a7840b..3bdb7afc 100644
--- a/v2rayN/v2rayN/Base/DownloaderHelper.cs
+++ b/v2rayN/v2rayN/Base/DownloaderHelper.cs
@@ -2,180 +2,179 @@
using System.IO;
using System.Net;
-namespace v2rayN.Base
+namespace v2rayN.Base;
+
+internal class DownloaderHelper
{
- internal class DownloaderHelper
+ private static readonly Lazy _instance = new(() => new());
+ public static DownloaderHelper Instance => _instance.Value;
+
+ public async Task DownloadStringAsync(IWebProxy? webProxy, string url, string? userAgent, int timeout)
{
- private static readonly Lazy _instance = new(() => new());
- public static DownloaderHelper Instance => _instance.Value;
-
- public async Task DownloadStringAsync(IWebProxy? webProxy, string url, string? userAgent, int timeout)
+ if (string.IsNullOrEmpty(url))
{
- if (string.IsNullOrEmpty(url))
- {
- return null;
- }
-
- Uri uri = new(url);
- //Authorization Header
- var headers = new WebHeaderCollection();
- if (!Utils.IsNullOrEmpty(uri.UserInfo))
- {
- headers.Add(HttpRequestHeader.Authorization, "Basic " + Utils.Base64Encode(uri.UserInfo));
- }
-
- var downloadOpt = new DownloadConfiguration()
- {
- Timeout = timeout * 1000,
- MaxTryAgainOnFailover = 2,
- RequestConfiguration =
- {
- Headers = headers,
- UserAgent = userAgent,
- Timeout = timeout * 1000,
- Proxy = webProxy
- }
- };
-
- using var downloader = new DownloadService(downloadOpt);
- downloader.DownloadFileCompleted += (sender, value) =>
- {
- if (value.Error != null)
- {
- throw value.Error;
- }
- };
-
- using var cts = new CancellationTokenSource();
- using var stream = await downloader.DownloadFileTaskAsync(address: url, cts.Token).WaitAsync(TimeSpan.FromSeconds(timeout), cts.Token);
- using StreamReader reader = new(stream);
-
- downloadOpt = null;
-
- return reader.ReadToEnd();
+ return null;
}
- public async Task DownloadDataAsync4Speed(IWebProxy webProxy, string url, IProgress progress, int timeout)
+ Uri uri = new(url);
+ //Authorization Header
+ var headers = new WebHeaderCollection();
+ if (!Utils.IsNullOrEmpty(uri.UserInfo))
{
- if (string.IsNullOrEmpty(url))
- {
- throw new ArgumentNullException(nameof(url));
- }
-
- var downloadOpt = new DownloadConfiguration()
- {
- Timeout = timeout * 1000,
- MaxTryAgainOnFailover = 2,
- RequestConfiguration =
- {
- Timeout= timeout * 1000,
- Proxy = webProxy
- }
- };
-
- DateTime totalDatetime = DateTime.Now;
- int totalSecond = 0;
- var hasValue = false;
- double maxSpeed = 0;
- using var downloader = new DownloadService(downloadOpt);
- //downloader.DownloadStarted += (sender, value) =>
- //{
- // if (progress != null)
- // {
- // progress.Report("Start download data...");
- // }
- //};
- downloader.DownloadProgressChanged += (sender, value) =>
- {
- TimeSpan ts = (DateTime.Now - totalDatetime);
- if (progress != null && ts.Seconds > totalSecond)
- {
- hasValue = true;
- totalSecond = ts.Seconds;
- if (value.BytesPerSecondSpeed > maxSpeed)
- {
- maxSpeed = value.BytesPerSecondSpeed;
- var speed = (maxSpeed / 1000 / 1000).ToString("#0.0");
- progress.Report(speed);
- }
- }
- };
- downloader.DownloadFileCompleted += (sender, value) =>
- {
- if (progress != null)
- {
- if (!hasValue && value.Error != null)
- {
- progress.Report(value.Error?.Message);
- }
- }
- };
- //progress.Report("......");
- using var cts = new CancellationTokenSource();
- cts.CancelAfter(timeout * 1000);
- using var stream = await downloader.DownloadFileTaskAsync(address: url, cts.Token);
-
- downloadOpt = null;
+ headers.Add(HttpRequestHeader.Authorization, "Basic " + Utils.Base64Encode(uri.UserInfo));
}
- public async Task DownloadFileAsync(IWebProxy? webProxy, string url, string fileName, IProgress progress, int timeout)
+ var downloadOpt = new DownloadConfiguration()
{
- if (string.IsNullOrEmpty(url))
- {
- throw new ArgumentNullException(nameof(url));
- }
- if (string.IsNullOrEmpty(fileName))
- {
- throw new ArgumentNullException(nameof(fileName));
- }
- if (File.Exists(fileName))
- {
- File.Delete(fileName);
- }
-
- var downloadOpt = new DownloadConfiguration()
+ Timeout = timeout * 1000,
+ MaxTryAgainOnFailover = 2,
+ RequestConfiguration =
{
+ Headers = headers,
+ UserAgent = userAgent,
Timeout = timeout * 1000,
- MaxTryAgainOnFailover = 2,
- RequestConfiguration =
- {
- Timeout= timeout * 1000,
- Proxy = webProxy
- }
- };
+ Proxy = webProxy
+ }
+ };
- var progressPercentage = 0;
- var hasValue = false;
- using var downloader = new DownloadService(downloadOpt);
- downloader.DownloadStarted += (sender, value) =>
+ using var downloader = new DownloadService(downloadOpt);
+ downloader.DownloadFileCompleted += (sender, value) =>
+ {
+ if (value.Error != null)
{
- progress?.Report(0);
- };
- downloader.DownloadProgressChanged += (sender, value) =>
+ throw value.Error;
+ }
+ };
+
+ using var cts = new CancellationTokenSource();
+ using var stream = await downloader.DownloadFileTaskAsync(address: url, cts.Token).WaitAsync(TimeSpan.FromSeconds(timeout), cts.Token);
+ using StreamReader reader = new(stream);
+
+ downloadOpt = null;
+
+ return reader.ReadToEnd();
+ }
+
+ public async Task DownloadDataAsync4Speed(IWebProxy webProxy, string url, IProgress progress, int timeout)
+ {
+ if (string.IsNullOrEmpty(url))
+ {
+ throw new ArgumentNullException(nameof(url));
+ }
+
+ var downloadOpt = new DownloadConfiguration()
+ {
+ Timeout = timeout * 1000,
+ MaxTryAgainOnFailover = 2,
+ RequestConfiguration =
+ {
+ Timeout= timeout * 1000,
+ Proxy = webProxy
+ }
+ };
+
+ DateTime totalDatetime = DateTime.Now;
+ int totalSecond = 0;
+ var hasValue = false;
+ double maxSpeed = 0;
+ using var downloader = new DownloadService(downloadOpt);
+ //downloader.DownloadStarted += (sender, value) =>
+ //{
+ // if (progress != null)
+ // {
+ // progress.Report("Start download data...");
+ // }
+ //};
+ downloader.DownloadProgressChanged += (sender, value) =>
+ {
+ TimeSpan ts = (DateTime.Now - totalDatetime);
+ if (progress != null && ts.Seconds > totalSecond)
{
hasValue = true;
- var percent = (int)value.ProgressPercentage;// Convert.ToInt32((totalRead * 1d) / (total * 1d) * 100);
- if (progressPercentage != percent && percent % 10 == 0)
+ totalSecond = ts.Seconds;
+ if (value.BytesPerSecondSpeed > maxSpeed)
{
- progressPercentage = percent;
- progress.Report(percent);
+ maxSpeed = value.BytesPerSecondSpeed;
+ var speed = (maxSpeed / 1000 / 1000).ToString("#0.0");
+ progress.Report(speed);
}
- };
- downloader.DownloadFileCompleted += (sender, value) =>
+ }
+ };
+ downloader.DownloadFileCompleted += (sender, value) =>
+ {
+ if (progress != null)
{
- if (progress != null)
+ if (!hasValue && value.Error != null)
{
- if (hasValue && value.Error == null)
- {
- progress.Report(101);
- }
+ progress.Report(value.Error?.Message);
}
- };
+ }
+ };
+ //progress.Report("......");
+ using var cts = new CancellationTokenSource();
+ cts.CancelAfter(timeout * 1000);
+ using var stream = await downloader.DownloadFileTaskAsync(address: url, cts.Token);
- using var cts = new CancellationTokenSource();
- await downloader.DownloadFileTaskAsync(url, fileName, cts.Token).WaitAsync(TimeSpan.FromSeconds(timeout), cts.Token);
+ downloadOpt = null;
+ }
- downloadOpt = null;
+ public async Task DownloadFileAsync(IWebProxy? webProxy, string url, string fileName, IProgress progress, int timeout)
+ {
+ if (string.IsNullOrEmpty(url))
+ {
+ throw new ArgumentNullException(nameof(url));
}
+ if (string.IsNullOrEmpty(fileName))
+ {
+ throw new ArgumentNullException(nameof(fileName));
+ }
+ if (File.Exists(fileName))
+ {
+ File.Delete(fileName);
+ }
+
+ var downloadOpt = new DownloadConfiguration()
+ {
+ Timeout = timeout * 1000,
+ MaxTryAgainOnFailover = 2,
+ RequestConfiguration =
+ {
+ Timeout= timeout * 1000,
+ Proxy = webProxy
+ }
+ };
+
+ var progressPercentage = 0;
+ var hasValue = false;
+ using var downloader = new DownloadService(downloadOpt);
+ downloader.DownloadStarted += (sender, value) =>
+ {
+ progress?.Report(0);
+ };
+ downloader.DownloadProgressChanged += (sender, value) =>
+ {
+ hasValue = true;
+ var percent = (int)value.ProgressPercentage;// Convert.ToInt32((totalRead * 1d) / (total * 1d) * 100);
+ if (progressPercentage != percent && percent % 10 == 0)
+ {
+ progressPercentage = percent;
+ progress.Report(percent);
+ }
+ };
+ downloader.DownloadFileCompleted += (sender, value) =>
+ {
+ if (progress != null)
+ {
+ if (hasValue && value.Error == null)
+ {
+ progress.Report(101);
+ }
+ }
+ };
+
+ using var cts = new CancellationTokenSource();
+ await downloader.DownloadFileTaskAsync(url, fileName, cts.Token).WaitAsync(TimeSpan.FromSeconds(timeout), cts.Token);
+
+ downloadOpt = null;
}
}
\ No newline at end of file
diff --git a/v2rayN/v2rayN/Base/HttpClientHelper.cs b/v2rayN/v2rayN/Base/HttpClientHelper.cs
index 72d9d3c6..a1c31ab9 100644
--- a/v2rayN/v2rayN/Base/HttpClientHelper.cs
+++ b/v2rayN/v2rayN/Base/HttpClientHelper.cs
@@ -3,154 +3,153 @@ using System.Net.Http;
using System.Net.Mime;
using System.Text;
-namespace v2rayN.Base
+namespace v2rayN.Base;
+
+///
+///
+public class HttpClientHelper
{
- ///
- ///
- public class HttpClientHelper
+ private static readonly Lazy _instance = new(() =>
{
- private static readonly Lazy _instance = new(() =>
+ HttpClientHandler handler = new() { UseCookies = false };
+ HttpClientHelper helper = new(new HttpClient(handler));
+ return helper;
+ });
+
+ public static HttpClientHelper Instance => _instance.Value;
+ private readonly HttpClient httpClient;
+
+ private HttpClientHelper(HttpClient httpClient) => this.httpClient = httpClient;
+
+ public async Task GetAsync(string url)
+ {
+ if (string.IsNullOrEmpty(url)) return null;
+ return await httpClient.GetStringAsync(url);
+ }
+
+ public async Task GetAsync(HttpClient client, string url, CancellationToken token = default)
+ {
+ if (string.IsNullOrWhiteSpace(url)) return null;
+ return await client.GetStringAsync(url, token);
+ }
+
+ public async Task PutAsync(string url, Dictionary headers)
+ {
+ var jsonContent = Utils.ToJson(headers);
+ var content = new StringContent(jsonContent, Encoding.UTF8, MediaTypeNames.Application.Json);
+
+ var result = await httpClient.PutAsync(url, content);
+ }
+
+ public static async Task DownloadFileAsync(HttpClient client, string url, string fileName, IProgress? progress, CancellationToken token = default)
+ {
+ ArgumentNullException.ThrowIfNull(url);
+ ArgumentNullException.ThrowIfNull(fileName);
+ if (File.Exists(fileName)) File.Delete(fileName);
+
+ using var response = await client.GetAsync(url, HttpCompletionOption.ResponseHeadersRead, token);
+
+ if (!response.IsSuccessStatusCode) throw new Exception(response.StatusCode.ToString());
+
+ var total = response.Content.Headers.ContentLength ?? -1L;
+ var canReportProgress = total != -1 && progress != null;
+
+ using var stream = await response.Content.ReadAsStreamAsync(token);
+ using var file = File.Create(fileName);
+ var totalRead = 0L;
+ var buffer = new byte[1024 * 1024];
+ var progressPercentage = 0;
+
+ while (true)
{
- HttpClientHandler handler = new() { UseCookies = false };
- HttpClientHelper helper = new(new HttpClient(handler));
- return helper;
- });
+ token.ThrowIfCancellationRequested();
- public static HttpClientHelper Instance => _instance.Value;
- private readonly HttpClient httpClient;
+ var read = await stream.ReadAsync(buffer, token);
+ totalRead += read;
- private HttpClientHelper(HttpClient httpClient) => this.httpClient = httpClient;
+ if (read == 0) break;
+ file.Write(buffer, 0, read);
- public async Task GetAsync(string url)
- {
- if (string.IsNullOrEmpty(url)) return null;
- return await httpClient.GetStringAsync(url);
- }
-
- public async Task GetAsync(HttpClient client, string url, CancellationToken token = default)
- {
- if (string.IsNullOrWhiteSpace(url)) return null;
- return await client.GetStringAsync(url, token);
- }
-
- public async Task PutAsync(string url, Dictionary headers)
- {
- var jsonContent = Utils.ToJson(headers);
- var content = new StringContent(jsonContent, Encoding.UTF8, MediaTypeNames.Application.Json);
-
- var result = await httpClient.PutAsync(url, content);
- }
-
- public static async Task DownloadFileAsync(HttpClient client, string url, string fileName, IProgress? progress, CancellationToken token = default)
- {
- ArgumentNullException.ThrowIfNull(url);
- ArgumentNullException.ThrowIfNull(fileName);
- if (File.Exists(fileName)) File.Delete(fileName);
-
- using var response = await client.GetAsync(url, HttpCompletionOption.ResponseHeadersRead, token);
-
- if (!response.IsSuccessStatusCode) throw new Exception(response.StatusCode.ToString());
-
- var total = response.Content.Headers.ContentLength ?? -1L;
- var canReportProgress = total != -1 && progress != null;
-
- using var stream = await response.Content.ReadAsStreamAsync(token);
- using var file = File.Create(fileName);
- var totalRead = 0L;
- var buffer = new byte[1024 * 1024];
- var progressPercentage = 0;
-
- while (true)
- {
- token.ThrowIfCancellationRequested();
-
- var read = await stream.ReadAsync(buffer, token);
- totalRead += read;
-
- if (read == 0) break;
- file.Write(buffer, 0, read);
-
- if (canReportProgress)
- {
- var percent = (int)(100.0 * totalRead / total);
- //if (progressPercentage != percent && percent % 10 == 0)
- {
- progressPercentage = percent;
- progress!.Report(percent);
- }
- }
- }
if (canReportProgress)
{
- progress!.Report(101);
+ var percent = (int)(100.0 * totalRead / total);
+ //if (progressPercentage != percent && percent % 10 == 0)
+ {
+ progressPercentage = percent;
+ progress!.Report(percent);
+ }
}
}
-
- public async Task DownloadDataAsync4Speed(HttpClient client, string url, IProgress progress, CancellationToken token = default)
+ if (canReportProgress)
{
- if (string.IsNullOrEmpty(url))
+ progress!.Report(101);
+ }
+ }
+
+ public async Task DownloadDataAsync4Speed(HttpClient client, string url, IProgress progress, CancellationToken token = default)
+ {
+ if (string.IsNullOrEmpty(url))
+ {
+ throw new ArgumentNullException(nameof(url));
+ }
+
+ var response = await client.GetAsync(url, HttpCompletionOption.ResponseHeadersRead, token);
+
+ if (!response.IsSuccessStatusCode)
+ {
+ throw new Exception(response.StatusCode.ToString());
+ }
+
+ //var total = response.Content.Headers.ContentLength.HasValue ? response.Content.Headers.ContentLength.Value : -1L;
+ //var canReportProgress = total != -1 && progress != null;
+
+ using var stream = await response.Content.ReadAsStreamAsync(token);
+ var totalRead = 0L;
+ var buffer = new byte[1024 * 64];
+ var isMoreToRead = true;
+ string progressSpeed = string.Empty;
+ DateTime totalDatetime = DateTime.Now;
+ int totalSecond = 0;
+
+ do
+ {
+ if (token.IsCancellationRequested)
{
- throw new ArgumentNullException(nameof(url));
- }
-
- var response = await client.GetAsync(url, HttpCompletionOption.ResponseHeadersRead, token);
-
- if (!response.IsSuccessStatusCode)
- {
- throw new Exception(response.StatusCode.ToString());
- }
-
- //var total = response.Content.Headers.ContentLength.HasValue ? response.Content.Headers.ContentLength.Value : -1L;
- //var canReportProgress = total != -1 && progress != null;
-
- using var stream = await response.Content.ReadAsStreamAsync(token);
- var totalRead = 0L;
- var buffer = new byte[1024 * 64];
- var isMoreToRead = true;
- string progressSpeed = string.Empty;
- DateTime totalDatetime = DateTime.Now;
- int totalSecond = 0;
-
- do
- {
- if (token.IsCancellationRequested)
+ if (totalRead > 0)
{
- if (totalRead > 0)
- {
- return;
- }
- else
- {
- token.ThrowIfCancellationRequested();
- }
- }
-
- var read = await stream.ReadAsync(buffer, token);
-
- if (read == 0)
- {
- isMoreToRead = false;
+ return;
}
else
{
- var data = new byte[read];
- buffer.ToList().CopyTo(0, data, 0, read);
+ token.ThrowIfCancellationRequested();
+ }
+ }
- totalRead += read;
+ var read = await stream.ReadAsync(buffer, token);
- TimeSpan ts = (DateTime.Now - totalDatetime);
- if (progress != null && ts.Seconds > totalSecond)
+ if (read == 0)
+ {
+ isMoreToRead = false;
+ }
+ else
+ {
+ var data = new byte[read];
+ buffer.ToList().CopyTo(0, data, 0, read);
+
+ totalRead += read;
+
+ TimeSpan ts = (DateTime.Now - totalDatetime);
+ if (progress != null && ts.Seconds > totalSecond)
+ {
+ totalSecond = ts.Seconds;
+ var speed = (totalRead * 1d / ts.TotalMilliseconds / 1000).ToString("#0.0");
+ if (progressSpeed != speed)
{
- totalSecond = ts.Seconds;
- var speed = (totalRead * 1d / ts.TotalMilliseconds / 1000).ToString("#0.0");
- if (progressSpeed != speed)
- {
- progressSpeed = speed;
- progress.Report(speed);
- }
+ progressSpeed = speed;
+ progress.Report(speed);
}
}
- } while (isMoreToRead);
- }
+ }
+ } while (isMoreToRead);
}
}
\ No newline at end of file
diff --git a/v2rayN/v2rayN/Base/MyDGTextColumn.cs b/v2rayN/v2rayN/Base/MyDGTextColumn.cs
index 427ffacc..c46ebb05 100644
--- a/v2rayN/v2rayN/Base/MyDGTextColumn.cs
+++ b/v2rayN/v2rayN/Base/MyDGTextColumn.cs
@@ -1,9 +1,8 @@
using System.Windows.Controls;
-namespace v2rayN.Base
+namespace v2rayN.Base;
+
+internal class MyDGTextColumn : DataGridTextColumn
{
- internal class MyDGTextColumn : DataGridTextColumn
- {
- public string ExName { get; set; }
- }
+ public string ExName { get; set; }
}
\ No newline at end of file
diff --git a/v2rayN/v2rayN/Base/SqliteHelper.cs b/v2rayN/v2rayN/Base/SqliteHelper.cs
index 7903f3f1..925ed879 100644
--- a/v2rayN/v2rayN/Base/SqliteHelper.cs
+++ b/v2rayN/v2rayN/Base/SqliteHelper.cs
@@ -1,122 +1,121 @@
using SQLite;
using System.Collections;
-namespace v2rayN.Base
+namespace v2rayN.Base;
+
+public sealed class SqliteHelper
{
- public sealed class SqliteHelper
+ private static readonly Lazy _instance = new(() => new());
+ public static SqliteHelper Instance => _instance.Value;
+ private string _connstr;
+ private SQLiteConnection _db;
+ private SQLiteAsyncConnection _dbAsync;
+ private static readonly object objLock = new();
+
+ public SqliteHelper()
{
- private static readonly Lazy _instance = new(() => new());
- public static SqliteHelper Instance => _instance.Value;
- private string _connstr;
- private SQLiteConnection _db;
- private SQLiteAsyncConnection _dbAsync;
- private static readonly object objLock = new();
+ _connstr = Utils.GetConfigPath(Global.ConfigDB);
+ _db = new SQLiteConnection(_connstr, false);
+ _dbAsync = new SQLiteAsyncConnection(_connstr, false);
+ }
- public SqliteHelper()
- {
- _connstr = Utils.GetConfigPath(Global.ConfigDB);
- _db = new SQLiteConnection(_connstr, false);
- _dbAsync = new SQLiteAsyncConnection(_connstr, false);
- }
+ public CreateTableResult CreateTable()
+ {
+ return _db.CreateTable();
+ }
- public CreateTableResult CreateTable()
- {
- return _db.CreateTable();
- }
+ public int Insert(object model)
+ {
+ return _db.Insert(model);
+ }
- public int Insert(object model)
+ public int InsertAll(IEnumerable models)
+ {
+ lock (objLock)
{
- return _db.Insert(model);
- }
-
- public int InsertAll(IEnumerable models)
- {
- lock (objLock)
- {
- return _db.InsertAll(models);
- }
- }
-
- public async Task InsertAsync(object model)
- {
- return await _dbAsync.InsertAsync(model);
- }
-
- public int Replace(object model)
- {
- lock (objLock)
- {
- return _db.InsertOrReplace(model);
- }
- }
-
- public async Task Replacesync(object model)
- {
- return await _dbAsync.InsertOrReplaceAsync(model);
- }
-
- public int Update(object model)
- {
- lock (objLock)
- {
- return _db.Update(model);
- }
- }
-
- public async Task UpdateAsync(object model)
- {
- return await _dbAsync.UpdateAsync(model);
- }
-
- public int UpdateAll(IEnumerable models)
- {
- lock (objLock)
- {
- return _db.UpdateAll(models);
- }
- }
-
- public int Delete(object model)
- {
- lock (objLock)
- {
- return _db.Delete(model);
- }
- }
-
- public async Task DeleteAsync(object model)
- {
- return await _dbAsync.DeleteAsync(model);
- }
-
- public List Query(string sql) where T : new()
- {
- return _db.Query(sql);
- }
-
- public async Task> QueryAsync(string sql) where T : new()
- {
- return await _dbAsync.QueryAsync(sql);
- }
-
- public int Execute(string sql)
- {
- return _db.Execute(sql);
- }
-
- public async Task ExecuteAsync(string sql)
- {
- return await _dbAsync.ExecuteAsync(sql);
- }
-
- public TableQuery Table() where T : new()
- {
- return _db.Table();
- }
-
- public AsyncTableQuery TableAsync() where T : new()
- {
- return _dbAsync.Table();
+ return _db.InsertAll(models);
}
}
+
+ public async Task InsertAsync(object model)
+ {
+ return await _dbAsync.InsertAsync(model);
+ }
+
+ public int Replace(object model)
+ {
+ lock (objLock)
+ {
+ return _db.InsertOrReplace(model);
+ }
+ }
+
+ public async Task Replacesync(object model)
+ {
+ return await _dbAsync.InsertOrReplaceAsync(model);
+ }
+
+ public int Update(object model)
+ {
+ lock (objLock)
+ {
+ return _db.Update(model);
+ }
+ }
+
+ public async Task UpdateAsync(object model)
+ {
+ return await _dbAsync.UpdateAsync(model);
+ }
+
+ public int UpdateAll(IEnumerable models)
+ {
+ lock (objLock)
+ {
+ return _db.UpdateAll(models);
+ }
+ }
+
+ public int Delete(object model)
+ {
+ lock (objLock)
+ {
+ return _db.Delete(model);
+ }
+ }
+
+ public async Task DeleteAsync(object model)
+ {
+ return await _dbAsync.DeleteAsync(model);
+ }
+
+ public List Query(string sql) where T : new()
+ {
+ return _db.Query(sql);
+ }
+
+ public async Task> QueryAsync(string sql) where T : new()
+ {
+ return await _dbAsync.QueryAsync(sql);
+ }
+
+ public int Execute(string sql)
+ {
+ return _db.Execute(sql);
+ }
+
+ public async Task ExecuteAsync(string sql)
+ {
+ return await _dbAsync.ExecuteAsync(sql);
+ }
+
+ public TableQuery Table() where T : new()
+ {
+ return _db.Table();
+ }
+
+ public AsyncTableQuery TableAsync() where T : new()
+ {
+ return _dbAsync.Table();
+ }
}
\ No newline at end of file
diff --git a/v2rayN/v2rayN/Base/StringEx.cs b/v2rayN/v2rayN/Base/StringEx.cs
index cf0f9106..0fa0e827 100644
--- a/v2rayN/v2rayN/Base/StringEx.cs
+++ b/v2rayN/v2rayN/Base/StringEx.cs
@@ -1,84 +1,83 @@
using System.Diagnostics.CodeAnalysis;
using System.IO;
-namespace v2rayN.Base
+namespace v2rayN.Base;
+
+internal static class StringEx
{
- internal static class StringEx
+ public static bool IsNullOrEmpty([NotNullWhen(false)] this string? value)
{
- public static bool IsNullOrEmpty([NotNullWhen(false)] this string? value)
+ return string.IsNullOrEmpty(value);
+ }
+
+ public static bool IsNullOrWhiteSpace([NotNullWhen(false)] this string? value)
+ {
+ return string.IsNullOrWhiteSpace(value);
+ }
+
+ public static bool BeginWithAny(this string s, IEnumerable chars)
+ {
+ if (s.IsNullOrEmpty()) return false;
+ return chars.Contains(s[0]);
+ }
+
+ public static bool IsWhiteSpace(this string value)
+ {
+ foreach (char c in value)
{
- return string.IsNullOrEmpty(value);
+ if (char.IsWhiteSpace(c)) continue;
+
+ return false;
}
+ return true;
+ }
- public static bool IsNullOrWhiteSpace([NotNullWhen(false)] this string? value)
+ public static IEnumerable NonWhiteSpaceLines(this TextReader reader)
+ {
+ string? line;
+ while ((line = reader.ReadLine()) != null)
{
- return string.IsNullOrWhiteSpace(value);
- }
-
- public static bool BeginWithAny(this string s, IEnumerable chars)
- {
- if (s.IsNullOrEmpty()) return false;
- return chars.Contains(s[0]);
- }
-
- public static bool IsWhiteSpace(this string value)
- {
- foreach (char c in value)
- {
- if (char.IsWhiteSpace(c)) continue;
-
- return false;
- }
- return true;
- }
-
- public static IEnumerable NonWhiteSpaceLines(this TextReader reader)
- {
- string? line;
- while ((line = reader.ReadLine()) != null)
- {
- if (line.IsWhiteSpace()) continue;
- yield return line;
- }
- }
-
- public static string TrimEx(this string? value)
- {
- return value == null ? string.Empty : value.Trim();
- }
-
- public static string RemovePrefix(this string value, char prefix)
- {
- if (value.StartsWith(prefix))
- {
- return value.Substring(1);
- }
- else
- {
- return value;
- }
- }
-
- public static string RemovePrefix(this string value, string prefix)
- {
- if (value.StartsWith(prefix))
- {
- return value.Substring(prefix.Length);
- }
- else
- {
- return value;
- }
- }
-
- public static string UpperFirstChar(this string value)
- {
- if (string.IsNullOrEmpty(value))
- {
- return string.Empty;
- }
-
- return char.ToUpper(value[0]) + value.Substring(1);
+ if (line.IsWhiteSpace()) continue;
+ yield return line;
}
}
+
+ public static string TrimEx(this string? value)
+ {
+ return value == null ? string.Empty : value.Trim();
+ }
+
+ public static string RemovePrefix(this string value, char prefix)
+ {
+ if (value.StartsWith(prefix))
+ {
+ return value.Substring(1);
+ }
+ else
+ {
+ return value;
+ }
+ }
+
+ public static string RemovePrefix(this string value, string prefix)
+ {
+ if (value.StartsWith(prefix))
+ {
+ return value.Substring(prefix.Length);
+ }
+ else
+ {
+ return value;
+ }
+ }
+
+ public static string UpperFirstChar(this string value)
+ {
+ if (string.IsNullOrEmpty(value))
+ {
+ return string.Empty;
+ }
+
+ return char.ToUpper(value[0]) + value.Substring(1);
+ }
}
\ No newline at end of file
diff --git a/v2rayN/v2rayN/Converters/DelayColorConverter.cs b/v2rayN/v2rayN/Converters/DelayColorConverter.cs
index b5c91565..09da3473 100644
--- a/v2rayN/v2rayN/Converters/DelayColorConverter.cs
+++ b/v2rayN/v2rayN/Converters/DelayColorConverter.cs
@@ -1,25 +1,24 @@
using System.Windows.Data;
using System.Windows.Media;
-namespace v2rayN.Converters
+namespace v2rayN.Converters;
+
+public class DelayColorConverter : IValueConverter
{
- public class DelayColorConverter : IValueConverter
+ public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
- public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
- {
- int.TryParse(value.ToString(), out var delay);
+ int.TryParse(value.ToString(), out var delay);
- if (delay <= 0)
- return new SolidColorBrush(Colors.Red);
- if (delay <= 200)
- return new SolidColorBrush(Colors.Green);
- else
- return new SolidColorBrush(Colors.IndianRed);
- }
+ if (delay <= 0)
+ return new SolidColorBrush(Colors.Red);
+ if (delay <= 200)
+ return new SolidColorBrush(Colors.Green);
+ else
+ return new SolidColorBrush(Colors.IndianRed);
+ }
- public object? ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
- {
- return null;
- }
+ public object? ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
+ {
+ return null;
}
}
\ No newline at end of file
diff --git a/v2rayN/v2rayN/Converters/InverseBooleanConverter.cs b/v2rayN/v2rayN/Converters/InverseBooleanConverter.cs
index d5809a37..2b3f8b34 100644
--- a/v2rayN/v2rayN/Converters/InverseBooleanConverter.cs
+++ b/v2rayN/v2rayN/Converters/InverseBooleanConverter.cs
@@ -1,24 +1,23 @@
using System.Globalization;
using System.Windows.Data;
-namespace v2rayN.Converters
+namespace v2rayN.Converters;
+
+[ValueConversion(typeof(bool), typeof(bool))]
+public class InverseBooleanConverter : IValueConverter
{
- [ValueConversion(typeof(bool), typeof(bool))]
- public class InverseBooleanConverter : IValueConverter
+ public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
- public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
+ if (targetType != typeof(bool))
{
- if (targetType != typeof(bool))
- {
- throw new InvalidOperationException("The target must be a boolean");
- }
-
- return !(bool)value;
+ throw new InvalidOperationException("The target must be a boolean");
}
- public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
- {
- throw new NotImplementedException();
- }
+ return !(bool)value;
+ }
+
+ public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
+ {
+ throw new NotImplementedException();
}
}
\ No newline at end of file
diff --git a/v2rayN/v2rayN/Converters/MaterialDesignFonts.cs b/v2rayN/v2rayN/Converters/MaterialDesignFonts.cs
index 0b6908d1..4e9ebcc2 100644
--- a/v2rayN/v2rayN/Converters/MaterialDesignFonts.cs
+++ b/v2rayN/v2rayN/Converters/MaterialDesignFonts.cs
@@ -1,27 +1,26 @@
using System.Windows.Media;
using v2rayN.Handler;
-namespace v2rayN.Converters
-{
- public class MaterialDesignFonts
- {
- public static FontFamily MyFont { get; }
+namespace v2rayN.Converters;
- static MaterialDesignFonts()
+public class MaterialDesignFonts
+{
+ public static FontFamily MyFont { get; }
+
+ static MaterialDesignFonts()
+ {
+ try
{
- try
+ var fontFamily = LazyConfig.Instance.GetConfig().uiItem.currentFontFamily;
+ if (!string.IsNullOrEmpty(fontFamily))
{
- var fontFamily = LazyConfig.Instance.GetConfig().uiItem.currentFontFamily;
- if (!string.IsNullOrEmpty(fontFamily))
- {
- var fontPath = Utils.GetFontsPath();
- MyFont = new FontFamily(new Uri(@$"file:///{fontPath}\"), $"./#{fontFamily}");
- }
+ var fontPath = Utils.GetFontsPath();
+ MyFont = new FontFamily(new Uri(@$"file:///{fontPath}\"), $"./#{fontFamily}");
}
- catch
- {
- }
- MyFont ??= new FontFamily("Microsoft YaHei");
}
+ catch
+ {
+ }
+ MyFont ??= new FontFamily("Microsoft YaHei");
}
}
\ No newline at end of file
diff --git a/v2rayN/v2rayN/Global.cs b/v2rayN/v2rayN/Global.cs
index 4af96a07..32c00bb6 100644
--- a/v2rayN/v2rayN/Global.cs
+++ b/v2rayN/v2rayN/Global.cs
@@ -1,174 +1,173 @@
-namespace v2rayN
+namespace v2rayN;
+
+internal class Global
{
- internal class Global
+ #region const
+
+ public const string githubUrl = "https://github.com";
+ public const string githubApiUrl = "https://api.github.com/repos";
+ public const string v2rayWebsiteUrl = @"https://www.v2fly.org/";
+ public const string AboutUrl = @"https://github.com/2dust/v2rayN";
+ public const string UpdateUrl = AboutUrl + @"/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 SagerNetCoreUrl = "https://github.com/SagerNet/v2ray-core/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 hysteriaCoreUrl = "https://github.com/apernet/hysteria/releases";
+ public const string naiveproxyCoreUrl = "https://github.com/klzgrad/naiveproxy/releases";
+ public const string tuicCoreUrl = "https://github.com/EAimTY/tuic/releases";
+ public const string singboxCoreUrl = "https://github.com/SagerNet/sing-box/releases";
+ public const string geoUrl = "https://github.com/Loyalsoldier/v2ray-rules-dat/releases/latest/download/{0}.dat";
+ public const string singboxGeoUrl = "https://github.com/soffchen/sing-{0}/releases/latest/download/{0}.db";
+ public const string SpeedPingTestUrl = @"https://www.google.com/generate_204";
+ public const string juicityCoreUrl = "https://github.com/juicity/juicity/releases";
+ public const string CustomRoutingListUrl = @"https://raw.githubusercontent.com/2dust/v2rayCustomRoutingList/master/";
+
+ public const string PromotionUrl = @"aHR0cHM6Ly85LjIzNDQ1Ni54eXovYWJjLmh0bWw=";
+ public const string ConfigFileName = "guiNConfig.json";
+ public const string ConfigDB = "guiNDB.db";
+ public const string coreConfigFileName = "config.json";
+ public const string corePreConfigFileName = "configPre.json";
+
+ public const string v2raySampleClient = "v2rayN.Sample.SampleClientConfig";
+ public const string SingboxSampleClient = "v2rayN.Sample.SingboxSampleClientConfig";
+ public const string v2raySampleHttprequestFileName = "v2rayN.Sample.SampleHttprequest";
+ public const string v2raySampleHttpresponseFileName = "v2rayN.Sample.SampleHttpresponse";
+ public const string v2raySampleInbound = "v2rayN.Sample.SampleInbound";
+ public const string CustomRoutingFileName = "v2rayN.Sample.custom_routing_";
+
+ public const string TunSingboxDNSFileName = "v2rayN.Sample.tun_singbox_dns";
+ public const string TunSingboxInboundFileName = "v2rayN.Sample.tun_singbox_inbound";
+ public const string TunSingboxRulesFileName = "v2rayN.Sample.tun_singbox_rules";
+
+ public const string DNSV2rayNormalFileName = "v2rayN.Sample.dns_v2ray_normal";
+ public const string DNSSingboxNormalFileName = "v2rayN.Sample.dns_singbox_normal";
+
+ public const string DefaultSecurity = "auto";
+ public const string DefaultNetwork = "tcp";
+ public const string TcpHeaderHttp = "http";
+ public const string None = "none";
+ public const string agentTag = "proxy";
+ public const string directTag = "direct";
+ public const string blockTag = "block";
+ public const string StreamSecurity = "tls";
+ public const string StreamSecurityReality = "reality";
+ public const string InboundSocks = "socks";
+ public const string InboundHttp = "http";
+ public const string InboundSocks2 = "socks2";
+ public const string InboundHttp2 = "http2";
+ public const string Loopback = "127.0.0.1";
+ public const string InboundAPITagName = "api";
+ public const string InboundAPIProtocal = "dokodemo-door";
+
+ public const string vmessProtocol = "vmess://";
+ public const string vmessProtocolLite = "vmess";
+ public const string ssProtocol = "ss://";
+ public const string ssProtocolLite = "shadowsocks";
+ public const string socksProtocol = "socks://";
+ public const string socksProtocolLite = "socks";
+ public const string httpProtocol = "http://";
+ public const string httpsProtocol = "https://";
+ public const string vlessProtocol = "vless://";
+ public const string vlessProtocolLite = "vless";
+ public const string trojanProtocol = "trojan://";
+ public const string trojanProtocolLite = "trojan";
+
+ public const string userEMail = "t@t.tt";
+ public const string MyRegPath = "Software\\v2rayNGUI";
+ public const string AutoRunRegPath = @"Software\Microsoft\Windows\CurrentVersion\Run";
+ public const string AutoRunName = "v2rayNAutoRun";
+ public const string MyRegKeyLanguage = "CurrentLanguage";
+ public const string CustomIconName = "v2rayN.ico";
+ public const string IEProxyExceptions = "localhost;127.*;10.*;172.16.*;172.17.*;172.18.*;172.19.*;172.20.*;172.21.*;172.22.*;172.23.*;172.24.*;172.25.*;172.26.*;172.27.*;172.28.*;172.29.*;172.30.*;172.31.*;192.168.*";
+ public const string RoutingRuleComma = "";
+ public const string GrpcgunMode = "gun";
+ public const string GrpcmultiMode = "multi";
+ public const int MaxPort = 65536;
+ public const string CommandClearMsg = "CommandClearMsg";
+ public const string DelayUnit = "";
+ public const string SpeedUnit = "";
+ public const int MinFontSize = 10;
+ public const string RebootAs = "rebootas";
+
+ public static readonly List IEProxyProtocols = new() {
+ "{ip}:{http_port}",
+ "socks={ip}:{socks_port}",
+ "http={ip}:{http_port};https={ip}:{http_port};ftp={ip}:{http_port};socks={ip}:{socks_port}",
+ "http=http://{ip}:{http_port};https=http://{ip}:{http_port}",
+ ""
+ };
+
+ public static readonly List SubConvertUrls = new List {
+ @"https://sub.xeton.dev/sub?url={0}",
+ @"https://api.dler.io/sub?url={0}",
+ @"http://127.0.0.1:25500/sub?url={0}",
+ ""
+ };
+
+ public static readonly List SubConvertConfig = new List {
+ @"https://raw.githubusercontent.com/ACL4SSR/ACL4SSR/master/Clash/config/ACL4SSR_Online.ini"
+ };
+
+ public static readonly List SubConvertTargets = new List {
+ "",
+ "mixed",
+ "v2ray",
+ "clash",
+ "ss",
+ };
+
+ public static readonly List SpeedTestUrls = new() {
+ @"http://cachefly.cachefly.net/100mb.test",
+ @"http://cachefly.cachefly.net/10mb.test"
+ };
+
+ public static readonly Dictionary userAgentTxt = new()
{
- #region const
+ {"chrome","Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.131 Safari/537.36" },
+ {"firefox","Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:90.0) Gecko/20100101 Firefox/90.0" },
+ {"safari","Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/14.1.1 Safari/605.1.15" },
+ {"edge","Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36 Edg/91.0.864.70" },
+ {"none",""}
+ };
- public const string githubUrl = "https://github.com";
- public const string githubApiUrl = "https://api.github.com/repos";
- public const string v2rayWebsiteUrl = @"https://www.v2fly.org/";
- public const string AboutUrl = @"https://github.com/2dust/v2rayN";
- public const string UpdateUrl = AboutUrl + @"/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 SagerNetCoreUrl = "https://github.com/SagerNet/v2ray-core/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 hysteriaCoreUrl = "https://github.com/apernet/hysteria/releases";
- public const string naiveproxyCoreUrl = "https://github.com/klzgrad/naiveproxy/releases";
- public const string tuicCoreUrl = "https://github.com/EAimTY/tuic/releases";
- public const string singboxCoreUrl = "https://github.com/SagerNet/sing-box/releases";
- public const string geoUrl = "https://github.com/Loyalsoldier/v2ray-rules-dat/releases/latest/download/{0}.dat";
- public const string singboxGeoUrl = "https://github.com/soffchen/sing-{0}/releases/latest/download/{0}.db";
- public const string SpeedPingTestUrl = @"https://www.google.com/generate_204";
- public const string juicityCoreUrl = "https://github.com/juicity/juicity/releases";
- public const string CustomRoutingListUrl = @"https://raw.githubusercontent.com/2dust/v2rayCustomRoutingList/master/";
+ public static readonly List vmessSecuritys = new() { "aes-128-gcm", "chacha20-poly1305", "auto", "none", "zero" };
+ public static readonly List ssSecuritys = new() { "aes-256-gcm", "aes-128-gcm", "chacha20-poly1305", "chacha20-ietf-poly1305", "none", "plain" };
+ public static readonly List ssSecuritysInSagerNet = new() { "none", "2022-blake3-aes-128-gcm", "2022-blake3-aes-256-gcm", "2022-blake3-chacha20-poly1305", "aes-128-gcm", "aes-192-gcm", "aes-256-gcm", "chacha20-ietf-poly1305", "xchacha20-ietf-poly1305", "rc4", "rc4-md5", "aes-128-ctr", "aes-192-ctr", "aes-256-ctr", "aes-128-cfb", "aes-192-cfb", "aes-256-cfb", "aes-128-cfb8", "aes-192-cfb8", "aes-256-cfb8", "aes-128-ofb", "aes-192-ofb", "aes-256-ofb", "bf-cfb", "cast5-cfb", "des-cfb", "idea-cfb", "rc2-cfb", "seed-cfb", "camellia-128-cfb", "camellia-192-cfb", "camellia-256-cfb", "camellia-128-cfb8", "camellia-192-cfb8", "camellia-256-cfb8", "salsa20", "chacha20", "chacha20-ietf", "xchacha20" };
+ public static readonly List ssSecuritysInXray = new() { "aes-256-gcm", "aes-128-gcm", "chacha20-poly1305", "chacha20-ietf-poly1305", "xchacha20-poly1305", "xchacha20-ietf-poly1305", "none", "plain", "2022-blake3-aes-128-gcm", "2022-blake3-aes-256-gcm", "2022-blake3-chacha20-poly1305" };
+ public static readonly List flows = new() { "", "xtls-rprx-vision", "xtls-rprx-vision-udp443" };
+ public static readonly List networks = new() { "tcp", "kcp", "ws", "h2", "quic", "grpc" };
+ public static readonly List kcpHeaderTypes = new() { "srtp", "utp", "wechat-video", "dtls", "wireguard" };
+ public static readonly List coreTypes = new() { "v2fly", "SagerNet", "Xray", "v2fly_v5", "sing_box" };
+ public static readonly List coreTypes4VLESS = new() { "Xray", "sing_box" };
+ public static readonly List domainStrategys = new() { "AsIs", "IPIfNonMatch", "IPOnDemand" };
+ public static readonly List domainStrategys4Singbox = new() { "ipv4_only", "ipv6_only", "prefer_ipv4", "prefer_ipv6", "" };
+ public static readonly List domainMatchers = new() { "linear", "mph", "" };
+ public static readonly List fingerprints = new() { "chrome", "firefox", "safari", "ios", "android", "edge", "360", "qq", "random", "randomized", "" };
+ public static readonly List userAgent = new() { "chrome", "firefox", "safari", "edge", "none" };
- public const string PromotionUrl = @"aHR0cHM6Ly85LjIzNDQ1Ni54eXovYWJjLmh0bWw=";
- public const string ConfigFileName = "guiNConfig.json";
- public const string ConfigDB = "guiNDB.db";
- public const string coreConfigFileName = "config.json";
- public const string corePreConfigFileName = "configPre.json";
+ public static readonly List allowInsecures = new() { "true", "false", "" };
+ public static readonly List domainStrategy4Freedoms = new() { "AsIs", "UseIP", "UseIPv4", "UseIPv6", "" };
+ public static readonly List Languages = new() { "zh-Hans", "zh-Hant", "en", "fa-Ir", "ru" };
+ public static readonly List alpns = new() { "h2", "http/1.1", "h2,http/1.1", "" };
+ public static readonly List LogLevel = new() { "debug", "info", "warning", "error", "none" };
+ public static readonly List InboundTags = new() { "socks", "http", "socks2", "http2" };
+ public static readonly List Protocols = new() { "http", "tls", "bittorrent" };
+ public static readonly List TunMtus = new() { "9000", "1500" };
+ public static readonly List TunStacks = new() { "gvisor", "system" };
+ public static readonly List PresetMsgFilters = new() { "proxy", "direct", "block", "" };
+ public static readonly List SingboxMuxs = new() { "h2mux", "smux", "yamux", "" };
- public const string v2raySampleClient = "v2rayN.Sample.SampleClientConfig";
- public const string SingboxSampleClient = "v2rayN.Sample.SingboxSampleClientConfig";
- public const string v2raySampleHttprequestFileName = "v2rayN.Sample.SampleHttprequest";
- public const string v2raySampleHttpresponseFileName = "v2rayN.Sample.SampleHttpresponse";
- public const string v2raySampleInbound = "v2rayN.Sample.SampleInbound";
- public const string CustomRoutingFileName = "v2rayN.Sample.custom_routing_";
+ #endregion const
- public const string TunSingboxDNSFileName = "v2rayN.Sample.tun_singbox_dns";
- public const string TunSingboxInboundFileName = "v2rayN.Sample.tun_singbox_inbound";
- public const string TunSingboxRulesFileName = "v2rayN.Sample.tun_singbox_rules";
+ #region global variable
- public const string DNSV2rayNormalFileName = "v2rayN.Sample.dns_v2ray_normal";
- public const string DNSSingboxNormalFileName = "v2rayN.Sample.dns_singbox_normal";
+ public static int statePort { get; set; }
+ public static Job processJob { get; set; }
+ public static bool ShowInTaskbar { get; set; }
+ public static string ExePathKey { get; set; }
- public const string DefaultSecurity = "auto";
- public const string DefaultNetwork = "tcp";
- public const string TcpHeaderHttp = "http";
- public const string None = "none";
- public const string agentTag = "proxy";
- public const string directTag = "direct";
- public const string blockTag = "block";
- public const string StreamSecurity = "tls";
- public const string StreamSecurityReality = "reality";
- public const string InboundSocks = "socks";
- public const string InboundHttp = "http";
- public const string InboundSocks2 = "socks2";
- public const string InboundHttp2 = "http2";
- public const string Loopback = "127.0.0.1";
- public const string InboundAPITagName = "api";
- public const string InboundAPIProtocal = "dokodemo-door";
-
- public const string vmessProtocol = "vmess://";
- public const string vmessProtocolLite = "vmess";
- public const string ssProtocol = "ss://";
- public const string ssProtocolLite = "shadowsocks";
- public const string socksProtocol = "socks://";
- public const string socksProtocolLite = "socks";
- public const string httpProtocol = "http://";
- public const string httpsProtocol = "https://";
- public const string vlessProtocol = "vless://";
- public const string vlessProtocolLite = "vless";
- public const string trojanProtocol = "trojan://";
- public const string trojanProtocolLite = "trojan";
-
- public const string userEMail = "t@t.tt";
- public const string MyRegPath = "Software\\v2rayNGUI";
- public const string AutoRunRegPath = @"Software\Microsoft\Windows\CurrentVersion\Run";
- public const string AutoRunName = "v2rayNAutoRun";
- public const string MyRegKeyLanguage = "CurrentLanguage";
- public const string CustomIconName = "v2rayN.ico";
- public const string IEProxyExceptions = "localhost;127.*;10.*;172.16.*;172.17.*;172.18.*;172.19.*;172.20.*;172.21.*;172.22.*;172.23.*;172.24.*;172.25.*;172.26.*;172.27.*;172.28.*;172.29.*;172.30.*;172.31.*;192.168.*";
- public const string RoutingRuleComma = "";
- public const string GrpcgunMode = "gun";
- public const string GrpcmultiMode = "multi";
- public const int MaxPort = 65536;
- public const string CommandClearMsg = "CommandClearMsg";
- public const string DelayUnit = "";
- public const string SpeedUnit = "";
- public const int MinFontSize = 10;
- public const string RebootAs = "rebootas";
-
- public static readonly List IEProxyProtocols = new() {
- "{ip}:{http_port}",
- "socks={ip}:{socks_port}",
- "http={ip}:{http_port};https={ip}:{http_port};ftp={ip}:{http_port};socks={ip}:{socks_port}",
- "http=http://{ip}:{http_port};https=http://{ip}:{http_port}",
- ""
- };
-
- public static readonly List SubConvertUrls = new List {
- @"https://sub.xeton.dev/sub?url={0}",
- @"https://api.dler.io/sub?url={0}",
- @"http://127.0.0.1:25500/sub?url={0}",
- ""
- };
-
- public static readonly List SubConvertConfig = new List {
- @"https://raw.githubusercontent.com/ACL4SSR/ACL4SSR/master/Clash/config/ACL4SSR_Online.ini"
- };
-
- public static readonly List SubConvertTargets = new List {
- "",
- "mixed",
- "v2ray",
- "clash",
- "ss",
- };
-
- public static readonly List SpeedTestUrls = new() {
- @"http://cachefly.cachefly.net/100mb.test",
- @"http://cachefly.cachefly.net/10mb.test"
- };
-
- public static readonly Dictionary userAgentTxt = 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" },
- {"firefox","Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:90.0) Gecko/20100101 Firefox/90.0" },
- {"safari","Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/14.1.1 Safari/605.1.15" },
- {"edge","Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36 Edg/91.0.864.70" },
- {"none",""}
- };
-
- public static readonly List vmessSecuritys = new() { "aes-128-gcm", "chacha20-poly1305", "auto", "none", "zero" };
- public static readonly List ssSecuritys = new() { "aes-256-gcm", "aes-128-gcm", "chacha20-poly1305", "chacha20-ietf-poly1305", "none", "plain" };
- public static readonly List ssSecuritysInSagerNet = new() { "none", "2022-blake3-aes-128-gcm", "2022-blake3-aes-256-gcm", "2022-blake3-chacha20-poly1305", "aes-128-gcm", "aes-192-gcm", "aes-256-gcm", "chacha20-ietf-poly1305", "xchacha20-ietf-poly1305", "rc4", "rc4-md5", "aes-128-ctr", "aes-192-ctr", "aes-256-ctr", "aes-128-cfb", "aes-192-cfb", "aes-256-cfb", "aes-128-cfb8", "aes-192-cfb8", "aes-256-cfb8", "aes-128-ofb", "aes-192-ofb", "aes-256-ofb", "bf-cfb", "cast5-cfb", "des-cfb", "idea-cfb", "rc2-cfb", "seed-cfb", "camellia-128-cfb", "camellia-192-cfb", "camellia-256-cfb", "camellia-128-cfb8", "camellia-192-cfb8", "camellia-256-cfb8", "salsa20", "chacha20", "chacha20-ietf", "xchacha20" };
- public static readonly List ssSecuritysInXray = new() { "aes-256-gcm", "aes-128-gcm", "chacha20-poly1305", "chacha20-ietf-poly1305", "xchacha20-poly1305", "xchacha20-ietf-poly1305", "none", "plain", "2022-blake3-aes-128-gcm", "2022-blake3-aes-256-gcm", "2022-blake3-chacha20-poly1305" };
- public static readonly List flows = new() { "", "xtls-rprx-vision", "xtls-rprx-vision-udp443" };
- public static readonly List networks = new() { "tcp", "kcp", "ws", "h2", "quic", "grpc" };
- public static readonly List kcpHeaderTypes = new() { "srtp", "utp", "wechat-video", "dtls", "wireguard" };
- public static readonly List coreTypes = new() { "v2fly", "SagerNet", "Xray", "v2fly_v5", "sing_box" };
- public static readonly List coreTypes4VLESS = new() { "Xray", "sing_box" };
- public static readonly List domainStrategys = new() { "AsIs", "IPIfNonMatch", "IPOnDemand" };
- public static readonly List domainStrategys4Singbox = new() { "ipv4_only", "ipv6_only", "prefer_ipv4", "prefer_ipv6", "" };
- public static readonly List domainMatchers = new() { "linear", "mph", "" };
- public static readonly List fingerprints = new() { "chrome", "firefox", "safari", "ios", "android", "edge", "360", "qq", "random", "randomized", "" };
- public static readonly List userAgent = new() { "chrome", "firefox", "safari", "edge", "none" };
-
- public static readonly List allowInsecures = new() { "true", "false", "" };
- public static readonly List domainStrategy4Freedoms = new() { "AsIs", "UseIP", "UseIPv4", "UseIPv6", "" };
- public static readonly List Languages = new() { "zh-Hans", "zh-Hant", "en", "fa-Ir", "ru" };
- public static readonly List alpns = new() { "h2", "http/1.1", "h2,http/1.1", "" };
- public static readonly List LogLevel = new() { "debug", "info", "warning", "error", "none" };
- public static readonly List InboundTags = new() { "socks", "http", "socks2", "http2" };
- public static readonly List Protocols = new() { "http", "tls", "bittorrent" };
- public static readonly List TunMtus = new() { "9000", "1500" };
- public static readonly List TunStacks = new() { "gvisor", "system" };
- public static readonly List PresetMsgFilters = new() { "proxy", "direct", "block", "" };
- public static readonly List SingboxMuxs = new() { "h2mux", "smux", "yamux", "" };
-
- #endregion const
-
- #region global variable
-
- public static int statePort { get; set; }
- public static Job processJob { get; set; }
- public static bool ShowInTaskbar { get; set; }
- public static string ExePathKey { get; set; }
-
- #endregion global variable
- }
+ #endregion global variable
}
diff --git a/v2rayN/v2rayN/Handler/ConfigHandler.cs b/v2rayN/v2rayN/Handler/ConfigHandler.cs
index 8bd6892d..8efa46b3 100644
--- a/v2rayN/v2rayN/Handler/ConfigHandler.cs
+++ b/v2rayN/v2rayN/Handler/ConfigHandler.cs
@@ -5,1621 +5,1620 @@ using v2rayN.Base;
using v2rayN.Mode;
using v2rayN.Tool;
-namespace v2rayN.Handler
+namespace v2rayN.Handler;
+
+///
+/// 本软件配置文件处理类
+///
+internal class ConfigHandler
{
+ private static string configRes = Global.ConfigFileName;
+ private static readonly object objLock = new();
+
+ #region ConfigHandler
+
///
- /// 本软件配置文件处理类
+ /// 载入配置文件
///
- internal class ConfigHandler
+ ///
+ ///
+ public static int LoadConfig(ref Config config)
{
- private static string configRes = Global.ConfigFileName;
- private static readonly object objLock = new();
-
- #region ConfigHandler
-
- ///
- /// 载入配置文件
- ///
- ///
- ///
- public static int LoadConfig(ref Config config)
+ //载入配置文件
+ string result = Utils.LoadResource(Utils.GetConfigPath(configRes));
+ if (!Utils.IsNullOrEmpty(result))
{
- //载入配置文件
- string result = Utils.LoadResource(Utils.GetConfigPath(configRes));
- if (!Utils.IsNullOrEmpty(result))
- {
- //转成Json
- config = Utils.FromJson(result);
- }
- else
- {
- if (File.Exists(Utils.GetConfigPath(configRes)))
- {
- Utils.SaveLog("LoadConfig Exception");
- return -1;
- }
- }
-
- if (config == null)
- {
- config = new Config
- {
- };
- }
- if (config.coreBasicItem == null)
- {
- config.coreBasicItem = new()
- {
- logEnabled = false,
- loglevel = "warning",
-
- muxEnabled = false,
- };
- }
-
- //本地监听
- if (config.inbound == null)
- {
- config.inbound = new List();
- InItem inItem = new()
- {
- protocol = Global.InboundSocks,
- localPort = 10808,
- udpEnabled = true,
- sniffingEnabled = true,
- routeOnly = false,
- };
-
- config.inbound.Add(inItem);
-
- //inItem = new InItem();
- //inItem.protocol = "http";
- //inItem.localPort = 1081;
- //inItem.udpEnabled = true;
-
- //config.inbound.Add(inItem);
- }
- else
- {
- if (config.inbound.Count > 0)
- {
- config.inbound[0].protocol = Global.InboundSocks;
- }
- }
- if (config.routingBasicItem == null)
- {
- config.routingBasicItem = new()
- {
- enableRoutingAdvanced = true
- };
- }
- //路由规则
- if (Utils.IsNullOrEmpty(config.routingBasicItem.domainStrategy))
- {
- config.routingBasicItem.domainStrategy = Global.domainStrategys[0];//"IPIfNonMatch";
- }
- //if (Utils.IsNullOrEmpty(config.domainMatcher))
- //{
- // config.domainMatcher = "linear";
- //}
-
- //kcp
- if (config.kcpItem == null)
- {
- config.kcpItem = new KcpItem
- {
- mtu = 1350,
- tti = 50,
- uplinkCapacity = 12,
- downlinkCapacity = 100,
- readBufferSize = 2,
- writeBufferSize = 2,
- congestion = false
- };
- }
- if (config.grpcItem == null)
- {
- config.grpcItem = new GrpcItem
- {
- idle_timeout = 60,
- health_check_timeout = 20,
- permit_without_stream = false,
- initial_windows_size = 0,
- };
- }
- if (config.tunModeItem == null)
- {
- config.tunModeItem = new TunModeItem
- {
- enableTun = false,
- mtu = 9000,
- };
- }
- if (config.guiItem == null)
- {
- config.guiItem = new()
- {
- enableStatistics = false,
- };
- }
- if (config.uiItem == null)
- {
- config.uiItem = new UIItem()
- {
- enableAutoAdjustMainLvColWidth = true
- };
- }
- if (config.uiItem.mainColumnItem == null)
- {
- config.uiItem.mainColumnItem = new();
- }
- if (Utils.IsNullOrEmpty(config.uiItem.currentLanguage))
- {
- config.uiItem.currentLanguage = Global.Languages[0];
- }
-
- if (config.constItem == null)
- {
- config.constItem = new ConstItem();
- }
- if (Utils.IsNullOrEmpty(config.constItem.defIEProxyExceptions))
- {
- config.constItem.defIEProxyExceptions = Global.IEProxyExceptions;
- }
-
- if (config.speedTestItem == null)
- {
- config.speedTestItem = new();
- }
- if (config.speedTestItem.speedTestTimeout < 10)
- {
- config.speedTestItem.speedTestTimeout = 10;
- }
- if (Utils.IsNullOrEmpty(config.speedTestItem.speedTestUrl))
- {
- config.speedTestItem.speedTestUrl = Global.SpeedTestUrls[0];
- }
- if (Utils.IsNullOrEmpty(config.speedTestItem.speedPingTestUrl))
- {
- config.speedTestItem.speedPingTestUrl = Global.SpeedPingTestUrl;
- }
-
- if (config.mux4Sbox == null)
- {
- config.mux4Sbox = new()
- {
- protocol = Global.SingboxMuxs[0],
- max_connections = 4,
- min_streams = 4,
- max_streams = 0,
- padding = true
- };
- }
-
- LazyConfig.Instance.SetConfig(config);
- return 0;
+ //转成Json
+ config = Utils.FromJson(result);
}
-
- ///
- /// 保参数
- ///
- ///
- ///
- public static int SaveConfig(ref Config config, bool reload = true)
+ else
{
- ToJsonFile(config);
-
- return 0;
- }
-
- ///
- /// 存储文件
- ///
- ///
- private static void ToJsonFile(Config config)
- {
- lock (objLock)
- {
- try
- {
- //save temp file
- var resPath = Utils.GetConfigPath(configRes);
- var tempPath = $"{resPath}_temp";
- if (Utils.ToJsonFile(config, tempPath) != 0)
- {
- return;
- }
-
- if (File.Exists(resPath))
- {
- File.Delete(resPath);
- }
- //rename
- File.Move(tempPath, resPath);
- }
- catch (Exception ex)
- {
- Utils.SaveLog("ToJsonFile", ex);
- }
- }
- }
-
- public static int ImportOldGuiConfig(ref Config config, string fileName)
- {
- string result = Utils.LoadResource(fileName);
- if (Utils.IsNullOrEmpty(result))
+ if (File.Exists(Utils.GetConfigPath(configRes)))
{
+ Utils.SaveLog("LoadConfig Exception");
return -1;
}
-
- var configOld = Utils.FromJson(result);
- if (configOld == null)
- {
- return -1;
- }
-
- var subItem = Utils.FromJson>(Utils.ToJson(configOld.subItem));
- foreach (var it in subItem)
- {
- if (Utils.IsNullOrEmpty(it.id))
- {
- it.id = Utils.GetGUID(false);
- }
- SqliteHelper.Instance.Replace(it);
- }
-
- var profileItems = Utils.FromJson>(Utils.ToJson(configOld.vmess));
- foreach (var it in profileItems)
- {
- if (Utils.IsNullOrEmpty(it.indexId))
- {
- it.indexId = Utils.GetGUID(false);
- }
- SqliteHelper.Instance.Replace(it);
- }
-
- foreach (var it in configOld.routings)
- {
- if (it.locked)
- {
- continue;
- }
- var routing = Utils.FromJson(Utils.ToJson(it));
- foreach (var it2 in it.rules)
- {
- it2.id = Utils.GetGUID(false);
- }
- routing.ruleNum = it.rules.Count;
- routing.ruleSet = Utils.ToJson(it.rules, false);
-
- if (Utils.IsNullOrEmpty(routing.id))
- {
- routing.id = Utils.GetGUID(false);
- }
- SqliteHelper.Instance.Replace(routing);
- }
-
- config = Utils.FromJson(Utils.ToJson(configOld));
-
- if (config.coreBasicItem == null)
- {
- config.coreBasicItem = new()
- {
- logEnabled = configOld.logEnabled,
- loglevel = configOld.loglevel,
- muxEnabled = configOld.muxEnabled,
- };
- }
-
- if (config.routingBasicItem == null)
- {
- config.routingBasicItem = new()
- {
- enableRoutingAdvanced = configOld.enableRoutingAdvanced,
- domainStrategy = configOld.domainStrategy
- };
- }
-
- if (config.guiItem == null)
- {
- config.guiItem = new()
- {
- enableStatistics = configOld.enableStatistics,
- keepOlderDedupl = configOld.keepOlderDedupl,
- ignoreGeoUpdateCore = configOld.ignoreGeoUpdateCore,
- autoUpdateInterval = configOld.autoUpdateInterval,
- checkPreReleaseUpdate = configOld.checkPreReleaseUpdate,
- enableSecurityProtocolTls13 = configOld.enableSecurityProtocolTls13,
- trayMenuServersLimit = configOld.trayMenuServersLimit,
- };
- }
-
- GetDefaultServer(ref config);
- GetDefaultRouting(ref config);
- SaveConfig(ref config);
- LoadConfig(ref config);
-
- return 0;
}
- #endregion ConfigHandler
-
- #region Server
-
- ///
- /// 添加服务器或编辑
- ///
- ///
- ///
- ///
- public static int AddServer(ref Config config, ProfileItem profileItem, bool toFile = true)
+ if (config == null)
{
- profileItem.configType = EConfigType.VMess;
-
- profileItem.address = profileItem.address.TrimEx();
- profileItem.id = profileItem.id.TrimEx();
- profileItem.security = profileItem.security.TrimEx();
- profileItem.network = profileItem.network.TrimEx();
- profileItem.headerType = profileItem.headerType.TrimEx();
- profileItem.requestHost = profileItem.requestHost.TrimEx();
- profileItem.path = profileItem.path.TrimEx();
- profileItem.streamSecurity = profileItem.streamSecurity.TrimEx();
-
- if (!Global.vmessSecuritys.Contains(profileItem.security))
+ config = new Config
{
- return -1;
- }
- if (profileItem.id.IsNullOrEmpty())
- {
- return -1;
- }
-
- AddServerCommon(ref config, profileItem, toFile);
-
- return 0;
+ };
}
-
- ///
- /// 移除服务器
- ///
- ///
- ///
- ///
- public static int RemoveServer(Config config, List indexs)
+ if (config.coreBasicItem == null)
{
- var subid = "TempRemoveSubId";
- foreach (var item in indexs)
+ config.coreBasicItem = new()
{
- item.subid = subid;
- }
+ logEnabled = false,
+ loglevel = "warning",
- SqliteHelper.Instance.UpdateAll(indexs);
- RemoveServerViaSubid(ref config, subid, false);
-
- return 0;
+ muxEnabled = false,
+ };
}
- ///
- /// 克隆服务器
- ///
- ///
- ///
- ///
- public static int CopyServer(ref Config config, List indexs)
+ //本地监听
+ if (config.inbound == null)
{
- foreach (var it in indexs)
+ config.inbound = new List();
+ InItem inItem = new()
{
- var item = LazyConfig.Instance.GetProfileItem(it.indexId);
- if (item is null)
- {
- continue;
- }
+ protocol = Global.InboundSocks,
+ localPort = 10808,
+ udpEnabled = true,
+ sniffingEnabled = true,
+ routeOnly = false,
+ };
- ProfileItem profileItem = Utils.DeepCopy(item);
- profileItem.indexId = string.Empty;
- profileItem.remarks = $"{item.remarks}-clone";
+ config.inbound.Add(inItem);
- if (profileItem.configType == EConfigType.Custom)
- {
- profileItem.address = Utils.GetConfigPath(profileItem.address);
- if (AddCustomServer(ref config, profileItem, false) == 0)
- {
- }
- }
- else
- {
- AddServerCommon(ref config, profileItem, true);
- }
- }
+ //inItem = new InItem();
+ //inItem.protocol = "http";
+ //inItem.localPort = 1081;
+ //inItem.udpEnabled = true;
- return 0;
+ //config.inbound.Add(inItem);
}
-
- ///
- /// 设置活动服务器
- ///
- ///
- ///
- ///
- public static int SetDefaultServerIndex(ref Config config, string? indexId)
+ else
{
- if (Utils.IsNullOrEmpty(indexId))
+ if (config.inbound.Count > 0)
{
- return -1;
+ config.inbound[0].protocol = Global.InboundSocks;
}
-
- config.indexId = indexId;
-
- ToJsonFile(config);
-
- return 0;
}
-
- public static int SetDefaultServer(Config config, List lstProfile)
+ if (config.routingBasicItem == null)
{
- if (lstProfile.Exists(t => t.indexId == config.indexId))
+ config.routingBasicItem = new()
{
- return 0;
- }
- if (SqliteHelper.Instance.Table().Where(t => t.indexId == config.indexId).Any())
- {
- return 0;
- }
- if (lstProfile.Count > 0)
- {
- return SetDefaultServerIndex(ref config, lstProfile.Where(t => t.port > 0).FirstOrDefault()?.indexId);
- }
- return SetDefaultServerIndex(ref config, SqliteHelper.Instance.Table().Where(t => t.port > 0).Select(t => t.indexId).FirstOrDefault());
+ enableRoutingAdvanced = true
+ };
}
-
- public static ProfileItem? GetDefaultServer(ref Config config)
+ //路由规则
+ if (Utils.IsNullOrEmpty(config.routingBasicItem.domainStrategy))
{
- var item = LazyConfig.Instance.GetProfileItem(config.indexId);
- if (item is null)
- {
- var item2 = SqliteHelper.Instance.Table().FirstOrDefault();
- SetDefaultServerIndex(ref config, item2?.indexId);
- return item2;
- }
-
- return item;
+ config.routingBasicItem.domainStrategy = Global.domainStrategys[0];//"IPIfNonMatch";
}
+ //if (Utils.IsNullOrEmpty(config.domainMatcher))
+ //{
+ // config.domainMatcher = "linear";
+ //}
- ///
- /// 移动服务器
- ///
- ///
- ///
- ///
- ///
- ///
- public static int MoveServer(ref Config config, ref List lstProfile, int index, EMove eMove, int pos = -1)
+ //kcp
+ if (config.kcpItem == null)
{
- int count = lstProfile.Count;
- if (index < 0 || index > lstProfile.Count - 1)
+ config.kcpItem = new KcpItem
{
- return -1;
- }
-
- for (int i = 0; i < lstProfile.Count; i++)
- {
- ProfileExHandler.Instance.SetSort(lstProfile[i].indexId, (i + 1) * 10);
- }
-
- var sort = 0;
- switch (eMove)
- {
- case EMove.Top:
- {
- if (index == 0)
- {
- return 0;
- }
- sort = ProfileExHandler.Instance.GetSort(lstProfile[0].indexId) - 1;
-
- break;
- }
- case EMove.Up:
- {
- if (index == 0)
- {
- return 0;
- }
- sort = ProfileExHandler.Instance.GetSort(lstProfile[index - 1].indexId) - 1;
-
- break;
- }
-
- case EMove.Down:
- {
- if (index == count - 1)
- {
- return 0;
- }
- sort = ProfileExHandler.Instance.GetSort(lstProfile[index + 1].indexId) + 1;
-
- break;
- }
- case EMove.Bottom:
- {
- if (index == count - 1)
- {
- return 0;
- }
- sort = ProfileExHandler.Instance.GetSort(lstProfile[^1].indexId) + 1;
-
- break;
- }
- case EMove.Position:
- sort = pos * 10 + 1;
- break;
- }
-
- ProfileExHandler.Instance.SetSort(lstProfile[index].indexId, sort);
- return 0;
+ mtu = 1350,
+ tti = 50,
+ uplinkCapacity = 12,
+ downlinkCapacity = 100,
+ readBufferSize = 2,
+ writeBufferSize = 2,
+ congestion = false
+ };
}
-
- ///
- /// 添加自定义服务器
- ///
- ///
- ///
- ///
- public static int AddCustomServer(ref Config config, ProfileItem profileItem, bool blDelete)
+ if (config.grpcItem == null)
{
- var fileName = profileItem.address;
- if (!File.Exists(fileName))
+ config.grpcItem = new GrpcItem
{
- return -1;
- }
- var ext = Path.GetExtension(fileName);
- string newFileName = $"{Utils.GetGUID()}{ext}";
- //newFileName = Path.Combine(Utils.GetTempPath(), newFileName);
-
- try
- {
- File.Copy(fileName, Utils.GetConfigPath(newFileName));
- if (blDelete)
- {
- File.Delete(fileName);
- }
- }
- catch (Exception ex)
- {
- Utils.SaveLog(ex.Message, ex);
- return -1;
- }
-
- profileItem.address = newFileName;
- profileItem.configType = EConfigType.Custom;
- if (Utils.IsNullOrEmpty(profileItem.remarks))
- {
- profileItem.remarks = $"import custom@{DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss")}";
- }
-
- AddServerCommon(ref config, profileItem, true);
-
- return 0;
+ idle_timeout = 60,
+ health_check_timeout = 20,
+ permit_without_stream = false,
+ initial_windows_size = 0,
+ };
}
-
- ///
- /// 添加服务器或编辑
- ///
- ///
- ///
- ///
- public static int EditCustomServer(ref Config config, ProfileItem profileItem)
+ if (config.tunModeItem == null)
{
- if (SqliteHelper.Instance.Update(profileItem) > 0)
+ config.tunModeItem = new TunModeItem
{
- return 0;
- }
- else
- {
- return -1;
- }
-
- //ToJsonFile(config);
+ enableTun = false,
+ mtu = 9000,
+ };
}
-
- ///
- /// 添加服务器或编辑
- ///
- ///
- ///
- ///
- public static int AddShadowsocksServer(ref Config config, ProfileItem profileItem, bool toFile = true)
+ if (config.guiItem == null)
{
- profileItem.configType = EConfigType.Shadowsocks;
-
- profileItem.address = profileItem.address.TrimEx();
- profileItem.id = profileItem.id.TrimEx();
- profileItem.security = profileItem.security.TrimEx();
-
- if (!LazyConfig.Instance.GetShadowsocksSecuritys(profileItem).Contains(profileItem.security))
+ config.guiItem = new()
{
- return -1;
- }
- if (profileItem.id.IsNullOrEmpty())
- {
- return -1;
- }
-
- AddServerCommon(ref config, profileItem, toFile);
-
- return 0;
+ enableStatistics = false,
+ };
}
-
- ///
- /// 添加服务器或编辑
- ///
- ///
- ///
- ///
- public static int AddSocksServer(ref Config config, ProfileItem profileItem, bool toFile = true)
+ if (config.uiItem == null)
{
- profileItem.configType = EConfigType.Socks;
-
- profileItem.address = profileItem.address.TrimEx();
-
- AddServerCommon(ref config, profileItem, toFile);
-
- return 0;
+ config.uiItem = new UIItem()
+ {
+ enableAutoAdjustMainLvColWidth = true
+ };
}
-
- ///
- /// 添加服务器或编辑
- ///
- ///
- ///
- ///
- public static int AddTrojanServer(ref Config config, ProfileItem profileItem, bool toFile = true)
+ if (config.uiItem.mainColumnItem == null)
{
- profileItem.configType = EConfigType.Trojan;
-
- profileItem.address = profileItem.address.TrimEx();
- profileItem.id = profileItem.id.TrimEx();
- if (Utils.IsNullOrEmpty(profileItem.streamSecurity))
- {
- profileItem.streamSecurity = Global.StreamSecurity;
- }
- if (profileItem.id.IsNullOrEmpty())
- {
- return -1;
- }
-
- AddServerCommon(ref config, profileItem, toFile);
-
- return 0;
+ config.uiItem.mainColumnItem = new();
}
-
- public static int SortServers(ref Config config, string subId, string colName, bool asc)
+ if (Utils.IsNullOrEmpty(config.uiItem.currentLanguage))
{
- var lstModel = LazyConfig.Instance.ProfileItems(subId, "");
- if (lstModel.Count <= 0)
- {
- return -1;
- }
- var lstProfileExs = ProfileExHandler.Instance.ProfileExs;
- var lstProfile = (from t in lstModel
- 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,
- delay = t33 == null ? 0 : t33.delay,
- speed = t33 == null ? 0 : t33.speed,
- sort = t33 == null ? 0 : t33.sort
- }).ToList();
-
- Enum.TryParse(colName, true, out EServerColName name);
- var propertyName = string.Empty;
- switch (name)
- {
- case EServerColName.configType:
- case EServerColName.remarks:
- case EServerColName.address:
- case EServerColName.port:
- case EServerColName.security:
- case EServerColName.network:
- case EServerColName.streamSecurity:
- propertyName = name.ToString();
- break;
-
- case EServerColName.delayVal:
- propertyName = "delay";
- break;
-
- case EServerColName.speedVal:
- propertyName = "speed";
- break;
-
- case EServerColName.subRemarks:
- propertyName = "subid";
- break;
-
- default:
- return -1;
- }
-
- var items = lstProfile.AsQueryable();
-
- if (asc)
- {
- lstProfile = items.OrderBy(propertyName).ToList();
- }
- else
- {
- lstProfile = items.OrderByDescending(propertyName).ToList();
- }
- for (int i = 0; i < lstProfile.Count; i++)
- {
- ProfileExHandler.Instance.SetSort(lstProfile[i].indexId, (i + 1) * 10);
- }
- if (name == EServerColName.delayVal)
- {
- var maxSort = lstProfile.Max(t => t.sort) + 10;
- foreach (var item in lstProfile)
- {
- if (item.delay <= 0)
- {
- ProfileExHandler.Instance.SetSort(item.indexId, maxSort);
- }
- }
- }
- if (name == EServerColName.speedVal)
- {
- var maxSort = lstProfile.Max(t => t.sort) + 10;
- foreach (var item in lstProfile)
- {
- if (item.speed <= 0)
- {
- ProfileExHandler.Instance.SetSort(item.indexId, maxSort);
- }
- }
- }
-
- return 0;
+ config.uiItem.currentLanguage = Global.Languages[0];
}
- ///
- /// 添加服务器或编辑
- ///
- ///
- ///
- ///
- public static int AddVlessServer(ref Config config, ProfileItem profileItem, bool toFile = true)
+ if (config.constItem == null)
{
- profileItem.configType = EConfigType.VLESS;
-
- profileItem.address = profileItem.address.TrimEx();
- profileItem.id = profileItem.id.TrimEx();
- profileItem.security = profileItem.security.TrimEx();
- profileItem.network = profileItem.network.TrimEx();
- profileItem.headerType = profileItem.headerType.TrimEx();
- profileItem.requestHost = profileItem.requestHost.TrimEx();
- profileItem.path = profileItem.path.TrimEx();
- profileItem.streamSecurity = profileItem.streamSecurity.TrimEx();
-
- if (!Global.flows.Contains(profileItem.flow))
- {
- profileItem.flow = Global.flows.First();
- }
- if (profileItem.id.IsNullOrEmpty())
- {
- return -1;
- }
-
- AddServerCommon(ref config, profileItem, toFile);
-
- return 0;
+ config.constItem = new ConstItem();
}
-
- public static Tuple DedupServerList(Config config, string subId)
+ if (Utils.IsNullOrEmpty(config.constItem.defIEProxyExceptions))
{
- var lstProfile = LazyConfig.Instance.ProfileItems(subId);
-
- List lstKeep = new();
- List lstRemove = new();
- if (!config.guiItem.keepOlderDedupl) lstProfile.Reverse();
-
- foreach (ProfileItem item in lstProfile)
- {
- if (!lstKeep.Exists(i => CompareProfileItem(i, item, false)))
- {
- lstKeep.Add(item);
- }
- else
- {
- lstRemove.Add(item);
- }
- }
- RemoveServer(config, lstRemove);
-
- return new Tuple(lstProfile.Count, lstKeep.Count);
+ config.constItem.defIEProxyExceptions = Global.IEProxyExceptions;
}
- public static int AddServerCommon(ref Config config, ProfileItem profileItem, bool toFile = true)
+ if (config.speedTestItem == null)
{
- profileItem.configVersion = 2;
-
- if (!Utils.IsNullOrEmpty(profileItem.streamSecurity))
- {
- if (Utils.IsNullOrEmpty(profileItem.allowInsecure))
- {
- profileItem.allowInsecure = config.coreBasicItem.defAllowInsecure.ToString().ToLower();
- }
- if (Utils.IsNullOrEmpty(profileItem.fingerprint))
- {
- profileItem.fingerprint = config.coreBasicItem.defFingerprint;
- }
- }
-
- if (!Utils.IsNullOrEmpty(profileItem.network) && !Global.networks.Contains(profileItem.network))
- {
- profileItem.network = Global.DefaultNetwork;
- }
-
- var maxSort = -1;
- if (Utils.IsNullOrEmpty(profileItem.indexId))
- {
- profileItem.indexId = Utils.GetGUID(false);
- maxSort = ProfileExHandler.Instance.GetMaxSort();
- }
- if (!toFile && maxSort < 0)
- {
- maxSort = ProfileExHandler.Instance.GetMaxSort();
- }
- if (maxSort > 0)
- {
- ProfileExHandler.Instance.SetSort(profileItem.indexId, maxSort + 1);
- }
-
- if (toFile)
- {
- SqliteHelper.Instance.Replace(profileItem);
- }
- return 0;
+ config.speedTestItem = new();
}
-
- private static bool CompareProfileItem(ProfileItem o, ProfileItem n, bool remarks)
+ if (config.speedTestItem.speedTestTimeout < 10)
{
- if (o == null || n == null)
- {
- return false;
- }
-
- return o.configType == n.configType
- && o.address == n.address
- && o.port == n.port
- && o.id == n.id
- && o.alterId == n.alterId
- && o.security == n.security
- && o.network == n.network
- && o.headerType == n.headerType
- && o.requestHost == n.requestHost
- && o.path == n.path
- && (o.configType == EConfigType.Trojan || o.streamSecurity == n.streamSecurity)
- && o.flow == n.flow
- && o.sni == n.sni
- && (!remarks || o.remarks == n.remarks);
+ config.speedTestItem.speedTestTimeout = 10;
+ }
+ if (Utils.IsNullOrEmpty(config.speedTestItem.speedTestUrl))
+ {
+ config.speedTestItem.speedTestUrl = Global.SpeedTestUrls[0];
+ }
+ if (Utils.IsNullOrEmpty(config.speedTestItem.speedPingTestUrl))
+ {
+ config.speedTestItem.speedPingTestUrl = Global.SpeedPingTestUrl;
}
- private static int RemoveProfileItem(Config config, string indexId)
+ if (config.mux4Sbox == null)
+ {
+ config.mux4Sbox = new()
+ {
+ protocol = Global.SingboxMuxs[0],
+ max_connections = 4,
+ min_streams = 4,
+ max_streams = 0,
+ padding = true
+ };
+ }
+
+ LazyConfig.Instance.SetConfig(config);
+ return 0;
+ }
+
+ ///
+ /// 保参数
+ ///
+ ///
+ ///
+ public static int SaveConfig(ref Config config, bool reload = true)
+ {
+ ToJsonFile(config);
+
+ return 0;
+ }
+
+ ///
+ /// 存储文件
+ ///
+ ///
+ private static void ToJsonFile(Config config)
+ {
+ lock (objLock)
{
try
{
- var item = LazyConfig.Instance.GetProfileItem(indexId);
- if (item == null)
+ //save temp file
+ var resPath = Utils.GetConfigPath(configRes);
+ var tempPath = $"{resPath}_temp";
+ if (Utils.ToJsonFile(config, tempPath) != 0)
{
- return 0;
- }
- if (item.configType == EConfigType.Custom)
- {
- File.Delete(Utils.GetConfigPath(item.address));
+ return;
}
- SqliteHelper.Instance.Delete(item);
+ if (File.Exists(resPath))
+ {
+ File.Delete(resPath);
+ }
+ //rename
+ File.Move(tempPath, resPath);
}
catch (Exception ex)
{
- Utils.SaveLog("Remove Item", ex);
- }
-
- return 0;
- }
-
- #endregion Server
-
- #region Batch add servers
-
- ///
- /// 批量添加服务器
- ///
- ///
- ///
- ///
- /// 成功导入的数量
- private static int AddBatchServers(ref Config config, string clipboardData, string subid, bool isSub, List lstOriSub)
- {
- if (Utils.IsNullOrEmpty(clipboardData))
- {
- return -1;
- }
-
- string subFilter = string.Empty;
- //remove sub items
- if (isSub && !Utils.IsNullOrEmpty(subid))
- {
- RemoveServerViaSubid(ref config, subid, isSub);
- subFilter = LazyConfig.Instance.GetSubItem(subid)?.filter ?? "";
- }
-
- int countServers = 0;
- //Check for duplicate indexId
- List? lstDbIndexId = null;
- List lstAdd = new();
- var arrData = clipboardData.Split(Environment.NewLine.ToCharArray()).Where(t => !t.IsNullOrEmpty());
- if (isSub)
- {
- arrData = arrData.Distinct();
- }
- foreach (string str in arrData)
- {
- //maybe sub
- if (!isSub && (str.StartsWith(Global.httpsProtocol) || str.StartsWith(Global.httpProtocol)))
- {
- if (AddSubItem(ref config, str) == 0)
- {
- countServers++;
- }
- continue;
- }
- ProfileItem profileItem = ShareHandler.ImportFromClipboardConfig(str, out string msg);
- if (profileItem == null)
- {
- continue;
- }
-
- //exist sub items
- if (isSub && !Utils.IsNullOrEmpty(subid))
- {
- var existItem = lstOriSub?.FirstOrDefault(t => t.isSub == isSub && CompareProfileItem(t, profileItem, true));
- if (existItem != null)
- {
- //Check for duplicate indexId
- if (lstDbIndexId is null)
- {
- lstDbIndexId = LazyConfig.Instance.ProfileItemIndexs("");
- }
- if (lstAdd.Any(t => t.indexId == existItem.indexId)
- || lstDbIndexId.Any(t => t == existItem.indexId))
- {
- profileItem.indexId = string.Empty;
- }
- else
- {
- profileItem.indexId = existItem.indexId;
- }
- }
- //filter
- if (!Utils.IsNullOrEmpty(subFilter))
- {
- if (!Regex.IsMatch(profileItem.remarks, subFilter))
- {
- continue;
- }
- }
- }
- profileItem.subid = subid;
- profileItem.isSub = isSub;
- var addStatus = -1;
-
- if (profileItem.configType == EConfigType.VMess)
- {
- addStatus = AddServer(ref config, profileItem, false);
- }
- else if (profileItem.configType == EConfigType.Shadowsocks)
- {
- addStatus = AddShadowsocksServer(ref config, profileItem, false);
- }
- else if (profileItem.configType == EConfigType.Socks)
- {
- addStatus = AddSocksServer(ref config, profileItem, false);
- }
- else if (profileItem.configType == EConfigType.Trojan)
- {
- addStatus = AddTrojanServer(ref config, profileItem, false);
- }
- else if (profileItem.configType == EConfigType.VLESS)
- {
- addStatus = AddVlessServer(ref config, profileItem, false);
- }
-
- if (addStatus == 0)
- {
- countServers++;
- lstAdd.Add(profileItem);
- }
- }
-
- if (lstAdd.Count > 0)
- {
- SqliteHelper.Instance.InsertAll(lstAdd);
- }
-
- ToJsonFile(config);
- return countServers;
- }
-
- private static int AddBatchServers4Custom(ref Config config, string clipboardData, string subid, bool isSub, List lstOriSub)
- {
- if (Utils.IsNullOrEmpty(clipboardData))
- {
- return -1;
- }
-
- //判断str是否包含s的任意一个字符串
- static bool Containss(string str, params string[] s)
- {
- foreach (var item in s)
- {
- if (str.Contains(item, StringComparison.OrdinalIgnoreCase)) return true;
- }
- return false;
- }
-
- ProfileItem profileItem = new();
- //Is v2ray configuration
- V2rayConfig? v2rayConfig = Utils.FromJson(clipboardData);
- if (v2rayConfig?.inbounds?.Count > 0
- && v2rayConfig.outbounds?.Count > 0)
- {
- var fileName = Utils.GetTempPath($"{Utils.GetGUID(false)}.json");
- File.WriteAllText(fileName, clipboardData);
-
- profileItem.coreType = ECoreType.Xray;
- profileItem.address = fileName;
- profileItem.remarks = "v2ray_custom";
- }
- //Is Clash configuration
- else if (Containss(clipboardData, "port", "socks-port", "proxies"))
- {
- var fileName = Utils.GetTempPath($"{Utils.GetGUID(false)}.yaml");
- File.WriteAllText(fileName, clipboardData);
-
- profileItem.coreType = ECoreType.clash;
- profileItem.address = fileName;
- profileItem.remarks = "clash_custom";
- }
- //Is hysteria configuration
- else if (Containss(clipboardData, "server", "up", "down", "listen", "", ""))
- {
- var fileName = Utils.GetTempPath($"{Utils.GetGUID(false)}.json");
- File.WriteAllText(fileName, clipboardData);
-
- profileItem.coreType = ECoreType.hysteria;
- profileItem.address = fileName;
- profileItem.remarks = "hysteria_custom";
- }
- //Is naiveproxy configuration
- else if (Containss(clipboardData, "listen", "proxy", "", ""))
- {
- var fileName = Utils.GetTempPath($"{Utils.GetGUID(false)}.json");
- File.WriteAllText(fileName, clipboardData);
-
- profileItem.coreType = ECoreType.naiveproxy;
- profileItem.address = fileName;
- profileItem.remarks = "naiveproxy_custom";
- }
- //Is Other configuration
- else
- {
- return -1;
- //var fileName = Utils.GetTempPath($"{Utils.GetGUID(false)}.txt");
- //File.WriteAllText(fileName, clipboardData);
-
- //profileItem.address = fileName;
- //profileItem.remarks = "other_custom";
- }
-
- if (isSub && !Utils.IsNullOrEmpty(subid))
- {
- RemoveServerViaSubid(ref config, subid, isSub);
- }
- if (isSub && lstOriSub?.Count == 1)
- {
- profileItem.indexId = lstOriSub[0].indexId;
- }
- profileItem.subid = subid;
- profileItem.isSub = isSub;
-
- if (Utils.IsNullOrEmpty(profileItem.address))
- {
- return -1;
- }
-
- if (AddCustomServer(ref config, profileItem, true) == 0)
- {
- return 1;
- }
- else
- {
- return -1;
+ Utils.SaveLog("ToJsonFile", ex);
}
}
+ }
- private static int AddBatchServers4SsSIP008(ref Config config, string clipboardData, string subid, bool isSub, List lstOriSub)
+ public static int ImportOldGuiConfig(ref Config config, string fileName)
+ {
+ string result = Utils.LoadResource(fileName);
+ if (Utils.IsNullOrEmpty(result))
{
- if (Utils.IsNullOrEmpty(clipboardData))
- {
- return -1;
- }
-
- if (isSub && !Utils.IsNullOrEmpty(subid))
- {
- RemoveServerViaSubid(ref config, subid, isSub);
- }
-
- //SsSIP008
- var lstSsServer = Utils.FromJson>(clipboardData);
- if (lstSsServer?.Count <= 0)
- {
- var ssSIP008 = Utils.FromJson(clipboardData);
- if (ssSIP008?.servers?.Count > 0)
- {
- lstSsServer = ssSIP008.servers;
- }
- }
-
- if (lstSsServer?.Count > 0)
- {
- int counter = 0;
- foreach (var it in lstSsServer)
- {
- var ssItem = new ProfileItem()
- {
- subid = subid,
- remarks = it.remarks,
- security = it.method,
- id = it.password,
- address = it.server,
- port = Utils.ToInt(it.server_port)
- };
- ssItem.subid = subid;
- ssItem.isSub = isSub;
- if (AddShadowsocksServer(ref config, ssItem) == 0)
- {
- counter++;
- }
- }
- ToJsonFile(config);
- return counter;
- }
-
return -1;
}
- public static int AddBatchServers(ref Config config, string clipboardData, string subid, bool isSub)
+ var configOld = Utils.FromJson(result);
+ if (configOld == null)
{
- List? lstOriSub = null;
- if (isSub && !Utils.IsNullOrEmpty(subid))
- {
- lstOriSub = LazyConfig.Instance.ProfileItems(subid);
- }
-
- var counter = 0;
- if (Utils.IsBase64String(clipboardData))
- {
- counter = AddBatchServers(ref config, Utils.Base64Decode(clipboardData), subid, isSub, lstOriSub);
- }
- if (counter < 1)
- {
- counter = AddBatchServers(ref config, clipboardData, subid, isSub, lstOriSub);
- }
- if (counter < 1)
- {
- counter = AddBatchServers(ref config, Utils.Base64Decode(clipboardData), subid, isSub, lstOriSub);
- }
-
- if (counter < 1)
- {
- counter = AddBatchServers4SsSIP008(ref config, clipboardData, subid, isSub, lstOriSub);
- }
-
- //maybe other sub
- if (counter < 1)
- {
- counter = AddBatchServers4Custom(ref config, clipboardData, subid, isSub, lstOriSub);
- }
-
- return counter;
+ return -1;
}
- #endregion Batch add servers
-
- #region Sub & Group
-
- ///
- /// add sub
- ///
- ///
- ///
- ///
- public static int AddSubItem(ref Config config, string url)
+ var subItem = Utils.FromJson>(Utils.ToJson(configOld.subItem));
+ foreach (var it in subItem)
{
- //already exists
- if (SqliteHelper.Instance.Table().Where(e => e.url == url).Count() > 0)
+ if (Utils.IsNullOrEmpty(it.id))
{
- return 0;
+ it.id = Utils.GetGUID(false);
}
+ SqliteHelper.Instance.Replace(it);
+ }
- SubItem subItem = new()
+ var profileItems = Utils.FromJson>(Utils.ToJson(configOld.vmess));
+ foreach (var it in profileItems)
+ {
+ if (Utils.IsNullOrEmpty(it.indexId))
{
- id = string.Empty,
- remarks = "import_sub",
- url = url
+ it.indexId = Utils.GetGUID(false);
+ }
+ SqliteHelper.Instance.Replace(it);
+ }
+
+ foreach (var it in configOld.routings)
+ {
+ if (it.locked)
+ {
+ continue;
+ }
+ var routing = Utils.FromJson(Utils.ToJson(it));
+ foreach (var it2 in it.rules)
+ {
+ it2.id = Utils.GetGUID(false);
+ }
+ routing.ruleNum = it.rules.Count;
+ routing.ruleSet = Utils.ToJson(it.rules, false);
+
+ if (Utils.IsNullOrEmpty(routing.id))
+ {
+ routing.id = Utils.GetGUID(false);
+ }
+ SqliteHelper.Instance.Replace(routing);
+ }
+
+ config = Utils.FromJson(Utils.ToJson(configOld));
+
+ if (config.coreBasicItem == null)
+ {
+ config.coreBasicItem = new()
+ {
+ logEnabled = configOld.logEnabled,
+ loglevel = configOld.loglevel,
+ muxEnabled = configOld.muxEnabled,
};
-
- return AddSubItem(ref config, subItem);
}
- public static int AddSubItem(ref Config config, SubItem subItem)
+ if (config.routingBasicItem == null)
{
- if (Utils.IsNullOrEmpty(subItem.id))
+ config.routingBasicItem = new()
{
- subItem.id = Utils.GetGUID(false);
+ enableRoutingAdvanced = configOld.enableRoutingAdvanced,
+ domainStrategy = configOld.domainStrategy
+ };
+ }
- if (subItem.sort <= 0)
+ if (config.guiItem == null)
+ {
+ config.guiItem = new()
+ {
+ enableStatistics = configOld.enableStatistics,
+ keepOlderDedupl = configOld.keepOlderDedupl,
+ ignoreGeoUpdateCore = configOld.ignoreGeoUpdateCore,
+ autoUpdateInterval = configOld.autoUpdateInterval,
+ checkPreReleaseUpdate = configOld.checkPreReleaseUpdate,
+ enableSecurityProtocolTls13 = configOld.enableSecurityProtocolTls13,
+ trayMenuServersLimit = configOld.trayMenuServersLimit,
+ };
+ }
+
+ GetDefaultServer(ref config);
+ GetDefaultRouting(ref config);
+ SaveConfig(ref config);
+ LoadConfig(ref config);
+
+ return 0;
+ }
+
+ #endregion ConfigHandler
+
+ #region Server
+
+ ///
+ /// 添加服务器或编辑
+ ///
+ ///
+ ///
+ ///
+ public static int AddServer(ref Config config, ProfileItem profileItem, bool toFile = true)
+ {
+ profileItem.configType = EConfigType.VMess;
+
+ profileItem.address = profileItem.address.TrimEx();
+ profileItem.id = profileItem.id.TrimEx();
+ profileItem.security = profileItem.security.TrimEx();
+ profileItem.network = profileItem.network.TrimEx();
+ profileItem.headerType = profileItem.headerType.TrimEx();
+ profileItem.requestHost = profileItem.requestHost.TrimEx();
+ profileItem.path = profileItem.path.TrimEx();
+ profileItem.streamSecurity = profileItem.streamSecurity.TrimEx();
+
+ if (!Global.vmessSecuritys.Contains(profileItem.security))
+ {
+ return -1;
+ }
+ if (profileItem.id.IsNullOrEmpty())
+ {
+ return -1;
+ }
+
+ AddServerCommon(ref config, profileItem, toFile);
+
+ return 0;
+ }
+
+ ///
+ /// 移除服务器
+ ///
+ ///
+ ///
+ ///
+ public static int RemoveServer(Config config, List indexs)
+ {
+ var subid = "TempRemoveSubId";
+ foreach (var item in indexs)
+ {
+ item.subid = subid;
+ }
+
+ SqliteHelper.Instance.UpdateAll(indexs);
+ RemoveServerViaSubid(ref config, subid, false);
+
+ return 0;
+ }
+
+ ///
+ /// 克隆服务器
+ ///
+ ///
+ ///
+ ///
+ public static int CopyServer(ref Config config, List indexs)
+ {
+ foreach (var it in indexs)
+ {
+ var item = LazyConfig.Instance.GetProfileItem(it.indexId);
+ if (item is null)
+ {
+ continue;
+ }
+
+ ProfileItem profileItem = Utils.DeepCopy(item);
+ profileItem.indexId = string.Empty;
+ profileItem.remarks = $"{item.remarks}-clone";
+
+ if (profileItem.configType == EConfigType.Custom)
+ {
+ profileItem.address = Utils.GetConfigPath(profileItem.address);
+ if (AddCustomServer(ref config, profileItem, false) == 0)
{
- var maxSort = 0;
- if (SqliteHelper.Instance.Table().Count() > 0)
- {
- maxSort = SqliteHelper.Instance.Table().Max(t => t == null ? 0 : t.sort);
- }
- subItem.sort = maxSort + 1;
}
}
- if (SqliteHelper.Instance.Replace(subItem) > 0)
- {
- return 0;
- }
else
{
- return -1;
+ AddServerCommon(ref config, profileItem, true);
}
}
- ///
- /// 移除服务器
- ///
- ///
- ///
- ///
- public static int RemoveServerViaSubid(ref Config config, string subid, bool isSub)
+ return 0;
+ }
+
+ ///
+ /// 设置活动服务器
+ ///
+ ///
+ ///
+ ///
+ public static int SetDefaultServerIndex(ref Config config, string? indexId)
+ {
+ if (Utils.IsNullOrEmpty(indexId))
{
- if (Utils.IsNullOrEmpty(subid))
+ return -1;
+ }
+
+ config.indexId = indexId;
+
+ ToJsonFile(config);
+
+ return 0;
+ }
+
+ public static int SetDefaultServer(Config config, List lstProfile)
+ {
+ if (lstProfile.Exists(t => t.indexId == config.indexId))
+ {
+ return 0;
+ }
+ if (SqliteHelper.Instance.Table().Where(t => t.indexId == config.indexId).Any())
+ {
+ return 0;
+ }
+ if (lstProfile.Count > 0)
+ {
+ return SetDefaultServerIndex(ref config, lstProfile.Where(t => t.port > 0).FirstOrDefault()?.indexId);
+ }
+ return SetDefaultServerIndex(ref config, SqliteHelper.Instance.Table().Where(t => t.port > 0).Select(t => t.indexId).FirstOrDefault());
+ }
+
+ public static ProfileItem? GetDefaultServer(ref Config config)
+ {
+ var item = LazyConfig.Instance.GetProfileItem(config.indexId);
+ if (item is null)
+ {
+ var item2 = SqliteHelper.Instance.Table().FirstOrDefault();
+ SetDefaultServerIndex(ref config, item2?.indexId);
+ return item2;
+ }
+
+ return item;
+ }
+
+ ///
+ /// 移动服务器
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ public static int MoveServer(ref Config config, ref List lstProfile, int index, EMove eMove, int pos = -1)
+ {
+ int count = lstProfile.Count;
+ if (index < 0 || index > lstProfile.Count - 1)
+ {
+ return -1;
+ }
+
+ for (int i = 0; i < lstProfile.Count; i++)
+ {
+ ProfileExHandler.Instance.SetSort(lstProfile[i].indexId, (i + 1) * 10);
+ }
+
+ var sort = 0;
+ switch (eMove)
+ {
+ case EMove.Top:
+ {
+ if (index == 0)
+ {
+ return 0;
+ }
+ sort = ProfileExHandler.Instance.GetSort(lstProfile[0].indexId) - 1;
+
+ break;
+ }
+ case EMove.Up:
+ {
+ if (index == 0)
+ {
+ return 0;
+ }
+ sort = ProfileExHandler.Instance.GetSort(lstProfile[index - 1].indexId) - 1;
+
+ break;
+ }
+
+ case EMove.Down:
+ {
+ if (index == count - 1)
+ {
+ return 0;
+ }
+ sort = ProfileExHandler.Instance.GetSort(lstProfile[index + 1].indexId) + 1;
+
+ break;
+ }
+ case EMove.Bottom:
+ {
+ if (index == count - 1)
+ {
+ return 0;
+ }
+ sort = ProfileExHandler.Instance.GetSort(lstProfile[^1].indexId) + 1;
+
+ break;
+ }
+ case EMove.Position:
+ sort = pos * 10 + 1;
+ break;
+ }
+
+ ProfileExHandler.Instance.SetSort(lstProfile[index].indexId, sort);
+ return 0;
+ }
+
+ ///
+ /// 添加自定义服务器
+ ///
+ ///
+ ///
+ ///
+ public static int AddCustomServer(ref Config config, ProfileItem profileItem, bool blDelete)
+ {
+ var fileName = profileItem.address;
+ if (!File.Exists(fileName))
+ {
+ return -1;
+ }
+ var ext = Path.GetExtension(fileName);
+ string newFileName = $"{Utils.GetGUID()}{ext}";
+ //newFileName = Path.Combine(Utils.GetTempPath(), newFileName);
+
+ try
+ {
+ File.Copy(fileName, Utils.GetConfigPath(newFileName));
+ if (blDelete)
{
- return -1;
+ File.Delete(fileName);
}
- var customProfile = SqliteHelper.Instance.Table().Where(t => t.subid == subid && t.configType == EConfigType.Custom).ToList();
- if (isSub)
+ }
+ catch (Exception ex)
+ {
+ Utils.SaveLog(ex.Message, ex);
+ return -1;
+ }
+
+ profileItem.address = newFileName;
+ profileItem.configType = EConfigType.Custom;
+ if (Utils.IsNullOrEmpty(profileItem.remarks))
+ {
+ profileItem.remarks = $"import custom@{DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss")}";
+ }
+
+ AddServerCommon(ref config, profileItem, true);
+
+ return 0;
+ }
+
+ ///
+ /// 添加服务器或编辑
+ ///
+ ///
+ ///
+ ///
+ public static int EditCustomServer(ref Config config, ProfileItem profileItem)
+ {
+ if (SqliteHelper.Instance.Update(profileItem) > 0)
+ {
+ return 0;
+ }
+ else
+ {
+ return -1;
+ }
+
+ //ToJsonFile(config);
+ }
+
+ ///
+ /// 添加服务器或编辑
+ ///
+ ///
+ ///
+ ///
+ public static int AddShadowsocksServer(ref Config config, ProfileItem profileItem, bool toFile = true)
+ {
+ profileItem.configType = EConfigType.Shadowsocks;
+
+ profileItem.address = profileItem.address.TrimEx();
+ profileItem.id = profileItem.id.TrimEx();
+ profileItem.security = profileItem.security.TrimEx();
+
+ if (!LazyConfig.Instance.GetShadowsocksSecuritys(profileItem).Contains(profileItem.security))
+ {
+ return -1;
+ }
+ if (profileItem.id.IsNullOrEmpty())
+ {
+ return -1;
+ }
+
+ AddServerCommon(ref config, profileItem, toFile);
+
+ return 0;
+ }
+
+ ///
+ /// 添加服务器或编辑
+ ///
+ ///
+ ///
+ ///
+ public static int AddSocksServer(ref Config config, ProfileItem profileItem, bool toFile = true)
+ {
+ profileItem.configType = EConfigType.Socks;
+
+ profileItem.address = profileItem.address.TrimEx();
+
+ AddServerCommon(ref config, profileItem, toFile);
+
+ return 0;
+ }
+
+ ///
+ /// 添加服务器或编辑
+ ///
+ ///
+ ///
+ ///
+ public static int AddTrojanServer(ref Config config, ProfileItem profileItem, bool toFile = true)
+ {
+ profileItem.configType = EConfigType.Trojan;
+
+ profileItem.address = profileItem.address.TrimEx();
+ profileItem.id = profileItem.id.TrimEx();
+ if (Utils.IsNullOrEmpty(profileItem.streamSecurity))
+ {
+ profileItem.streamSecurity = Global.StreamSecurity;
+ }
+ if (profileItem.id.IsNullOrEmpty())
+ {
+ return -1;
+ }
+
+ AddServerCommon(ref config, profileItem, toFile);
+
+ return 0;
+ }
+
+ public static int SortServers(ref Config config, string subId, string colName, bool asc)
+ {
+ var lstModel = LazyConfig.Instance.ProfileItems(subId, "");
+ if (lstModel.Count <= 0)
+ {
+ return -1;
+ }
+ var lstProfileExs = ProfileExHandler.Instance.ProfileExs;
+ var lstProfile = (from t in lstModel
+ 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,
+ delay = t33 == null ? 0 : t33.delay,
+ speed = t33 == null ? 0 : t33.speed,
+ sort = t33 == null ? 0 : t33.sort
+ }).ToList();
+
+ Enum.TryParse(colName, true, out EServerColName name);
+ var propertyName = string.Empty;
+ switch (name)
+ {
+ case EServerColName.configType:
+ case EServerColName.remarks:
+ case EServerColName.address:
+ case EServerColName.port:
+ case EServerColName.security:
+ case EServerColName.network:
+ case EServerColName.streamSecurity:
+ propertyName = name.ToString();
+ break;
+
+ case EServerColName.delayVal:
+ propertyName = "delay";
+ break;
+
+ case EServerColName.speedVal:
+ propertyName = "speed";
+ break;
+
+ case EServerColName.subRemarks:
+ propertyName = "subid";
+ break;
+
+ default:
+ return -1;
+ }
+
+ var items = lstProfile.AsQueryable();
+
+ if (asc)
+ {
+ lstProfile = items.OrderBy(propertyName).ToList();
+ }
+ else
+ {
+ lstProfile = items.OrderByDescending(propertyName).ToList();
+ }
+ for (int i = 0; i < lstProfile.Count; i++)
+ {
+ ProfileExHandler.Instance.SetSort(lstProfile[i].indexId, (i + 1) * 10);
+ }
+ if (name == EServerColName.delayVal)
+ {
+ var maxSort = lstProfile.Max(t => t.sort) + 10;
+ foreach (var item in lstProfile)
{
- SqliteHelper.Instance.Execute($"delete from ProfileItem where isSub = 1 and subid = '{subid}'");
+ if (item.delay <= 0)
+ {
+ ProfileExHandler.Instance.SetSort(item.indexId, maxSort);
+ }
+ }
+ }
+ if (name == EServerColName.speedVal)
+ {
+ var maxSort = lstProfile.Max(t => t.sort) + 10;
+ foreach (var item in lstProfile)
+ {
+ if (item.speed <= 0)
+ {
+ ProfileExHandler.Instance.SetSort(item.indexId, maxSort);
+ }
+ }
+ }
+
+ return 0;
+ }
+
+ ///
+ /// 添加服务器或编辑
+ ///
+ ///
+ ///
+ ///
+ public static int AddVlessServer(ref Config config, ProfileItem profileItem, bool toFile = true)
+ {
+ profileItem.configType = EConfigType.VLESS;
+
+ profileItem.address = profileItem.address.TrimEx();
+ profileItem.id = profileItem.id.TrimEx();
+ profileItem.security = profileItem.security.TrimEx();
+ profileItem.network = profileItem.network.TrimEx();
+ profileItem.headerType = profileItem.headerType.TrimEx();
+ profileItem.requestHost = profileItem.requestHost.TrimEx();
+ profileItem.path = profileItem.path.TrimEx();
+ profileItem.streamSecurity = profileItem.streamSecurity.TrimEx();
+
+ if (!Global.flows.Contains(profileItem.flow))
+ {
+ profileItem.flow = Global.flows.First();
+ }
+ if (profileItem.id.IsNullOrEmpty())
+ {
+ return -1;
+ }
+
+ AddServerCommon(ref config, profileItem, toFile);
+
+ return 0;
+ }
+
+ public static Tuple DedupServerList(Config config, string subId)
+ {
+ var lstProfile = LazyConfig.Instance.ProfileItems(subId);
+
+ List lstKeep = new();
+ List lstRemove = new();
+ if (!config.guiItem.keepOlderDedupl) lstProfile.Reverse();
+
+ foreach (ProfileItem item in lstProfile)
+ {
+ if (!lstKeep.Exists(i => CompareProfileItem(i, item, false)))
+ {
+ lstKeep.Add(item);
}
else
{
- SqliteHelper.Instance.Execute($"delete from ProfileItem where subid = '{subid}'");
+ lstRemove.Add(item);
}
- foreach (var item in customProfile)
+ }
+ RemoveServer(config, lstRemove);
+
+ return new Tuple(lstProfile.Count, lstKeep.Count);
+ }
+
+ public static int AddServerCommon(ref Config config, ProfileItem profileItem, bool toFile = true)
+ {
+ profileItem.configVersion = 2;
+
+ if (!Utils.IsNullOrEmpty(profileItem.streamSecurity))
+ {
+ if (Utils.IsNullOrEmpty(profileItem.allowInsecure))
+ {
+ profileItem.allowInsecure = config.coreBasicItem.defAllowInsecure.ToString().ToLower();
+ }
+ if (Utils.IsNullOrEmpty(profileItem.fingerprint))
+ {
+ profileItem.fingerprint = config.coreBasicItem.defFingerprint;
+ }
+ }
+
+ if (!Utils.IsNullOrEmpty(profileItem.network) && !Global.networks.Contains(profileItem.network))
+ {
+ profileItem.network = Global.DefaultNetwork;
+ }
+
+ var maxSort = -1;
+ if (Utils.IsNullOrEmpty(profileItem.indexId))
+ {
+ profileItem.indexId = Utils.GetGUID(false);
+ maxSort = ProfileExHandler.Instance.GetMaxSort();
+ }
+ if (!toFile && maxSort < 0)
+ {
+ maxSort = ProfileExHandler.Instance.GetMaxSort();
+ }
+ if (maxSort > 0)
+ {
+ ProfileExHandler.Instance.SetSort(profileItem.indexId, maxSort + 1);
+ }
+
+ if (toFile)
+ {
+ SqliteHelper.Instance.Replace(profileItem);
+ }
+ return 0;
+ }
+
+ private static bool CompareProfileItem(ProfileItem o, ProfileItem n, bool remarks)
+ {
+ if (o == null || n == null)
+ {
+ return false;
+ }
+
+ return o.configType == n.configType
+ && o.address == n.address
+ && o.port == n.port
+ && o.id == n.id
+ && o.alterId == n.alterId
+ && o.security == n.security
+ && o.network == n.network
+ && o.headerType == n.headerType
+ && o.requestHost == n.requestHost
+ && o.path == n.path
+ && (o.configType == EConfigType.Trojan || o.streamSecurity == n.streamSecurity)
+ && o.flow == n.flow
+ && o.sni == n.sni
+ && (!remarks || o.remarks == n.remarks);
+ }
+
+ private static int RemoveProfileItem(Config config, string indexId)
+ {
+ try
+ {
+ var item = LazyConfig.Instance.GetProfileItem(indexId);
+ if (item == null)
+ {
+ return 0;
+ }
+ if (item.configType == EConfigType.Custom)
{
File.Delete(Utils.GetConfigPath(item.address));
}
- return 0;
- }
-
- public static int DeleteSubItem(ref Config config, string id)
- {
- var item = LazyConfig.Instance.GetSubItem(id);
- if (item is null)
- {
- return 0;
- }
SqliteHelper.Instance.Delete(item);
- RemoveServerViaSubid(ref config, id, false);
-
- return 0;
+ }
+ catch (Exception ex)
+ {
+ Utils.SaveLog("Remove Item", ex);
}
- public static int MoveToGroup(Config config, List lstProfile, string subid)
- {
- foreach (var item in lstProfile)
- {
- item.subid = subid;
- }
- SqliteHelper.Instance.UpdateAll(lstProfile);
+ return 0;
+ }
- return 0;
+ #endregion Server
+
+ #region Batch add servers
+
+ ///
+ /// 批量添加服务器
+ ///
+ ///
+ ///
+ ///
+ /// 成功导入的数量
+ private static int AddBatchServers(ref Config config, string clipboardData, string subid, bool isSub, List lstOriSub)
+ {
+ if (Utils.IsNullOrEmpty(clipboardData))
+ {
+ return -1;
}
- #endregion Sub & Group
-
- #region Routing
-
- public static int SaveRoutingItem(ref Config config, RoutingItem item)
+ string subFilter = string.Empty;
+ //remove sub items
+ if (isSub && !Utils.IsNullOrEmpty(subid))
{
- if (Utils.IsNullOrEmpty(item.id))
- {
- item.id = Utils.GetGUID(false);
- }
-
- if (SqliteHelper.Instance.Replace(item) > 0)
- {
- return 0;
- }
- else
- {
- return -1;
- }
+ RemoveServerViaSubid(ref config, subid, isSub);
+ subFilter = LazyConfig.Instance.GetSubItem(subid)?.filter ?? "";
}
- ///
- /// AddBatchRoutingRules
- ///
- ///
- ///
- ///
- public static int AddBatchRoutingRules(ref RoutingItem routingItem, string clipboardData)
+ int countServers = 0;
+ //Check for duplicate indexId
+ List? lstDbIndexId = null;
+ List lstAdd = new();
+ var arrData = clipboardData.Split(Environment.NewLine.ToCharArray()).Where(t => !t.IsNullOrEmpty());
+ if (isSub)
{
- if (Utils.IsNullOrEmpty(clipboardData))
- {
- return -1;
- }
-
- var lstRules = Utils.FromJson>(clipboardData);
- if (lstRules == null)
- {
- return -1;
- }
-
- foreach (var item in lstRules)
- {
- item.id = Utils.GetGUID(false);
- }
- routingItem.ruleNum = lstRules.Count;
- routingItem.ruleSet = Utils.ToJson(lstRules, false);
-
- if (Utils.IsNullOrEmpty(routingItem.id))
- {
- routingItem.id = Utils.GetGUID(false);
- }
-
- if (SqliteHelper.Instance.Replace(routingItem) > 0)
- {
- return 0;
- }
- else
- {
- return -1;
- }
+ arrData = arrData.Distinct();
}
-
- ///
- /// MoveRoutingRule
- ///
- ///
- ///
- ///
- ///
- public static int MoveRoutingRule(List rules, int index, EMove eMove, int pos = -1)
+ foreach (string str in arrData)
{
- int count = rules.Count;
- if (index < 0 || index > rules.Count - 1)
+ //maybe sub
+ if (!isSub && (str.StartsWith(Global.httpsProtocol) || str.StartsWith(Global.httpProtocol)))
{
- return -1;
- }
- switch (eMove)
- {
- case EMove.Top:
- {
- if (index == 0)
- {
- return 0;
- }
- var item = Utils.DeepCopy(rules[index]);
- rules.RemoveAt(index);
- rules.Insert(0, item);
-
- break;
- }
- case EMove.Up:
- {
- if (index == 0)
- {
- return 0;
- }
- var item = Utils.DeepCopy(rules[index]);
- rules.RemoveAt(index);
- rules.Insert(index - 1, item);
-
- break;
- }
-
- case EMove.Down:
- {
- if (index == count - 1)
- {
- return 0;
- }
- var item = Utils.DeepCopy(rules[index]);
- rules.RemoveAt(index);
- rules.Insert(index + 1, item);
-
- break;
- }
- case EMove.Bottom:
- {
- if (index == count - 1)
- {
- return 0;
- }
- var item = Utils.DeepCopy(rules[index]);
- rules.RemoveAt(index);
- rules.Add(item);
-
- break;
- }
- case EMove.Position:
- {
- var removeItem = rules[index];
- var item = Utils.DeepCopy(rules[index]);
- rules.Insert(pos, item);
- rules.Remove(removeItem);
- break;
- }
- }
- return 0;
- }
-
- public static int SetDefaultRouting(ref Config config, RoutingItem routingItem)
- {
- if (SqliteHelper.Instance.Table().Where(t => t.id == routingItem.id).Count() > 0)
- {
- config.routingBasicItem.routingIndexId = routingItem.id;
- }
-
- ToJsonFile(config);
-
- return 0;
- }
-
- public static RoutingItem GetDefaultRouting(ref Config config)
- {
- var item = LazyConfig.Instance.GetRoutingItem(config.routingBasicItem.routingIndexId);
- if (item is null)
- {
- var item2 = SqliteHelper.Instance.Table().FirstOrDefault(t => t.locked == false);
- SetDefaultRouting(ref config, item2);
- return item2;
- }
-
- return item;
- }
-
- public static int InitBuiltinRouting(ref Config config, bool blImportAdvancedRules = false)
- {
- var items = LazyConfig.Instance.RoutingItems();
- if (blImportAdvancedRules || items.Count <= 0)
- {
- var maxSort = items.Count;
- //Bypass the mainland
- var item2 = new RoutingItem()
+ if (AddSubItem(ref config, str) == 0)
{
- remarks = "绕过大陆(Whitelist)",
- url = string.Empty,
- sort = maxSort + 1,
- };
- AddBatchRoutingRules(ref item2, Utils.GetEmbedText(Global.CustomRoutingFileName + "white"));
+ countServers++;
+ }
+ continue;
+ }
+ ProfileItem profileItem = ShareHandler.ImportFromClipboardConfig(str, out string msg);
+ if (profileItem == null)
+ {
+ continue;
+ }
- //Blacklist
- var item3 = new RoutingItem()
+ //exist sub items
+ if (isSub && !Utils.IsNullOrEmpty(subid))
+ {
+ var existItem = lstOriSub?.FirstOrDefault(t => t.isSub == isSub && CompareProfileItem(t, profileItem, true));
+ if (existItem != null)
{
- remarks = "黑名单(Blacklist)",
- url = string.Empty,
- sort = maxSort + 2,
- };
- AddBatchRoutingRules(ref item3, Utils.GetEmbedText(Global.CustomRoutingFileName + "black"));
-
- //Global
- var item1 = new RoutingItem()
+ //Check for duplicate indexId
+ if (lstDbIndexId is null)
+ {
+ lstDbIndexId = LazyConfig.Instance.ProfileItemIndexs("");
+ }
+ if (lstAdd.Any(t => t.indexId == existItem.indexId)
+ || lstDbIndexId.Any(t => t == existItem.indexId))
+ {
+ profileItem.indexId = string.Empty;
+ }
+ else
+ {
+ profileItem.indexId = existItem.indexId;
+ }
+ }
+ //filter
+ if (!Utils.IsNullOrEmpty(subFilter))
{
- remarks = "全局(Global)",
- url = string.Empty,
- sort = maxSort + 3,
- };
- AddBatchRoutingRules(ref item1, Utils.GetEmbedText(Global.CustomRoutingFileName + "global"));
-
- if (!blImportAdvancedRules)
- {
- SetDefaultRouting(ref config, item2);
+ if (!Regex.IsMatch(profileItem.remarks, subFilter))
+ {
+ continue;
+ }
}
}
+ profileItem.subid = subid;
+ profileItem.isSub = isSub;
+ var addStatus = -1;
- if (GetLockedRoutingItem(ref config) == null)
+ if (profileItem.configType == EConfigType.VMess)
{
- var item1 = new RoutingItem()
- {
- remarks = "locked",
- url = string.Empty,
- locked = true,
- };
- AddBatchRoutingRules(ref item1, Utils.GetEmbedText(Global.CustomRoutingFileName + "locked"));
+ addStatus = AddServer(ref config, profileItem, false);
+ }
+ else if (profileItem.configType == EConfigType.Shadowsocks)
+ {
+ addStatus = AddShadowsocksServer(ref config, profileItem, false);
+ }
+ else if (profileItem.configType == EConfigType.Socks)
+ {
+ addStatus = AddSocksServer(ref config, profileItem, false);
+ }
+ else if (profileItem.configType == EConfigType.Trojan)
+ {
+ addStatus = AddTrojanServer(ref config, profileItem, false);
+ }
+ else if (profileItem.configType == EConfigType.VLESS)
+ {
+ addStatus = AddVlessServer(ref config, profileItem, false);
+ }
+
+ if (addStatus == 0)
+ {
+ countServers++;
+ lstAdd.Add(profileItem);
}
- return 0;
}
- public static RoutingItem GetLockedRoutingItem(ref Config config)
+ if (lstAdd.Count > 0)
{
- return SqliteHelper.Instance.Table().FirstOrDefault(it => it.locked == true);
+ SqliteHelper.Instance.InsertAll(lstAdd);
}
- public static void RemoveRoutingItem(RoutingItem routingItem)
- {
- SqliteHelper.Instance.Delete(routingItem);
- }
-
- #endregion Routing
-
- #region DNS
-
- public static int InitBuiltinDNS(Config config)
- {
- var items = LazyConfig.Instance.DNSItems();
- if (items.Count <= 0)
- {
- var item = new DNSItem()
- {
- remarks = "V2ray",
- coreType = ECoreType.Xray,
- };
- SaveDNSItems(config, item);
-
- var item2 = new DNSItem()
- {
- remarks = "sing-box",
- coreType = ECoreType.sing_box,
- };
- SaveDNSItems(config, item2);
- }
-
- return 0;
- }
-
- public static int SaveDNSItems(Config config, DNSItem item)
- {
- if (Utils.IsNullOrEmpty(item.id))
- {
- item.id = Utils.GetGUID(false);
- }
-
- if (SqliteHelper.Instance.Replace(item) > 0)
- {
- return 0;
- }
- else
- {
- return -1;
- }
- }
-
- #endregion DNS
+ ToJsonFile(config);
+ return countServers;
}
+
+ private static int AddBatchServers4Custom(ref Config config, string clipboardData, string subid, bool isSub, List lstOriSub)
+ {
+ if (Utils.IsNullOrEmpty(clipboardData))
+ {
+ return -1;
+ }
+
+ //判断str是否包含s的任意一个字符串
+ static bool Containss(string str, params string[] s)
+ {
+ foreach (var item in s)
+ {
+ if (str.Contains(item, StringComparison.OrdinalIgnoreCase)) return true;
+ }
+ return false;
+ }
+
+ ProfileItem profileItem = new();
+ //Is v2ray configuration
+ V2rayConfig? v2rayConfig = Utils.FromJson(clipboardData);
+ if (v2rayConfig?.inbounds?.Count > 0
+ && v2rayConfig.outbounds?.Count > 0)
+ {
+ var fileName = Utils.GetTempPath($"{Utils.GetGUID(false)}.json");
+ File.WriteAllText(fileName, clipboardData);
+
+ profileItem.coreType = ECoreType.Xray;
+ profileItem.address = fileName;
+ profileItem.remarks = "v2ray_custom";
+ }
+ //Is Clash configuration
+ else if (Containss(clipboardData, "port", "socks-port", "proxies"))
+ {
+ var fileName = Utils.GetTempPath($"{Utils.GetGUID(false)}.yaml");
+ File.WriteAllText(fileName, clipboardData);
+
+ profileItem.coreType = ECoreType.clash;
+ profileItem.address = fileName;
+ profileItem.remarks = "clash_custom";
+ }
+ //Is hysteria configuration
+ else if (Containss(clipboardData, "server", "up", "down", "listen", "", ""))
+ {
+ var fileName = Utils.GetTempPath($"{Utils.GetGUID(false)}.json");
+ File.WriteAllText(fileName, clipboardData);
+
+ profileItem.coreType = ECoreType.hysteria;
+ profileItem.address = fileName;
+ profileItem.remarks = "hysteria_custom";
+ }
+ //Is naiveproxy configuration
+ else if (Containss(clipboardData, "listen", "proxy", "", ""))
+ {
+ var fileName = Utils.GetTempPath($"{Utils.GetGUID(false)}.json");
+ File.WriteAllText(fileName, clipboardData);
+
+ profileItem.coreType = ECoreType.naiveproxy;
+ profileItem.address = fileName;
+ profileItem.remarks = "naiveproxy_custom";
+ }
+ //Is Other configuration
+ else
+ {
+ return -1;
+ //var fileName = Utils.GetTempPath($"{Utils.GetGUID(false)}.txt");
+ //File.WriteAllText(fileName, clipboardData);
+
+ //profileItem.address = fileName;
+ //profileItem.remarks = "other_custom";
+ }
+
+ if (isSub && !Utils.IsNullOrEmpty(subid))
+ {
+ RemoveServerViaSubid(ref config, subid, isSub);
+ }
+ if (isSub && lstOriSub?.Count == 1)
+ {
+ profileItem.indexId = lstOriSub[0].indexId;
+ }
+ profileItem.subid = subid;
+ profileItem.isSub = isSub;
+
+ if (Utils.IsNullOrEmpty(profileItem.address))
+ {
+ return -1;
+ }
+
+ if (AddCustomServer(ref config, profileItem, true) == 0)
+ {
+ return 1;
+ }
+ else
+ {
+ return -1;
+ }
+ }
+
+ private static int AddBatchServers4SsSIP008(ref Config config, string clipboardData, string subid, bool isSub, List lstOriSub)
+ {
+ if (Utils.IsNullOrEmpty(clipboardData))
+ {
+ return -1;
+ }
+
+ if (isSub && !Utils.IsNullOrEmpty(subid))
+ {
+ RemoveServerViaSubid(ref config, subid, isSub);
+ }
+
+ //SsSIP008
+ var lstSsServer = Utils.FromJson>(clipboardData);
+ if (lstSsServer?.Count <= 0)
+ {
+ var ssSIP008 = Utils.FromJson(clipboardData);
+ if (ssSIP008?.servers?.Count > 0)
+ {
+ lstSsServer = ssSIP008.servers;
+ }
+ }
+
+ if (lstSsServer?.Count > 0)
+ {
+ int counter = 0;
+ foreach (var it in lstSsServer)
+ {
+ var ssItem = new ProfileItem()
+ {
+ subid = subid,
+ remarks = it.remarks,
+ security = it.method,
+ id = it.password,
+ address = it.server,
+ port = Utils.ToInt(it.server_port)
+ };
+ ssItem.subid = subid;
+ ssItem.isSub = isSub;
+ if (AddShadowsocksServer(ref config, ssItem) == 0)
+ {
+ counter++;
+ }
+ }
+ ToJsonFile(config);
+ return counter;
+ }
+
+ return -1;
+ }
+
+ public static int AddBatchServers(ref Config config, string clipboardData, string subid, bool isSub)
+ {
+ List? lstOriSub = null;
+ if (isSub && !Utils.IsNullOrEmpty(subid))
+ {
+ lstOriSub = LazyConfig.Instance.ProfileItems(subid);
+ }
+
+ var counter = 0;
+ if (Utils.IsBase64String(clipboardData))
+ {
+ counter = AddBatchServers(ref config, Utils.Base64Decode(clipboardData), subid, isSub, lstOriSub);
+ }
+ if (counter < 1)
+ {
+ counter = AddBatchServers(ref config, clipboardData, subid, isSub, lstOriSub);
+ }
+ if (counter < 1)
+ {
+ counter = AddBatchServers(ref config, Utils.Base64Decode(clipboardData), subid, isSub, lstOriSub);
+ }
+
+ if (counter < 1)
+ {
+ counter = AddBatchServers4SsSIP008(ref config, clipboardData, subid, isSub, lstOriSub);
+ }
+
+ //maybe other sub
+ if (counter < 1)
+ {
+ counter = AddBatchServers4Custom(ref config, clipboardData, subid, isSub, lstOriSub);
+ }
+
+ return counter;
+ }
+
+ #endregion Batch add servers
+
+ #region Sub & Group
+
+ ///
+ /// add sub
+ ///
+ ///
+ ///
+ ///
+ public static int AddSubItem(ref Config config, string url)
+ {
+ //already exists
+ if (SqliteHelper.Instance.Table().Where(e => e.url == url).Count() > 0)
+ {
+ return 0;
+ }
+
+ SubItem subItem = new()
+ {
+ id = string.Empty,
+ remarks = "import_sub",
+ url = url
+ };
+
+ return AddSubItem(ref config, subItem);
+ }
+
+ public static int AddSubItem(ref Config config, SubItem subItem)
+ {
+ if (Utils.IsNullOrEmpty(subItem.id))
+ {
+ subItem.id = Utils.GetGUID(false);
+
+ if (subItem.sort <= 0)
+ {
+ var maxSort = 0;
+ if (SqliteHelper.Instance.Table().Count() > 0)
+ {
+ maxSort = SqliteHelper.Instance.Table().Max(t => t == null ? 0 : t.sort);
+ }
+ subItem.sort = maxSort + 1;
+ }
+ }
+ if (SqliteHelper.Instance.Replace(subItem) > 0)
+ {
+ return 0;
+ }
+ else
+ {
+ return -1;
+ }
+ }
+
+ ///
+ /// 移除服务器
+ ///
+ ///
+ ///
+ ///
+ public static int RemoveServerViaSubid(ref Config config, string subid, bool isSub)
+ {
+ if (Utils.IsNullOrEmpty(subid))
+ {
+ return -1;
+ }
+ var customProfile = SqliteHelper.Instance.Table().Where(t => t.subid == subid && t.configType == EConfigType.Custom).ToList();
+ if (isSub)
+ {
+ SqliteHelper.Instance.Execute($"delete from ProfileItem where isSub = 1 and subid = '{subid}'");
+ }
+ else
+ {
+ SqliteHelper.Instance.Execute($"delete from ProfileItem where subid = '{subid}'");
+ }
+ foreach (var item in customProfile)
+ {
+ File.Delete(Utils.GetConfigPath(item.address));
+ }
+
+ return 0;
+ }
+
+ public static int DeleteSubItem(ref Config config, string id)
+ {
+ var item = LazyConfig.Instance.GetSubItem(id);
+ if (item is null)
+ {
+ return 0;
+ }
+ SqliteHelper.Instance.Delete(item);
+ RemoveServerViaSubid(ref config, id, false);
+
+ return 0;
+ }
+
+ public static int MoveToGroup(Config config, List lstProfile, string subid)
+ {
+ foreach (var item in lstProfile)
+ {
+ item.subid = subid;
+ }
+ SqliteHelper.Instance.UpdateAll(lstProfile);
+
+ return 0;
+ }
+
+ #endregion Sub & Group
+
+ #region Routing
+
+ public static int SaveRoutingItem(ref Config config, RoutingItem item)
+ {
+ if (Utils.IsNullOrEmpty(item.id))
+ {
+ item.id = Utils.GetGUID(false);
+ }
+
+ if (SqliteHelper.Instance.Replace(item) > 0)
+ {
+ return 0;
+ }
+ else
+ {
+ return -1;
+ }
+ }
+
+ ///
+ /// AddBatchRoutingRules
+ ///
+ ///
+ ///
+ ///
+ public static int AddBatchRoutingRules(ref RoutingItem routingItem, string clipboardData)
+ {
+ if (Utils.IsNullOrEmpty(clipboardData))
+ {
+ return -1;
+ }
+
+ var lstRules = Utils.FromJson>(clipboardData);
+ if (lstRules == null)
+ {
+ return -1;
+ }
+
+ foreach (var item in lstRules)
+ {
+ item.id = Utils.GetGUID(false);
+ }
+ routingItem.ruleNum = lstRules.Count;
+ routingItem.ruleSet = Utils.ToJson(lstRules, false);
+
+ if (Utils.IsNullOrEmpty(routingItem.id))
+ {
+ routingItem.id = Utils.GetGUID(false);
+ }
+
+ if (SqliteHelper.Instance.Replace(routingItem) > 0)
+ {
+ return 0;
+ }
+ else
+ {
+ return -1;
+ }
+ }
+
+ ///
+ /// MoveRoutingRule
+ ///
+ ///
+ ///
+ ///
+ ///
+ public static int MoveRoutingRule(List rules, int index, EMove eMove, int pos = -1)
+ {
+ int count = rules.Count;
+ if (index < 0 || index > rules.Count - 1)
+ {
+ return -1;
+ }
+ switch (eMove)
+ {
+ case EMove.Top:
+ {
+ if (index == 0)
+ {
+ return 0;
+ }
+ var item = Utils.DeepCopy(rules[index]);
+ rules.RemoveAt(index);
+ rules.Insert(0, item);
+
+ break;
+ }
+ case EMove.Up:
+ {
+ if (index == 0)
+ {
+ return 0;
+ }
+ var item = Utils.DeepCopy(rules[index]);
+ rules.RemoveAt(index);
+ rules.Insert(index - 1, item);
+
+ break;
+ }
+
+ case EMove.Down:
+ {
+ if (index == count - 1)
+ {
+ return 0;
+ }
+ var item = Utils.DeepCopy(rules[index]);
+ rules.RemoveAt(index);
+ rules.Insert(index + 1, item);
+
+ break;
+ }
+ case EMove.Bottom:
+ {
+ if (index == count - 1)
+ {
+ return 0;
+ }
+ var item = Utils.DeepCopy(rules[index]);
+ rules.RemoveAt(index);
+ rules.Add(item);
+
+ break;
+ }
+ case EMove.Position:
+ {
+ var removeItem = rules[index];
+ var item = Utils.DeepCopy(rules[index]);
+ rules.Insert(pos, item);
+ rules.Remove(removeItem);
+ break;
+ }
+ }
+ return 0;
+ }
+
+ public static int SetDefaultRouting(ref Config config, RoutingItem routingItem)
+ {
+ if (SqliteHelper.Instance.Table().Where(t => t.id == routingItem.id).Count() > 0)
+ {
+ config.routingBasicItem.routingIndexId = routingItem.id;
+ }
+
+ ToJsonFile(config);
+
+ return 0;
+ }
+
+ public static RoutingItem GetDefaultRouting(ref Config config)
+ {
+ var item = LazyConfig.Instance.GetRoutingItem(config.routingBasicItem.routingIndexId);
+ if (item is null)
+ {
+ var item2 = SqliteHelper.Instance.Table().FirstOrDefault(t => t.locked == false);
+ SetDefaultRouting(ref config, item2);
+ return item2;
+ }
+
+ return item;
+ }
+
+ public static int InitBuiltinRouting(ref Config config, bool blImportAdvancedRules = false)
+ {
+ var items = LazyConfig.Instance.RoutingItems();
+ if (blImportAdvancedRules || items.Count <= 0)
+ {
+ var maxSort = items.Count;
+ //Bypass the mainland
+ var item2 = new RoutingItem()
+ {
+ remarks = "绕过大陆(Whitelist)",
+ url = string.Empty,
+ sort = maxSort + 1,
+ };
+ AddBatchRoutingRules(ref item2, Utils.GetEmbedText(Global.CustomRoutingFileName + "white"));
+
+ //Blacklist
+ var item3 = new RoutingItem()
+ {
+ remarks = "黑名单(Blacklist)",
+ url = string.Empty,
+ sort = maxSort + 2,
+ };
+ AddBatchRoutingRules(ref item3, Utils.GetEmbedText(Global.CustomRoutingFileName + "black"));
+
+ //Global
+ var item1 = new RoutingItem()
+ {
+ remarks = "全局(Global)",
+ url = string.Empty,
+ sort = maxSort + 3,
+ };
+ AddBatchRoutingRules(ref item1, Utils.GetEmbedText(Global.CustomRoutingFileName + "global"));
+
+ if (!blImportAdvancedRules)
+ {
+ SetDefaultRouting(ref config, item2);
+ }
+ }
+
+ if (GetLockedRoutingItem(ref config) == null)
+ {
+ var item1 = new RoutingItem()
+ {
+ remarks = "locked",
+ url = string.Empty,
+ locked = true,
+ };
+ AddBatchRoutingRules(ref item1, Utils.GetEmbedText(Global.CustomRoutingFileName + "locked"));
+ }
+ return 0;
+ }
+
+ public static RoutingItem GetLockedRoutingItem(ref Config config)
+ {
+ return SqliteHelper.Instance.Table().FirstOrDefault(it => it.locked == true);
+ }
+
+ public static void RemoveRoutingItem(RoutingItem routingItem)
+ {
+ SqliteHelper.Instance.Delete(routingItem);
+ }
+
+ #endregion Routing
+
+ #region DNS
+
+ public static int InitBuiltinDNS(Config config)
+ {
+ var items = LazyConfig.Instance.DNSItems();
+ if (items.Count <= 0)
+ {
+ var item = new DNSItem()
+ {
+ remarks = "V2ray",
+ coreType = ECoreType.Xray,
+ };
+ SaveDNSItems(config, item);
+
+ var item2 = new DNSItem()
+ {
+ remarks = "sing-box",
+ coreType = ECoreType.sing_box,
+ };
+ SaveDNSItems(config, item2);
+ }
+
+ return 0;
+ }
+
+ public static int SaveDNSItems(Config config, DNSItem item)
+ {
+ if (Utils.IsNullOrEmpty(item.id))
+ {
+ item.id = Utils.GetGUID(false);
+ }
+
+ if (SqliteHelper.Instance.Replace(item) > 0)
+ {
+ return 0;
+ }
+ else
+ {
+ return -1;
+ }
+ }
+
+ #endregion DNS
}
\ No newline at end of file
diff --git a/v2rayN/v2rayN/Handler/CoreConfigHandler.cs b/v2rayN/v2rayN/Handler/CoreConfigHandler.cs
index c0dc712e..01b91108 100644
--- a/v2rayN/v2rayN/Handler/CoreConfigHandler.cs
+++ b/v2rayN/v2rayN/Handler/CoreConfigHandler.cs
@@ -2,155 +2,154 @@
using v2rayN.Mode;
using v2rayN.Resx;
-namespace v2rayN.Handler
+namespace v2rayN.Handler;
+
+///
+/// Core configuration file processing class
+///
+internal class CoreConfigHandler
{
- ///
- /// Core configuration file processing class
- ///
- internal class CoreConfigHandler
+ public static int GenerateClientConfig(ProfileItem node, string? fileName, out string msg, out string content)
{
- public static int GenerateClientConfig(ProfileItem node, string? fileName, out string msg, out string content)
+ content = string.Empty;
+ try
{
- content = string.Empty;
- try
+ if (node == null)
{
- if (node == null)
+ msg = ResUI.CheckServerSettings;
+ return -1;
+ }
+ var config = LazyConfig.Instance.GetConfig();
+
+ msg = ResUI.InitialConfiguration;
+ if (node.configType == EConfigType.Custom)
+ {
+ return GenerateClientCustomConfig(node, fileName, out msg);
+ }
+ else if (config.tunModeItem.enableTun || LazyConfig.Instance.GetCoreType(node, node.configType) == ECoreType.sing_box)
+ {
+ var configGenSingbox = new CoreConfigSingbox(config);
+ if (configGenSingbox.GenerateClientConfigContent(node, out SingboxConfig? singboxConfig, out msg) != 0)
{
- msg = ResUI.CheckServerSettings;
return -1;
}
- var config = LazyConfig.Instance.GetConfig();
-
- msg = ResUI.InitialConfiguration;
- if (node.configType == EConfigType.Custom)
+ if (Utils.IsNullOrEmpty(fileName))
{
- return GenerateClientCustomConfig(node, fileName, out msg);
- }
- else if (config.tunModeItem.enableTun || 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 = Utils.ToJson(singboxConfig);
- }
- else
- {
- Utils.ToJsonFile(singboxConfig, fileName, false);
- }
+ content = Utils.ToJson(singboxConfig);
}
else
{
- var coreConfigV2ray = new CoreConfigV2ray(config);
- if (coreConfigV2ray.GenerateClientConfigContent(node, out V2rayConfig? v2rayConfig, out msg) != 0)
- {
- return -1;
- }
- if (Utils.IsNullOrEmpty(fileName))
- {
- content = Utils.ToJson(v2rayConfig);
- }
- else
- {
- Utils.ToJsonFile(v2rayConfig, fileName, false);
- }
+ Utils.ToJsonFile(singboxConfig, fileName, false);
}
}
- catch (Exception ex)
+ else
+ {
+ var coreConfigV2ray = new CoreConfigV2ray(config);
+ if (coreConfigV2ray.GenerateClientConfigContent(node, out V2rayConfig? v2rayConfig, out msg) != 0)
+ {
+ return -1;
+ }
+ if (Utils.IsNullOrEmpty(fileName))
+ {
+ content = Utils.ToJson(v2rayConfig);
+ }
+ else
+ {
+ Utils.ToJsonFile(v2rayConfig, fileName, false);
+ }
+ }
+ }
+ catch (Exception ex)
+ {
+ Utils.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.Delete(fileName);
+ }
+
+ string addressFileName = node.address;
+ if (!File.Exists(addressFileName))
+ {
+ addressFileName = Utils.GetConfigPath(addressFileName);
+ }
+ if (!File.Exists(addressFileName))
{
- Utils.SaveLog("GenerateClientConfig", ex);
msg = ResUI.FailedGenDefaultConfiguration;
return -1;
}
- return 0;
- }
+ File.Copy(addressFileName, fileName);
- private static int GenerateClientCustomConfig(ProfileItem node, string? fileName, out string msg)
- {
- try
+ //check again
+ if (!File.Exists(fileName))
{
- if (node == null || fileName is null)
- {
- msg = ResUI.CheckServerSettings;
- return -1;
- }
-
- if (File.Exists(fileName))
- {
- 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);
-
- //check again
- if (!File.Exists(fileName))
- {
- msg = ResUI.FailedGenDefaultConfiguration;
- return -1;
- }
-
- //overwrite port
- if (node.preSocksPort <= 0)
- {
- var fileContent = File.ReadAllLines(fileName).ToList();
- var coreType = LazyConfig.Instance.GetCoreType(node, node.configType);
- switch (coreType)
- {
- case ECoreType.v2fly:
- case ECoreType.SagerNet:
- case ECoreType.Xray:
- case ECoreType.v2fly_v5:
- break;
-
- case ECoreType.clash:
- case ECoreType.clash_meta:
- //remove the original
- var indexPort = fileContent.FindIndex(t => t.Contains("port:"));
- if (indexPort >= 0)
- {
- fileContent.RemoveAt(indexPort);
- }
- indexPort = fileContent.FindIndex(t => t.Contains("socks-port:"));
- if (indexPort >= 0)
- {
- fileContent.RemoveAt(indexPort);
- }
-
- fileContent.Add($"port: {LazyConfig.Instance.GetLocalPort(Global.InboundHttp)}");
- fileContent.Add($"socks-port: {LazyConfig.Instance.GetLocalPort(Global.InboundSocks)}");
- break;
- }
- File.WriteAllLines(fileName, fileContent);
- }
-
- msg = string.Format(ResUI.SuccessfulConfiguration, "");
- }
- catch (Exception ex)
- {
- Utils.SaveLog("GenerateClientCustomConfig", ex);
msg = ResUI.FailedGenDefaultConfiguration;
return -1;
}
- return 0;
- }
- public static string GenerateClientSpeedtestConfigString(Config config, List selecteds, out string msg)
- {
- var coreConfigV2ray = new CoreConfigV2ray(config);
- return coreConfigV2ray.GenerateClientSpeedtestConfigString(selecteds, out msg);
+ //overwrite port
+ if (node.preSocksPort <= 0)
+ {
+ var fileContent = File.ReadAllLines(fileName).ToList();
+ var coreType = LazyConfig.Instance.GetCoreType(node, node.configType);
+ switch (coreType)
+ {
+ case ECoreType.v2fly:
+ case ECoreType.SagerNet:
+ case ECoreType.Xray:
+ case ECoreType.v2fly_v5:
+ break;
+
+ case ECoreType.clash:
+ case ECoreType.clash_meta:
+ //remove the original
+ var indexPort = fileContent.FindIndex(t => t.Contains("port:"));
+ if (indexPort >= 0)
+ {
+ fileContent.RemoveAt(indexPort);
+ }
+ indexPort = fileContent.FindIndex(t => t.Contains("socks-port:"));
+ if (indexPort >= 0)
+ {
+ fileContent.RemoveAt(indexPort);
+ }
+
+ fileContent.Add($"port: {LazyConfig.Instance.GetLocalPort(Global.InboundHttp)}");
+ fileContent.Add($"socks-port: {LazyConfig.Instance.GetLocalPort(Global.InboundSocks)}");
+ break;
+ }
+ File.WriteAllLines(fileName, fileContent);
+ }
+
+ msg = string.Format(ResUI.SuccessfulConfiguration, "");
}
+ catch (Exception ex)
+ {
+ Utils.SaveLog("GenerateClientCustomConfig", ex);
+ msg = ResUI.FailedGenDefaultConfiguration;
+ return -1;
+ }
+ return 0;
+ }
+
+ public static string GenerateClientSpeedtestConfigString(Config config, List selecteds, out string msg)
+ {
+ var coreConfigV2ray = new CoreConfigV2ray(config);
+ return coreConfigV2ray.GenerateClientSpeedtestConfigString(selecteds, out msg);
}
}
\ No newline at end of file
diff --git a/v2rayN/v2rayN/Handler/CoreConfigSingbox.cs b/v2rayN/v2rayN/Handler/CoreConfigSingbox.cs
index 7d64b7b8..87b58721 100644
--- a/v2rayN/v2rayN/Handler/CoreConfigSingbox.cs
+++ b/v2rayN/v2rayN/Handler/CoreConfigSingbox.cs
@@ -2,739 +2,738 @@
using v2rayN.Mode;
using v2rayN.Resx;
-namespace v2rayN.Handler
+namespace v2rayN.Handler;
+
+internal class CoreConfigSingbox
{
- internal class CoreConfigSingbox
+ private string SampleClient = Global.SingboxSampleClient;
+ private Config _config;
+
+ public CoreConfigSingbox(Config config)
{
- private string SampleClient = Global.SingboxSampleClient;
- private Config _config;
+ _config = config;
+ }
- public CoreConfigSingbox(Config config)
+ public int GenerateClientConfigContent(ProfileItem node, out SingboxConfig? singboxConfig, out string msg)
+ {
+ singboxConfig = null;
+ try
{
- _config = config;
- }
-
- public int GenerateClientConfigContent(ProfileItem node, out SingboxConfig? singboxConfig, out string msg)
- {
- singboxConfig = null;
- try
+ if (node == null
+ || node.port <= 0)
{
- if (node == null
- || node.port <= 0)
- {
- msg = ResUI.CheckServerSettings;
- return -1;
- }
-
- msg = ResUI.InitialConfiguration;
-
- string result = Utils.GetEmbedText(SampleClient);
- if (Utils.IsNullOrEmpty(result))
- {
- msg = ResUI.FailedGetDefaultConfiguration;
- return -1;
- }
-
- singboxConfig = Utils.FromJson(result);
- if (singboxConfig == null)
- {
- msg = ResUI.FailedGenDefaultConfiguration;
- return -1;
- }
-
- log(singboxConfig);
-
- inbound(singboxConfig);
-
- outbound(node, singboxConfig);
-
- routing(singboxConfig);
-
- dns(node, singboxConfig);
-
- statistic(singboxConfig);
-
- msg = string.Format(ResUI.SuccessfulConfiguration, "");
+ msg = ResUI.CheckServerSettings;
+ return -1;
}
- catch (Exception ex)
+
+ msg = ResUI.InitialConfiguration;
+
+ string result = Utils.GetEmbedText(SampleClient);
+ if (Utils.IsNullOrEmpty(result))
+ {
+ msg = ResUI.FailedGetDefaultConfiguration;
+ return -1;
+ }
+
+ singboxConfig = Utils.FromJson(result);
+ if (singboxConfig == null)
{
- Utils.SaveLog("GenerateClientConfig4Singbox", ex);
msg = ResUI.FailedGenDefaultConfiguration;
return -1;
}
- return 0;
+
+ log(singboxConfig);
+
+ inbound(singboxConfig);
+
+ outbound(node, singboxConfig);
+
+ routing(singboxConfig);
+
+ dns(node, singboxConfig);
+
+ statistic(singboxConfig);
+
+ msg = string.Format(ResUI.SuccessfulConfiguration, "");
}
-
- private int log(SingboxConfig singboxConfig)
+ catch (Exception ex)
{
- try
- {
- switch (_config.coreBasicItem.loglevel)
- {
- case "debug":
- case "info":
- case "error":
- singboxConfig.log.level = _config.coreBasicItem.loglevel;
- break;
-
- case "warning":
- singboxConfig.log.level = "warn";
- break;
-
- default:
- break;
- }
- if (_config.coreBasicItem.loglevel == "none")
- {
- singboxConfig.log.disabled = true;
- }
- if (_config.coreBasicItem.logEnabled)
- {
- var dtNow = DateTime.Now;
- singboxConfig.log.output = Utils.GetLogPath($"sbox_{dtNow:yyyy-MM-dd}.txt");
- }
- }
- catch (Exception ex)
- {
- Utils.SaveLog(ex.Message, ex);
- }
- return 0;
+ Utils.SaveLog("GenerateClientConfig4Singbox", ex);
+ msg = ResUI.FailedGenDefaultConfiguration;
+ return -1;
}
+ return 0;
+ }
- #region inbound private
-
- private int inbound(SingboxConfig singboxConfig)
+ private int log(SingboxConfig singboxConfig)
+ {
+ try
{
- try
+ switch (_config.coreBasicItem.loglevel)
{
- singboxConfig.inbounds.Clear();
+ case "debug":
+ case "info":
+ case "error":
+ singboxConfig.log.level = _config.coreBasicItem.loglevel;
+ break;
- if (!_config.tunModeItem.enableTun || (_config.tunModeItem.enableTun && _config.tunModeItem.enableExInbound))
- {
- var inbound = new Inbound4Sbox()
- {
- type = Global.InboundSocks,
- tag = Global.InboundSocks,
- listen = Global.Loopback,
- };
- singboxConfig.inbounds.Add(inbound);
+ case "warning":
+ singboxConfig.log.level = "warn";
+ break;
- inbound.listen_port = LazyConfig.Instance.GetLocalPort(Global.InboundSocks);
- inbound.sniff = _config.inbound[0].sniffingEnabled;
- inbound.sniff_override_destination = _config.inbound[0].routeOnly ? false : _config.inbound[0].sniffingEnabled;
- inbound.domain_strategy = Utils.IsNullOrEmpty(_config.routingBasicItem.domainStrategy4Singbox) ? null : _config.routingBasicItem.domainStrategy4Singbox;
-
- if (_config.routingBasicItem.enableRoutingAdvanced)
- {
- var routing = ConfigHandler.GetDefaultRouting(ref _config);
- if (!Utils.IsNullOrEmpty(routing.domainStrategy4Singbox))
- {
- inbound.domain_strategy = routing.domainStrategy4Singbox;
- }
- }
-
- //http
- var inbound2 = GetInbound(inbound, Global.InboundHttp, 1, false);
- singboxConfig.inbounds.Add(inbound2);
-
- if (_config.inbound[0].allowLANConn)
- {
- if (_config.inbound[0].newPort4LAN)
- {
- var inbound3 = GetInbound(inbound, Global.InboundSocks2, 2, true);
- inbound3.listen = "::";
- singboxConfig.inbounds.Add(inbound3);
-
- var inbound4 = GetInbound(inbound, Global.InboundHttp2, 3, false);
- inbound4.listen = "::";
- singboxConfig.inbounds.Add(inbound4);
-
- //auth
- if (!Utils.IsNullOrEmpty(_config.inbound[0].user) && !Utils.IsNullOrEmpty(_config.inbound[0].pass))
- {
- inbound3.users = new() { new() { username = _config.inbound[0].user, password = _config.inbound[0].pass } };
- inbound4.users = new() { new() { username = _config.inbound[0].user, password = _config.inbound[0].pass } };
- }
- }
- else
- {
- inbound.listen = "::";
- inbound2.listen = "::";
- }
- }
- }
-
- if (_config.tunModeItem.enableTun)
- {
- if (_config.tunModeItem.mtu <= 0)
- {
- _config.tunModeItem.mtu = Convert.ToInt32(Global.TunMtus[0]);
- }
- if (Utils.IsNullOrEmpty(_config.tunModeItem.stack))
- {
- _config.tunModeItem.stack = Global.TunStacks[0];
- }
-
- var tunInbound = Utils.FromJson(Utils.GetEmbedText(Global.TunSingboxInboundFileName));
- tunInbound.mtu = _config.tunModeItem.mtu;
- tunInbound.strict_route = _config.tunModeItem.strictRoute;
- tunInbound.stack = _config.tunModeItem.stack;
-
- singboxConfig.inbounds.Add(tunInbound);
- }
+ default:
+ break;
}
- catch (Exception ex)
+ if (_config.coreBasicItem.loglevel == "none")
{
- Utils.SaveLog(ex.Message, ex);
+ singboxConfig.log.disabled = true;
+ }
+ if (_config.coreBasicItem.logEnabled)
+ {
+ var dtNow = DateTime.Now;
+ singboxConfig.log.output = Utils.GetLogPath($"sbox_{dtNow:yyyy-MM-dd}.txt");
}
- return 0;
}
-
- private Inbound4Sbox? GetInbound(Inbound4Sbox inItem, string tag, int offset, bool bSocks)
+ catch (Exception ex)
{
- var inbound = Utils.DeepCopy(inItem);
- inbound.tag = tag;
- inbound.listen_port = inItem.listen_port + offset;
- inbound.type = bSocks ? Global.InboundSocks : Global.InboundHttp;
- return inbound;
+ Utils.SaveLog(ex.Message, ex);
}
+ return 0;
+ }
- #endregion inbound private
+ #region inbound private
- #region outbound private
-
- private int outbound(ProfileItem node, SingboxConfig singboxConfig)
+ private int inbound(SingboxConfig singboxConfig)
+ {
+ try
{
- try
+ singboxConfig.inbounds.Clear();
+
+ if (!_config.tunModeItem.enableTun || (_config.tunModeItem.enableTun && _config.tunModeItem.enableExInbound))
{
- if (_config.tunModeItem.enableTun)
+ var inbound = new Inbound4Sbox()
{
- singboxConfig.outbounds.Add(new()
- {
- type = "dns",
- tag = "dns_out"
- });
- }
+ type = Global.InboundSocks,
+ tag = Global.InboundSocks,
+ listen = Global.Loopback,
+ };
+ singboxConfig.inbounds.Add(inbound);
- var outbound = singboxConfig.outbounds[0];
- outbound.server = node.address;
- outbound.server_port = node.port;
-
- if (node.configType == EConfigType.VMess)
- {
- outbound.type = Global.vmessProtocolLite;
-
- outbound.uuid = node.id;
- outbound.alter_id = node.alterId;
- if (Global.vmessSecuritys.Contains(node.security))
- {
- outbound.security = node.security;
- }
- else
- {
- outbound.security = Global.DefaultSecurity;
- }
-
- outboundMux(node, outbound);
- }
- else if (node.configType == EConfigType.Shadowsocks)
- {
- outbound.type = Global.ssProtocolLite;
-
- outbound.method = LazyConfig.Instance.GetShadowsocksSecuritys(node).Contains(node.security) ? node.security : "none";
- outbound.password = node.id;
-
- outboundMux(node, outbound);
- }
- else if (node.configType == EConfigType.Socks)
- {
- outbound.type = Global.socksProtocolLite;
-
- outbound.version = "5";
- if (!Utils.IsNullOrEmpty(node.security)
- && !Utils.IsNullOrEmpty(node.id))
- {
- outbound.username = node.security;
- outbound.password = node.id;
- }
- }
- else if (node.configType == EConfigType.VLESS)
- {
- outbound.type = Global.vlessProtocolLite;
-
- outbound.uuid = node.id;
-
- outbound.packet_encoding = "xudp";
-
- if (Utils.IsNullOrEmpty(node.flow))
- {
- outboundMux(node, outbound);
- }
- else
- {
- outbound.flow = node.flow;
- }
- }
- else if (node.configType == EConfigType.Trojan)
- {
- outbound.type = Global.trojanProtocolLite;
-
- outbound.password = node.id;
-
- outboundMux(node, outbound);
- }
-
- outboundTls(node, outbound);
-
- outboundTransport(node, outbound);
- }
- catch (Exception ex)
- {
- Utils.SaveLog(ex.Message, ex);
- }
- return 0;
- }
-
- private int outboundMux(ProfileItem node, Outbound4Sbox outbound)
- {
- try
- {
- //if (_config.coreBasicItem.muxEnabled)
- //{
- // var mux = new Multiplex4Sbox()
- // {
- // enabled = true,
- // protocol = _config.mux4Sbox.protocol,
- // max_connections = _config.mux4Sbox.max_connections,
- // min_streams = _config.mux4Sbox.min_streams,
- // max_streams = _config.mux4Sbox.max_streams,
- // padding = _config.mux4Sbox.padding
- // };
- // outbound.multiplex = mux;
- //}
- }
- catch (Exception ex)
- {
- Utils.SaveLog(ex.Message, ex);
- }
- return 0;
- }
-
- private int outboundTls(ProfileItem node, Outbound4Sbox outbound)
- {
- try
- {
- if (node.streamSecurity == Global.StreamSecurityReality || node.streamSecurity == Global.StreamSecurity)
- {
- var server_name = string.Empty;
- if (!string.IsNullOrWhiteSpace(node.sni))
- {
- server_name = node.sni;
- }
- else if (!string.IsNullOrWhiteSpace(node.requestHost))
- {
- server_name = Utils.String2List(node.requestHost)[0];
- }
- var tls = new Tls4Sbox()
- {
- enabled = true,
- server_name = server_name,
- insecure = Utils.ToBool(node.allowInsecure.IsNullOrEmpty() ? _config.coreBasicItem.defAllowInsecure.ToString().ToLower() : node.allowInsecure),
- alpn = node.GetAlpn(),
- };
- if (!Utils.IsNullOrEmpty(node.fingerprint))
- {
- tls.utls = new Utls4Sbox()
- {
- enabled = true,
- fingerprint = node.fingerprint.IsNullOrEmpty() ? _config.coreBasicItem.defFingerprint : node.fingerprint
- };
- }
- if (node.streamSecurity == Global.StreamSecurityReality)
- {
- tls.reality = new Reality4Sbox()
- {
- enabled = true,
- public_key = node.publicKey,
- short_id = node.shortId
- };
- tls.insecure = false;
- }
- outbound.tls = tls;
- }
- }
- catch (Exception ex)
- {
- Utils.SaveLog(ex.Message, ex);
- }
- return 0;
- }
-
- private int outboundTransport(ProfileItem node, Outbound4Sbox outbound)
- {
- try
- {
- var transport = new Transport4Sbox();
-
- switch (node.GetNetwork())
- {
- case "h2":
- transport.type = "http";
- transport.host = Utils.IsNullOrEmpty(node.requestHost) ? null : Utils.String2List(node.requestHost);
- transport.path = Utils.IsNullOrEmpty(node.path) ? null : node.path;
- break;
-
- case "ws":
- transport.type = "ws";
- transport.path = Utils.IsNullOrEmpty(node.path) ? null : node.path;
- if (!Utils.IsNullOrEmpty(node.requestHost))
- {
- transport.headers = new()
- {
- Host = node.requestHost
- };
- }
- break;
-
- case "quic":
- transport.type = "quic";
- break;
-
- case "grpc":
- transport.type = "grpc";
- transport.service_name = node.path;
- transport.idle_timeout = _config.grpcItem.idle_timeout.ToString("##s");
- transport.ping_timeout = _config.grpcItem.health_check_timeout.ToString("##s");
- transport.permit_without_stream = _config.grpcItem.permit_without_stream;
- break;
-
- default:
- transport = null;
- break;
- }
-
- outbound.transport = transport;
- }
- catch (Exception ex)
- {
- Utils.SaveLog(ex.Message, ex);
- }
- return 0;
- }
-
- #endregion outbound private
-
- #region routing rule private
-
- private int routing(SingboxConfig singboxConfig)
- {
- try
- {
- if (_config.tunModeItem.enableTun)
- {
- singboxConfig.route.auto_detect_interface = true;
-
- var tunRules = Utils.FromJson>(Utils.GetEmbedText(Global.TunSingboxRulesFileName));
- singboxConfig.route.rules.AddRange(tunRules);
-
- routingDirectExe(out List lstDnsExe, out List lstDirectExe);
- singboxConfig.route.rules.Add(new()
- {
- port = new() { 53 },
- outbound = "dns_out",
- process_name = lstDnsExe
- });
-
- singboxConfig.route.rules.Add(new()
- {
- outbound = "direct",
- process_name = lstDirectExe
- });
- }
+ inbound.listen_port = LazyConfig.Instance.GetLocalPort(Global.InboundSocks);
+ inbound.sniff = _config.inbound[0].sniffingEnabled;
+ inbound.sniff_override_destination = _config.inbound[0].routeOnly ? false : _config.inbound[0].sniffingEnabled;
+ inbound.domain_strategy = Utils.IsNullOrEmpty(_config.routingBasicItem.domainStrategy4Singbox) ? null : _config.routingBasicItem.domainStrategy4Singbox;
if (_config.routingBasicItem.enableRoutingAdvanced)
{
var routing = ConfigHandler.GetDefaultRouting(ref _config);
- if (routing != null)
+ if (!Utils.IsNullOrEmpty(routing.domainStrategy4Singbox))
{
- var rules = Utils.FromJson>(routing.ruleSet);
- foreach (var item in rules!)
+ inbound.domain_strategy = routing.domainStrategy4Singbox;
+ }
+ }
+
+ //http
+ var inbound2 = GetInbound(inbound, Global.InboundHttp, 1, false);
+ singboxConfig.inbounds.Add(inbound2);
+
+ if (_config.inbound[0].allowLANConn)
+ {
+ if (_config.inbound[0].newPort4LAN)
+ {
+ var inbound3 = GetInbound(inbound, Global.InboundSocks2, 2, true);
+ inbound3.listen = "::";
+ singboxConfig.inbounds.Add(inbound3);
+
+ var inbound4 = GetInbound(inbound, Global.InboundHttp2, 3, false);
+ inbound4.listen = "::";
+ singboxConfig.inbounds.Add(inbound4);
+
+ //auth
+ if (!Utils.IsNullOrEmpty(_config.inbound[0].user) && !Utils.IsNullOrEmpty(_config.inbound[0].pass))
{
- if (item.enabled)
- {
- routingUserRule(item, singboxConfig.route.rules);
- }
+ inbound3.users = new() { new() { username = _config.inbound[0].user, password = _config.inbound[0].pass } };
+ inbound4.users = new() { new() { username = _config.inbound[0].user, password = _config.inbound[0].pass } };
}
}
+ else
+ {
+ inbound.listen = "::";
+ inbound2.listen = "::";
+ }
+ }
+ }
+
+ if (_config.tunModeItem.enableTun)
+ {
+ if (_config.tunModeItem.mtu <= 0)
+ {
+ _config.tunModeItem.mtu = Convert.ToInt32(Global.TunMtus[0]);
+ }
+ if (Utils.IsNullOrEmpty(_config.tunModeItem.stack))
+ {
+ _config.tunModeItem.stack = Global.TunStacks[0];
+ }
+
+ var tunInbound = Utils.FromJson(Utils.GetEmbedText(Global.TunSingboxInboundFileName));
+ tunInbound.mtu = _config.tunModeItem.mtu;
+ tunInbound.strict_route = _config.tunModeItem.strictRoute;
+ tunInbound.stack = _config.tunModeItem.stack;
+
+ singboxConfig.inbounds.Add(tunInbound);
+ }
+ }
+ catch (Exception ex)
+ {
+ Utils.SaveLog(ex.Message, ex);
+ }
+ return 0;
+ }
+
+ private Inbound4Sbox? GetInbound(Inbound4Sbox inItem, string tag, int offset, bool bSocks)
+ {
+ var inbound = Utils.DeepCopy(inItem);
+ inbound.tag = tag;
+ inbound.listen_port = inItem.listen_port + offset;
+ inbound.type = bSocks ? Global.InboundSocks : Global.InboundHttp;
+ return inbound;
+ }
+
+ #endregion inbound private
+
+ #region outbound private
+
+ private int outbound(ProfileItem node, SingboxConfig singboxConfig)
+ {
+ try
+ {
+ if (_config.tunModeItem.enableTun)
+ {
+ singboxConfig.outbounds.Add(new()
+ {
+ type = "dns",
+ tag = "dns_out"
+ });
+ }
+
+ var outbound = singboxConfig.outbounds[0];
+ outbound.server = node.address;
+ outbound.server_port = node.port;
+
+ if (node.configType == EConfigType.VMess)
+ {
+ outbound.type = Global.vmessProtocolLite;
+
+ outbound.uuid = node.id;
+ outbound.alter_id = node.alterId;
+ if (Global.vmessSecuritys.Contains(node.security))
+ {
+ outbound.security = node.security;
}
else
{
- var lockedItem = ConfigHandler.GetLockedRoutingItem(ref _config);
- if (lockedItem != null)
+ outbound.security = Global.DefaultSecurity;
+ }
+
+ outboundMux(node, outbound);
+ }
+ else if (node.configType == EConfigType.Shadowsocks)
+ {
+ outbound.type = Global.ssProtocolLite;
+
+ outbound.method = LazyConfig.Instance.GetShadowsocksSecuritys(node).Contains(node.security) ? node.security : "none";
+ outbound.password = node.id;
+
+ outboundMux(node, outbound);
+ }
+ else if (node.configType == EConfigType.Socks)
+ {
+ outbound.type = Global.socksProtocolLite;
+
+ outbound.version = "5";
+ if (!Utils.IsNullOrEmpty(node.security)
+ && !Utils.IsNullOrEmpty(node.id))
+ {
+ outbound.username = node.security;
+ outbound.password = node.id;
+ }
+ }
+ else if (node.configType == EConfigType.VLESS)
+ {
+ outbound.type = Global.vlessProtocolLite;
+
+ outbound.uuid = node.id;
+
+ outbound.packet_encoding = "xudp";
+
+ if (Utils.IsNullOrEmpty(node.flow))
+ {
+ outboundMux(node, outbound);
+ }
+ else
+ {
+ outbound.flow = node.flow;
+ }
+ }
+ else if (node.configType == EConfigType.Trojan)
+ {
+ outbound.type = Global.trojanProtocolLite;
+
+ outbound.password = node.id;
+
+ outboundMux(node, outbound);
+ }
+
+ outboundTls(node, outbound);
+
+ outboundTransport(node, outbound);
+ }
+ catch (Exception ex)
+ {
+ Utils.SaveLog(ex.Message, ex);
+ }
+ return 0;
+ }
+
+ private int outboundMux(ProfileItem node, Outbound4Sbox outbound)
+ {
+ try
+ {
+ //if (_config.coreBasicItem.muxEnabled)
+ //{
+ // var mux = new Multiplex4Sbox()
+ // {
+ // enabled = true,
+ // protocol = _config.mux4Sbox.protocol,
+ // max_connections = _config.mux4Sbox.max_connections,
+ // min_streams = _config.mux4Sbox.min_streams,
+ // max_streams = _config.mux4Sbox.max_streams,
+ // padding = _config.mux4Sbox.padding
+ // };
+ // outbound.multiplex = mux;
+ //}
+ }
+ catch (Exception ex)
+ {
+ Utils.SaveLog(ex.Message, ex);
+ }
+ return 0;
+ }
+
+ private int outboundTls(ProfileItem node, Outbound4Sbox outbound)
+ {
+ try
+ {
+ if (node.streamSecurity == Global.StreamSecurityReality || node.streamSecurity == Global.StreamSecurity)
+ {
+ var server_name = string.Empty;
+ if (!string.IsNullOrWhiteSpace(node.sni))
+ {
+ server_name = node.sni;
+ }
+ else if (!string.IsNullOrWhiteSpace(node.requestHost))
+ {
+ server_name = Utils.String2List(node.requestHost)[0];
+ }
+ var tls = new Tls4Sbox()
+ {
+ enabled = true,
+ server_name = server_name,
+ insecure = Utils.ToBool(node.allowInsecure.IsNullOrEmpty() ? _config.coreBasicItem.defAllowInsecure.ToString().ToLower() : node.allowInsecure),
+ alpn = node.GetAlpn(),
+ };
+ if (!Utils.IsNullOrEmpty(node.fingerprint))
+ {
+ tls.utls = new Utls4Sbox()
{
- var rules = Utils.FromJson>(lockedItem.ruleSet);
- foreach (var item in rules!)
+ enabled = true,
+ fingerprint = node.fingerprint.IsNullOrEmpty() ? _config.coreBasicItem.defFingerprint : node.fingerprint
+ };
+ }
+ if (node.streamSecurity == Global.StreamSecurityReality)
+ {
+ tls.reality = new Reality4Sbox()
+ {
+ enabled = true,
+ public_key = node.publicKey,
+ short_id = node.shortId
+ };
+ tls.insecure = false;
+ }
+ outbound.tls = tls;
+ }
+ }
+ catch (Exception ex)
+ {
+ Utils.SaveLog(ex.Message, ex);
+ }
+ return 0;
+ }
+
+ private int outboundTransport(ProfileItem node, Outbound4Sbox outbound)
+ {
+ try
+ {
+ var transport = new Transport4Sbox();
+
+ switch (node.GetNetwork())
+ {
+ case "h2":
+ transport.type = "http";
+ transport.host = Utils.IsNullOrEmpty(node.requestHost) ? null : Utils.String2List(node.requestHost);
+ transport.path = Utils.IsNullOrEmpty(node.path) ? null : node.path;
+ break;
+
+ case "ws":
+ transport.type = "ws";
+ transport.path = Utils.IsNullOrEmpty(node.path) ? null : node.path;
+ if (!Utils.IsNullOrEmpty(node.requestHost))
+ {
+ transport.headers = new()
+ {
+ Host = node.requestHost
+ };
+ }
+ break;
+
+ case "quic":
+ transport.type = "quic";
+ break;
+
+ case "grpc":
+ transport.type = "grpc";
+ transport.service_name = node.path;
+ transport.idle_timeout = _config.grpcItem.idle_timeout.ToString("##s");
+ transport.ping_timeout = _config.grpcItem.health_check_timeout.ToString("##s");
+ transport.permit_without_stream = _config.grpcItem.permit_without_stream;
+ break;
+
+ default:
+ transport = null;
+ break;
+ }
+
+ outbound.transport = transport;
+ }
+ catch (Exception ex)
+ {
+ Utils.SaveLog(ex.Message, ex);
+ }
+ return 0;
+ }
+
+ #endregion outbound private
+
+ #region routing rule private
+
+ private int routing(SingboxConfig singboxConfig)
+ {
+ try
+ {
+ if (_config.tunModeItem.enableTun)
+ {
+ singboxConfig.route.auto_detect_interface = true;
+
+ var tunRules = Utils.FromJson>(Utils.GetEmbedText(Global.TunSingboxRulesFileName));
+ singboxConfig.route.rules.AddRange(tunRules);
+
+ routingDirectExe(out List lstDnsExe, out List lstDirectExe);
+ singboxConfig.route.rules.Add(new()
+ {
+ port = new() { 53 },
+ outbound = "dns_out",
+ process_name = lstDnsExe
+ });
+
+ singboxConfig.route.rules.Add(new()
+ {
+ outbound = "direct",
+ process_name = lstDirectExe
+ });
+ }
+
+ if (_config.routingBasicItem.enableRoutingAdvanced)
+ {
+ var routing = ConfigHandler.GetDefaultRouting(ref _config);
+ if (routing != null)
+ {
+ var rules = Utils.FromJson>(routing.ruleSet);
+ foreach (var item in rules!)
+ {
+ if (item.enabled)
{
routingUserRule(item, singboxConfig.route.rules);
}
}
}
}
- catch (Exception ex)
- {
- Utils.SaveLog(ex.Message, ex);
- }
- return 0;
- }
-
- private void routingDirectExe(out List lstDnsExe, out List lstDirectExe)
- {
- lstDnsExe = new();
- lstDirectExe = new();
- var coreInfos = LazyConfig.Instance.GetCoreInfos();
- foreach (var it in coreInfos)
- {
- if (it.coreType == ECoreType.v2rayN)
- {
- continue;
- }
- foreach (var it2 in it.coreExes)
- {
- if (!lstDnsExe.Contains(it2) && it.coreType != ECoreType.sing_box)
- {
- lstDnsExe.Add($"{it2}.exe");
- }
-
- if (!lstDirectExe.Contains(it2))
- {
- lstDirectExe.Add($"{it2}.exe");
- }
- }
- }
- }
-
- private int routingUserRule(RulesItem item, List rules)
- {
- try
- {
- if (item == null)
- {
- return 0;
- }
-
- var rule = new Rule4Sbox()
- {
- outbound = item.outboundTag,
- };
-
- if (!Utils.IsNullOrEmpty(item.port))
- {
- if (item.port.Contains("-"))
- {
- rule.port_range = new List { item.port.Replace("-", ":") };
- }
- else
- {
- rule.port = new List { Utils.ToInt(item.port) };
- }
- }
- if (item.protocol?.Count > 0)
- {
- rule.protocol = item.protocol;
- }
- if (item.inboundTag?.Count >= 0)
- {
- rule.inbound = item.inboundTag;
- }
- var rule2 = Utils.DeepCopy(rule);
- var rule3 = Utils.DeepCopy(rule);
-
- var hasDomainIp = false;
- if (item.domain?.Count > 0)
- {
- foreach (var it in item.domain)
- {
- parseV2Domain(it, rule);
- }
- rules.Add(rule);
- hasDomainIp = true;
- }
-
- if (item.ip?.Count > 0)
- {
- foreach (var it in item.ip)
- {
- parseV2Address(it, rule2);
- }
- rules.Add(rule2);
- hasDomainIp = true;
- }
-
- if (_config.tunModeItem.enableTun && item.process?.Count > 0)
- {
- rule3.process_name = item.process;
- rules.Add(rule3);
- hasDomainIp = true;
- }
-
- if (!hasDomainIp)
- {
- rules.Add(rule);
- }
- }
- catch (Exception ex)
- {
- Utils.SaveLog(ex.Message, ex);
- }
- return 0;
- }
-
- private void parseV2Domain(string domain, Rule4Sbox rule)
- {
- if (domain.StartsWith("ext:") || domain.StartsWith("ext-domain:"))
- {
- return;
- }
- else if (domain.StartsWith("geosite:"))
- {
- if (rule.geosite is null) { rule.geosite = new(); }
- rule.geosite?.Add(domain.Substring(8));
- }
- else if (domain.StartsWith("regexp:"))
- {
- if (rule.domain_regex is null) { rule.domain_regex = new(); }
- rule.domain_regex?.Add(domain.Replace(Global.RoutingRuleComma, ",").Substring(7));
- }
- else if (domain.StartsWith("domain:"))
- {
- if (rule.domain is null) { rule.domain = new(); }
- if (rule.domain_suffix is null) { rule.domain_suffix = new(); }
- rule.domain?.Add(domain.Substring(7));
- rule.domain_suffix?.Add("." + domain.Substring(7));
- }
- else if (domain.StartsWith("full:"))
- {
- if (rule.domain is null) { rule.domain = new(); }
- rule.domain?.Add(domain.Substring(5));
- }
- else if (domain.StartsWith("keyword:"))
- {
- if (rule.domain_keyword is null) { rule.domain_keyword = new(); }
- rule.domain_keyword?.Add(domain.Substring(8));
- }
else
{
- if (rule.domain_keyword is null) { rule.domain_keyword = new(); }
- rule.domain_keyword?.Add(domain);
- }
- }
-
- private void parseV2Address(string address, Rule4Sbox rule)
- {
- if (address.StartsWith("ext:") || address.StartsWith("ext-ip:"))
- {
- return;
- }
- else if (address.StartsWith("geoip:!"))
- {
- return;
- }
- else if (address.StartsWith("geoip:"))
- {
- if (rule.geoip is null) { rule.geoip = new(); }
- rule.geoip?.Add(address.Substring(6));
- }
- else
- {
- if (rule.ip_cidr is null) { rule.ip_cidr = new(); }
- rule.ip_cidr?.Add(address);
- }
- }
-
- #endregion routing rule private
-
- #region dns private
-
- private int dns(ProfileItem node, SingboxConfig singboxConfig)
- {
- try
- {
- Dns4Sbox? dns4Sbox;
- if (_config.tunModeItem.enableTun)
+ var lockedItem = ConfigHandler.GetLockedRoutingItem(ref _config);
+ if (lockedItem != null)
{
- var item = LazyConfig.Instance.GetDNSItem(ECoreType.sing_box);
- var tunDNS = item?.tunDNS;
- if (string.IsNullOrWhiteSpace(tunDNS))
+ var rules = Utils.FromJson>(lockedItem.ruleSet);
+ foreach (var item in rules!)
{
- tunDNS = Utils.GetEmbedText(Global.TunSingboxDNSFileName);
+ routingUserRule(item, singboxConfig.route.rules);
}
- dns4Sbox = Utils.FromJson(tunDNS);
+ }
+ }
+ }
+ catch (Exception ex)
+ {
+ Utils.SaveLog(ex.Message, ex);
+ }
+ return 0;
+ }
+
+ private void routingDirectExe(out List lstDnsExe, out List lstDirectExe)
+ {
+ lstDnsExe = new();
+ lstDirectExe = new();
+ var coreInfos = LazyConfig.Instance.GetCoreInfos();
+ foreach (var it in coreInfos)
+ {
+ if (it.coreType == ECoreType.v2rayN)
+ {
+ continue;
+ }
+ foreach (var it2 in it.coreExes)
+ {
+ if (!lstDnsExe.Contains(it2) && it.coreType != ECoreType.sing_box)
+ {
+ lstDnsExe.Add($"{it2}.exe");
+ }
+
+ if (!lstDirectExe.Contains(it2))
+ {
+ lstDirectExe.Add($"{it2}.exe");
+ }
+ }
+ }
+ }
+
+ private int routingUserRule(RulesItem item, List rules)
+ {
+ try
+ {
+ if (item == null)
+ {
+ return 0;
+ }
+
+ var rule = new Rule4Sbox()
+ {
+ outbound = item.outboundTag,
+ };
+
+ if (!Utils.IsNullOrEmpty(item.port))
+ {
+ if (item.port.Contains("-"))
+ {
+ rule.port_range = new List { item.port.Replace("-", ":") };
}
else
{
- var item = LazyConfig.Instance.GetDNSItem(ECoreType.sing_box);
- var normalDNS = item?.normalDNS;
- if (string.IsNullOrWhiteSpace(normalDNS))
- {
- normalDNS = "{\"servers\":[{\"address\":\"tcp://8.8.8.8\"}]}";
- }
-
- dns4Sbox = Utils.FromJson(normalDNS);
+ rule.port = new List { Utils.ToInt(item.port) };
}
- if (dns4Sbox is null)
- {
- return 0;
- }
- //Add the dns of the remote server domain
- if (dns4Sbox.rules is null)
- {
- dns4Sbox.rules = new();
- }
- dns4Sbox.servers.Add(new()
- {
- tag = "local_local",
- address = "223.5.5.5",
- detour = "direct"
- });
- dns4Sbox.rules.Add(new()
- {
- server = "local_local",
- outbound = "any"
- });
-
- singboxConfig.dns = dns4Sbox;
}
- catch (Exception ex)
+ if (item.protocol?.Count > 0)
{
- Utils.SaveLog(ex.Message, ex);
+ rule.protocol = item.protocol;
+ }
+ if (item.inboundTag?.Count >= 0)
+ {
+ rule.inbound = item.inboundTag;
+ }
+ var rule2 = Utils.DeepCopy(rule);
+ var rule3 = Utils.DeepCopy(rule);
+
+ var hasDomainIp = false;
+ if (item.domain?.Count > 0)
+ {
+ foreach (var it in item.domain)
+ {
+ parseV2Domain(it, rule);
+ }
+ rules.Add(rule);
+ hasDomainIp = true;
+ }
+
+ if (item.ip?.Count > 0)
+ {
+ foreach (var it in item.ip)
+ {
+ parseV2Address(it, rule2);
+ }
+ rules.Add(rule2);
+ hasDomainIp = true;
+ }
+
+ if (_config.tunModeItem.enableTun && item.process?.Count > 0)
+ {
+ rule3.process_name = item.process;
+ rules.Add(rule3);
+ hasDomainIp = true;
+ }
+
+ if (!hasDomainIp)
+ {
+ rules.Add(rule);
}
- return 0;
}
-
- #endregion dns private
-
- private int statistic(SingboxConfig singboxConfig)
+ catch (Exception ex)
{
- if (_config.guiItem.enableStatistics)
- {
- singboxConfig.experimental = new Experimental4Sbox()
- {
- //v2ray_api = new V2ray_Api4Sbox()
- //{
- // listen = $"{Global.Loopback}:{Global.statePort}",
- // stats = new Stats4Sbox()
- // {
- // enabled = true,
- // }
- //}
- clash_api = new Clash_Api4Sbox()
- {
- external_controller = $"{Global.Loopback}:{Global.statePort}",
- store_selected = true
- }
- };
- }
- return 0;
+ Utils.SaveLog(ex.Message, ex);
+ }
+ return 0;
+ }
+
+ private void parseV2Domain(string domain, Rule4Sbox rule)
+ {
+ if (domain.StartsWith("ext:") || domain.StartsWith("ext-domain:"))
+ {
+ return;
+ }
+ else if (domain.StartsWith("geosite:"))
+ {
+ if (rule.geosite is null) { rule.geosite = new(); }
+ rule.geosite?.Add(domain.Substring(8));
+ }
+ else if (domain.StartsWith("regexp:"))
+ {
+ if (rule.domain_regex is null) { rule.domain_regex = new(); }
+ rule.domain_regex?.Add(domain.Replace(Global.RoutingRuleComma, ",").Substring(7));
+ }
+ else if (domain.StartsWith("domain:"))
+ {
+ if (rule.domain is null) { rule.domain = new(); }
+ if (rule.domain_suffix is null) { rule.domain_suffix = new(); }
+ rule.domain?.Add(domain.Substring(7));
+ rule.domain_suffix?.Add("." + domain.Substring(7));
+ }
+ else if (domain.StartsWith("full:"))
+ {
+ if (rule.domain is null) { rule.domain = new(); }
+ rule.domain?.Add(domain.Substring(5));
+ }
+ else if (domain.StartsWith("keyword:"))
+ {
+ if (rule.domain_keyword is null) { rule.domain_keyword = new(); }
+ rule.domain_keyword?.Add(domain.Substring(8));
+ }
+ else
+ {
+ if (rule.domain_keyword is null) { rule.domain_keyword = new(); }
+ rule.domain_keyword?.Add(domain);
}
}
+
+ private void parseV2Address(string address, Rule4Sbox rule)
+ {
+ if (address.StartsWith("ext:") || address.StartsWith("ext-ip:"))
+ {
+ return;
+ }
+ else if (address.StartsWith("geoip:!"))
+ {
+ return;
+ }
+ else if (address.StartsWith("geoip:"))
+ {
+ if (rule.geoip is null) { rule.geoip = new(); }
+ rule.geoip?.Add(address.Substring(6));
+ }
+ else
+ {
+ if (rule.ip_cidr is null) { rule.ip_cidr = new(); }
+ rule.ip_cidr?.Add(address);
+ }
+ }
+
+ #endregion routing rule private
+
+ #region dns private
+
+ private int dns(ProfileItem node, SingboxConfig singboxConfig)
+ {
+ try
+ {
+ Dns4Sbox? dns4Sbox;
+ if (_config.tunModeItem.enableTun)
+ {
+ var item = LazyConfig.Instance.GetDNSItem(ECoreType.sing_box);
+ var tunDNS = item?.tunDNS;
+ if (string.IsNullOrWhiteSpace(tunDNS))
+ {
+ tunDNS = Utils.GetEmbedText(Global.TunSingboxDNSFileName);
+ }
+ dns4Sbox = Utils.FromJson(tunDNS);
+ }
+ else
+ {
+ var item = LazyConfig.Instance.GetDNSItem(ECoreType.sing_box);
+ var normalDNS = item?.normalDNS;
+ if (string.IsNullOrWhiteSpace(normalDNS))
+ {
+ normalDNS = "{\"servers\":[{\"address\":\"tcp://8.8.8.8\"}]}";
+ }
+
+ dns4Sbox = Utils.FromJson(normalDNS);
+ }
+ if (dns4Sbox is null)
+ {
+ return 0;
+ }
+ //Add the dns of the remote server domain
+ if (dns4Sbox.rules is null)
+ {
+ dns4Sbox.rules = new();
+ }
+ dns4Sbox.servers.Add(new()
+ {
+ tag = "local_local",
+ address = "223.5.5.5",
+ detour = "direct"
+ });
+ dns4Sbox.rules.Add(new()
+ {
+ server = "local_local",
+ outbound = "any"
+ });
+
+ singboxConfig.dns = dns4Sbox;
+ }
+ catch (Exception ex)
+ {
+ Utils.SaveLog(ex.Message, ex);
+ }
+ return 0;
+ }
+
+ #endregion dns private
+
+ private int statistic(SingboxConfig singboxConfig)
+ {
+ if (_config.guiItem.enableStatistics)
+ {
+ singboxConfig.experimental = new Experimental4Sbox()
+ {
+ //v2ray_api = new V2ray_Api4Sbox()
+ //{
+ // listen = $"{Global.Loopback}:{Global.statePort}",
+ // stats = new Stats4Sbox()
+ // {
+ // enabled = true,
+ // }
+ //}
+ clash_api = new Clash_Api4Sbox()
+ {
+ external_controller = $"{Global.Loopback}:{Global.statePort}",
+ store_selected = true
+ }
+ };
+ }
+ return 0;
+ }
}
\ No newline at end of file
diff --git a/v2rayN/v2rayN/Handler/CoreConfigV2ray.cs b/v2rayN/v2rayN/Handler/CoreConfigV2ray.cs
index 87253e54..cd14a021 100644
--- a/v2rayN/v2rayN/Handler/CoreConfigV2ray.cs
+++ b/v2rayN/v2rayN/Handler/CoreConfigV2ray.cs
@@ -4,202 +4,188 @@ using v2rayN.Base;
using v2rayN.Mode;
using v2rayN.Resx;
-namespace v2rayN.Handler
+namespace v2rayN.Handler;
+
+internal class CoreConfigV2ray
{
- internal class CoreConfigV2ray
+ private string SampleClient = Global.v2raySampleClient;
+ private Config _config;
+
+ public CoreConfigV2ray(Config config)
{
- private string SampleClient = Global.v2raySampleClient;
- private Config _config;
+ _config = config;
+ }
- public CoreConfigV2ray(Config config)
+ public int GenerateClientConfigContent(ProfileItem node, out V2rayConfig? v2rayConfig, out string msg)
+ {
+ v2rayConfig = null;
+ try
{
- _config = config;
- }
-
- public int GenerateClientConfigContent(ProfileItem node, out V2rayConfig? v2rayConfig, out string msg)
- {
- v2rayConfig = null;
- try
+ if (node == null
+ || node.port <= 0)
{
- if (node == null
- || node.port <= 0)
- {
- msg = ResUI.CheckServerSettings;
- return -1;
- }
-
- msg = ResUI.InitialConfiguration;
-
- string result = Utils.GetEmbedText(SampleClient);
- if (Utils.IsNullOrEmpty(result))
- {
- msg = ResUI.FailedGetDefaultConfiguration;
- return -1;
- }
-
- v2rayConfig = Utils.FromJson(result);
- if (v2rayConfig == null)
- {
- msg = ResUI.FailedGenDefaultConfiguration;
- return -1;
- }
-
- log(v2rayConfig);
-
- inbound(v2rayConfig);
-
- routing(v2rayConfig);
-
- outbound(node, v2rayConfig);
-
- dns(v2rayConfig);
-
- statistic(v2rayConfig);
-
- msg = string.Format(ResUI.SuccessfulConfiguration, "");
+ msg = ResUI.CheckServerSettings;
+ return -1;
}
- catch (Exception ex)
+
+ msg = ResUI.InitialConfiguration;
+
+ string result = Utils.GetEmbedText(SampleClient);
+ if (Utils.IsNullOrEmpty(result))
+ {
+ msg = ResUI.FailedGetDefaultConfiguration;
+ return -1;
+ }
+
+ v2rayConfig = Utils.FromJson(result);
+ if (v2rayConfig == null)
{
- Utils.SaveLog("GenerateClientConfig4V2ray", ex);
msg = ResUI.FailedGenDefaultConfiguration;
return -1;
}
- return 0;
- }
- private int log(V2rayConfig v2rayConfig)
+ log(v2rayConfig);
+
+ inbound(v2rayConfig);
+
+ routing(v2rayConfig);
+
+ outbound(node, v2rayConfig);
+
+ dns(v2rayConfig);
+
+ statistic(v2rayConfig);
+
+ msg = string.Format(ResUI.SuccessfulConfiguration, "");
+ }
+ catch (Exception ex)
{
- try
+ Utils.SaveLog("GenerateClientConfig4V2ray", ex);
+ msg = ResUI.FailedGenDefaultConfiguration;
+ return -1;
+ }
+ return 0;
+ }
+
+ private int log(V2rayConfig v2rayConfig)
+ {
+ try
+ {
+ if (_config.coreBasicItem.logEnabled)
{
- if (_config.coreBasicItem.logEnabled)
+ var dtNow = DateTime.Now;
+ v2rayConfig.log.loglevel = _config.coreBasicItem.loglevel;
+ v2rayConfig.log.access = Utils.GetLogPath($"Vaccess_{dtNow:yyyy-MM-dd}.txt");
+ v2rayConfig.log.error = Utils.GetLogPath($"Verror_{dtNow:yyyy-MM-dd}.txt");
+ }
+ else
+ {
+ v2rayConfig.log.loglevel = _config.coreBasicItem.loglevel;
+ v2rayConfig.log.access = "";
+ v2rayConfig.log.error = "";
+ }
+ }
+ catch (Exception ex)
+ {
+ Utils.SaveLog(ex.Message, ex);
+ }
+ return 0;
+ }
+
+ private int inbound(V2rayConfig v2rayConfig)
+ {
+ try
+ {
+ v2rayConfig.inbounds = new List();
+
+ Inbounds4Ray? inbound = GetInbound(_config.inbound[0], Global.InboundSocks, 0, true);
+ v2rayConfig.inbounds.Add(inbound);
+
+ //http
+ Inbounds4Ray? inbound2 = GetInbound(_config.inbound[0], Global.InboundHttp, 1, false);
+ v2rayConfig.inbounds.Add(inbound2);
+
+ if (_config.inbound[0].allowLANConn)
+ {
+ if (_config.inbound[0].newPort4LAN)
{
- var dtNow = DateTime.Now;
- v2rayConfig.log.loglevel = _config.coreBasicItem.loglevel;
- v2rayConfig.log.access = Utils.GetLogPath($"Vaccess_{dtNow:yyyy-MM-dd}.txt");
- v2rayConfig.log.error = Utils.GetLogPath($"Verror_{dtNow:yyyy-MM-dd}.txt");
+ Inbounds4Ray inbound3 = GetInbound(_config.inbound[0], Global.InboundSocks2, 2, true);
+ inbound3.listen = "0.0.0.0";
+ v2rayConfig.inbounds.Add(inbound3);
+
+ Inbounds4Ray inbound4 = GetInbound(_config.inbound[0], Global.InboundHttp2, 3, false);
+ inbound4.listen = "0.0.0.0";
+ v2rayConfig.inbounds.Add(inbound4);
+
+ //auth
+ if (!Utils.IsNullOrEmpty(_config.inbound[0].user) && !Utils.IsNullOrEmpty(_config.inbound[0].pass))
+ {
+ inbound3.settings.auth = "password";
+ inbound3.settings.accounts = new List { new AccountsItem4Ray() { user = _config.inbound[0].user, pass = _config.inbound[0].pass } };
+
+ inbound4.settings.auth = "password";
+ inbound4.settings.accounts = new List { new AccountsItem4Ray() { user = _config.inbound[0].user, pass = _config.inbound[0].pass } };
+ }
}
else
{
- v2rayConfig.log.loglevel = _config.coreBasicItem.loglevel;
- v2rayConfig.log.access = "";
- v2rayConfig.log.error = "";
+ inbound.listen = "0.0.0.0";
+ inbound2.listen = "0.0.0.0";
}
}
- catch (Exception ex)
- {
- Utils.SaveLog(ex.Message, ex);
- }
- return 0;
+ }
+ catch (Exception ex)
+ {
+ Utils.SaveLog(ex.Message, ex);
+ }
+ return 0;
+ }
+
+ private Inbounds4Ray? GetInbound(InItem inItem, string tag, int offset, bool bSocks)
+ {
+ string result = Utils.GetEmbedText(Global.v2raySampleInbound);
+ if (Utils.IsNullOrEmpty(result))
+ {
+ return null;
}
- private int inbound(V2rayConfig v2rayConfig)
+ var inbound = Utils.FromJson(result);
+ if (inbound == null)
{
- try
+ return null;
+ }
+ inbound.tag = tag;
+ inbound.port = inItem.localPort + offset;
+ inbound.protocol = bSocks ? Global.InboundSocks : Global.InboundHttp;
+ inbound.settings.udp = inItem.udpEnabled;
+ inbound.sniffing.enabled = inItem.sniffingEnabled;
+ inbound.sniffing.routeOnly = inItem.routeOnly;
+
+ return inbound;
+ }
+
+ private int routing(V2rayConfig v2rayConfig)
+ {
+ try
+ {
+ if (v2rayConfig.routing?.rules != null)
{
- v2rayConfig.inbounds = new List();
+ v2rayConfig.routing.domainStrategy = _config.routingBasicItem.domainStrategy;
+ v2rayConfig.routing.domainMatcher = Utils.IsNullOrEmpty(_config.routingBasicItem.domainMatcher) ? null : _config.routingBasicItem.domainMatcher;
- Inbounds4Ray? inbound = GetInbound(_config.inbound[0], Global.InboundSocks, 0, true);
- v2rayConfig.inbounds.Add(inbound);
-
- //http
- Inbounds4Ray? inbound2 = GetInbound(_config.inbound[0], Global.InboundHttp, 1, false);
- v2rayConfig.inbounds.Add(inbound2);
-
- if (_config.inbound[0].allowLANConn)
+ if (_config.routingBasicItem.enableRoutingAdvanced)
{
- if (_config.inbound[0].newPort4LAN)
+ var routing = ConfigHandler.GetDefaultRouting(ref _config);
+ if (routing != null)
{
- Inbounds4Ray inbound3 = GetInbound(_config.inbound[0], Global.InboundSocks2, 2, true);
- inbound3.listen = "0.0.0.0";
- v2rayConfig.inbounds.Add(inbound3);
-
- Inbounds4Ray inbound4 = GetInbound(_config.inbound[0], Global.InboundHttp2, 3, false);
- inbound4.listen = "0.0.0.0";
- v2rayConfig.inbounds.Add(inbound4);
-
- //auth
- if (!Utils.IsNullOrEmpty(_config.inbound[0].user) && !Utils.IsNullOrEmpty(_config.inbound[0].pass))
+ if (!Utils.IsNullOrEmpty(routing.domainStrategy))
{
- inbound3.settings.auth = "password";
- inbound3.settings.accounts = new List { new AccountsItem4Ray() { user = _config.inbound[0].user, pass = _config.inbound[0].pass } };
-
- inbound4.settings.auth = "password";
- inbound4.settings.accounts = new List { new AccountsItem4Ray() { user = _config.inbound[0].user, pass = _config.inbound[0].pass } };
+ v2rayConfig.routing.domainStrategy = routing.domainStrategy;
}
- }
- else
- {
- inbound.listen = "0.0.0.0";
- inbound2.listen = "0.0.0.0";
- }
- }
- }
- catch (Exception ex)
- {
- Utils.SaveLog(ex.Message, ex);
- }
- return 0;
- }
-
- private Inbounds4Ray? GetInbound(InItem inItem, string tag, int offset, bool bSocks)
- {
- string result = Utils.GetEmbedText(Global.v2raySampleInbound);
- if (Utils.IsNullOrEmpty(result))
- {
- return null;
- }
-
- var inbound = Utils.FromJson(result);
- if (inbound == null)
- {
- return null;
- }
- inbound.tag = tag;
- inbound.port = inItem.localPort + offset;
- inbound.protocol = bSocks ? Global.InboundSocks : Global.InboundHttp;
- inbound.settings.udp = inItem.udpEnabled;
- inbound.sniffing.enabled = inItem.sniffingEnabled;
- inbound.sniffing.routeOnly = inItem.routeOnly;
-
- return inbound;
- }
-
- private int routing(V2rayConfig v2rayConfig)
- {
- try
- {
- if (v2rayConfig.routing?.rules != null)
- {
- v2rayConfig.routing.domainStrategy = _config.routingBasicItem.domainStrategy;
- v2rayConfig.routing.domainMatcher = Utils.IsNullOrEmpty(_config.routingBasicItem.domainMatcher) ? null : _config.routingBasicItem.domainMatcher;
-
- if (_config.routingBasicItem.enableRoutingAdvanced)
- {
- var routing = ConfigHandler.GetDefaultRouting(ref _config);
- if (routing != null)
+ var rules = Utils.FromJson>(routing.ruleSet);
+ foreach (var item in rules)
{
- if (!Utils.IsNullOrEmpty(routing.domainStrategy))
- {
- v2rayConfig.routing.domainStrategy = routing.domainStrategy;
- }
- var rules = Utils.FromJson>(routing.ruleSet);
- foreach (var item in rules)
- {
- if (item.enabled)
- {
- var item2 = Utils.FromJson(Utils.ToJson(item));
- routingUserRule(item2, v2rayConfig);
- }
- }
- }
- }
- else
- {
- var lockedItem = ConfigHandler.GetLockedRoutingItem(ref _config);
- if (lockedItem != null)
- {
- var rules = Utils.FromJson>(lockedItem.ruleSet);
- foreach (var item in rules)
+ if (item.enabled)
{
var item2 = Utils.FromJson(Utils.ToJson(item));
routingUserRule(item2, v2rayConfig);
@@ -207,743 +193,756 @@ namespace v2rayN.Handler
}
}
}
- }
- catch (Exception ex)
- {
- Utils.SaveLog(ex.Message, ex);
- }
- return 0;
- }
-
- private int routingUserRule(RulesItem4Ray rules, V2rayConfig v2rayConfig)
- {
- try
- {
- if (rules == null)
+ else
{
- return 0;
- }
- if (Utils.IsNullOrEmpty(rules.port))
- {
- rules.port = null;
- }
- if (rules.domain?.Count == 0)
- {
- rules.domain = null;
- }
- if (rules.ip?.Count == 0)
- {
- rules.ip = null;
- }
- if (rules.protocol?.Count == 0)
- {
- rules.protocol = null;
- }
- if (rules.inboundTag?.Count == 0)
- {
- rules.inboundTag = null;
- }
-
- var hasDomainIp = false;
- if (rules.domain?.Count > 0)
- {
- var it = Utils.DeepCopy(rules);
- it.ip = null;
- it.type = "field";
- for (int k = it.domain.Count - 1; k >= 0; k--)
+ var lockedItem = ConfigHandler.GetLockedRoutingItem(ref _config);
+ if (lockedItem != null)
{
- if (it.domain[k].StartsWith("#"))
+ var rules = Utils.FromJson>(lockedItem.ruleSet);
+ foreach (var item in rules)
{
- it.domain.RemoveAt(k);
- }
- it.domain[k] = it.domain[k].Replace(Global.RoutingRuleComma, ",");
- }
- v2rayConfig.routing.rules.Add(it);
- hasDomainIp = true;
- }
- if (rules.ip?.Count > 0)
- {
- var it = Utils.DeepCopy(rules);
- it.domain = null;
- it.type = "field";
- v2rayConfig.routing.rules.Add(it);
- hasDomainIp = true;
- }
- if (!hasDomainIp)
- {
- if (!Utils.IsNullOrEmpty(rules.port)
- || (rules.protocol?.Count > 0)
- || (rules.inboundTag?.Count > 0)
- )
- {
- var it = Utils.DeepCopy(rules);
- it.type = "field";
- v2rayConfig.routing.rules.Add(it);
- }
- }
- }
- catch (Exception ex)
- {
- Utils.SaveLog(ex.Message, ex);
- }
- return 0;
- }
-
- private int outbound(ProfileItem node, V2rayConfig v2rayConfig)
- {
- try
- {
- Outbounds4Ray outbound = v2rayConfig.outbounds[0];
- if (node.configType == EConfigType.VMess)
- {
- VnextItem4Ray vnextItem;
- if (outbound.settings.vnext.Count <= 0)
- {
- vnextItem = new VnextItem4Ray();
- outbound.settings.vnext.Add(vnextItem);
- }
- else
- {
- vnextItem = outbound.settings.vnext[0];
- }
- vnextItem.address = node.address;
- vnextItem.port = node.port;
-
- UsersItem4Ray usersItem;
- if (vnextItem.users.Count <= 0)
- {
- usersItem = new UsersItem4Ray();
- vnextItem.users.Add(usersItem);
- }
- else
- {
- usersItem = vnextItem.users[0];
- }
- //远程服务器用户ID
- usersItem.id = node.id;
- usersItem.alterId = node.alterId;
- usersItem.email = Global.userEMail;
- if (Global.vmessSecuritys.Contains(node.security))
- {
- usersItem.security = node.security;
- }
- else
- {
- usersItem.security = Global.DefaultSecurity;
- }
-
- outboundMux(node, outbound, _config.coreBasicItem.muxEnabled);
-
- outbound.protocol = Global.vmessProtocolLite;
- outbound.settings.servers = null;
- }
- else if (node.configType == EConfigType.Shadowsocks)
- {
- ServersItem4Ray serversItem;
- if (outbound.settings.servers.Count <= 0)
- {
- serversItem = new ServersItem4Ray();
- outbound.settings.servers.Add(serversItem);
- }
- else
- {
- serversItem = outbound.settings.servers[0];
- }
- serversItem.address = node.address;
- serversItem.port = node.port;
- serversItem.password = node.id;
- serversItem.method = LazyConfig.Instance.GetShadowsocksSecuritys(node).Contains(node.security) ? node.security : "none";
-
- serversItem.ota = false;
- serversItem.level = 1;
-
- outboundMux(node, outbound, false);
-
- outbound.protocol = Global.ssProtocolLite;
- outbound.settings.vnext = null;
- }
- else if (node.configType == EConfigType.Socks)
- {
- ServersItem4Ray serversItem;
- if (outbound.settings.servers.Count <= 0)
- {
- serversItem = new ServersItem4Ray();
- outbound.settings.servers.Add(serversItem);
- }
- else
- {
- serversItem = outbound.settings.servers[0];
- }
- serversItem.address = node.address;
- serversItem.port = node.port;
- serversItem.method = null;
- serversItem.password = null;
-
- if (!Utils.IsNullOrEmpty(node.security)
- && !Utils.IsNullOrEmpty(node.id))
- {
- SocksUsersItem4Ray socksUsersItem = new()
- {
- user = node.security,
- pass = node.id,
- level = 1
- };
-
- serversItem.users = new List