Compare commits

...

48 Commits
6.9 ... 6.13

Author SHA1 Message Date
2dust
aac2b4aaf0 up 6.13 2023-02-19 15:44:52 +08:00
2dust
fe070b306f Merge pull request #3309 from ilyfairy/master
改为可空类型, 简化代码
2023-02-19 15:33:25 +08:00
2dust
ecfadf8a23 Merge branch 'master' into master 2023-02-19 15:23:04 +08:00
2dust
653af71596 Add log switch in tun mode 2023-02-19 14:55:44 +08:00
小仙女
6a89be2e89 简化代码 2023-02-19 13:34:22 +08:00
小仙女
b84bad4e1a 改为可空类型 2023-02-19 12:18:08 +08:00
2dust
0f8d86f081 Refactoring sorting and delayed storage 2023-02-19 11:23:45 +08:00
2dust
d44f311ba1 Refactoring sorting and delayed storage 2023-02-19 10:43:42 +08:00
2dust
6f5428ca61 Merge pull request #3306 from Weltolk/master
语句更通顺
2023-02-19 09:59:47 +08:00
2dust
b0bee3ca1a Merge pull request #3305 from ilyfairy/master
优化, 改成使用语法糖
2023-02-19 09:59:30 +08:00
2dust
7908194d27 Merge pull request #3301 from meaqese/add-russian-language
full-russian-support
2023-02-18 20:07:57 +08:00
小仙女
b27c7fb2dd string.Join的第二个参数(List<string>)改成ToArray 2023-02-17 22:06:17 +08:00
小仙女
a23cb95a10 性能优化 2023-02-17 15:17:01 +08:00
小仙女
fc137f9b1c 语句更通顺 2023-02-17 15:09:26 +08:00
Weltolk
84780bf9ef Update ResUI.zh-Hans.resx 2023-02-17 14:39:59 +08:00
小仙女
1321037c52 优化, 改成使用语法糖 2023-02-17 14:36:28 +08:00
meaqese
de1da12d45 full-russian-support 2023-02-17 03:18:41 +03:00
2dust
6d4cbacd50 GenerateSatelliteAssembliesForCore 2023-02-15 20:48:56 +08:00
2dust
bf9f7ca990 Adjust the group style 2023-02-15 20:47:17 +08:00
2dust
ca334104d7 bug fixes 2023-02-15 20:37:51 +08:00
2dust
c3e00ba31b bug fixes 2023-02-15 20:37:27 +08:00
2dust
ea3a9cc70e ShowInTaskbar = false 2023-02-15 20:36:50 +08:00
2dust
7ad22e0a73 up 6.12 2023-02-12 20:54:41 +08:00
2dust
ca1abb58eb Add subscription update multiple update function 2023-02-12 20:42:10 +08:00
2dust
3e353944b2 Update App.xaml 2023-02-12 20:41:06 +08:00
2dust
007a250f55 up 6.11 2023-02-12 08:54:23 +08:00
2dust
e9bb6a9951 bug fixes 2023-02-12 08:53:28 +08:00
2dust
82f236e07b up 6.10 2023-02-11 20:03:54 +08:00
2dust
17bfe74ecf Add routing sort 2023-02-11 19:34:15 +08:00
2dust
b77827df90 Update v2rayN.csproj 2023-02-10 21:02:41 +08:00
2dust
a359a508ae fix Import old config 2023-02-10 21:02:29 +08:00
2dust
3a740118f0 Adjust task service settings 2023-02-10 18:58:20 +08:00
2dust
58d9bcbd14 tidy code github 2023-02-10 16:25:16 +08:00
2dust
24be7b2180 store msg filter 2023-02-10 16:01:47 +08:00
2dust
f4c9ca8dff Refactor routing basic settings 2023-02-10 14:51:00 +08:00
2dust
9b8181b72b Refactor gui settings 2023-02-10 14:36:37 +08:00
2dust
1ff1962425 Refactor basic settings 2023-02-10 14:16:59 +08:00
2dust
9b05736746 Add environment variables to geo files 2023-02-10 11:22:03 +08:00
2dust
dec722e693 Update UpdateHandle.cs 2023-02-10 11:05:11 +08:00
2dust
49fa0a4c67 DownloadStringAsyncOri 2023-02-10 11:04:57 +08:00
2dust
0cdc69e1e8 Update MsgView.xaml 2023-02-10 09:39:18 +08:00
2dust
0494cc4ce7 adjust group style 2023-02-09 16:43:50 +08:00
2dust
30d82947d6 fix 2023-02-09 15:17:52 +08:00
2dust
ec59249d79 Optimize file download 2023-02-09 14:54:54 +08:00
2dust
7eb869ab1d Optimize file download 2023-02-09 10:54:31 +08:00
2dust
d014724a2d Optimize speed test 2023-02-08 19:20:44 +08:00
2dust
dfb6cef364 Update OptionSettingWindow.xaml.cs 2023-02-08 15:07:23 +08:00
2dust
0ebf8c9349 Optimize Font size 2023-02-07 19:05:49 +08:00
65 changed files with 2016 additions and 1409 deletions

View File

@@ -18,8 +18,9 @@
</ResourceDictionary.MergedDictionaries> </ResourceDictionary.MergedDictionaries>
<system:Double x:Key="MenuItemHeight">26</system:Double> <system:Double x:Key="MenuItemHeight">26</system:Double>
<system:Double x:Key="StdFontSize">12</system:Double> <system:Double x:Key="StdFontSize">12</system:Double>
<system:Double x:Key="StdFontSize1">14</system:Double> <system:Double x:Key="StdFontSize1">13</system:Double>
<system:Double x:Key="StdFontSize2">16</system:Double> <system:Double x:Key="StdFontSize2">14</system:Double>
<system:Double x:Key="StdFontSizeMsg">11</system:Double>
<Thickness <Thickness
x:Key="ServerItemMargin" x:Key="ServerItemMargin"
Bottom="4" Bottom="4"
@@ -134,6 +135,12 @@
TargetType="{x:Type GroupBox}"> TargetType="{x:Type GroupBox}">
<Setter Property="FontSize" Value="{DynamicResource StdFontSize}" /> <Setter Property="FontSize" Value="{DynamicResource StdFontSize}" />
</Style> </Style>
<Style
x:Key="MyChipListBoxItem"
BasedOn="{StaticResource MaterialDesignChoiceChipPrimaryOutlineListBoxItem}"
TargetType="{x:Type ListBoxItem}">
<Setter Property="Margin" Value="-2,0" />
</Style>
</ResourceDictionary> </ResourceDictionary>

View File

@@ -0,0 +1,187 @@
using Downloader;
using System.IO;
using System.Net;
namespace v2rayN.Base
{
internal class DownloaderHelper
{
private static readonly Lazy<DownloaderHelper> _instance = new(() => new());
public static DownloaderHelper Instance => _instance.Value;
public async Task<string?> DownloadStringAsync(IWebProxy webProxy, string url, string? userAgent, int timeout)
{
if (string.IsNullOrEmpty(url))
{
return null;
}
var cancellationToken = new CancellationTokenSource();
cancellationToken.CancelAfter(timeout * 1000);
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 new Exception(string.Format("{0}", value.Error.Message));
}
};
using var stream = await downloader.DownloadFileTaskAsync(address: url, cancellationToken: cancellationToken.Token);
using StreamReader reader = new(stream);
downloadOpt = null;
return reader.ReadToEnd();
}
public async Task DownloadDataAsync4Speed(IWebProxy webProxy, string url, IProgress<string> progress, int timeout)
{
if (string.IsNullOrEmpty(url))
{
throw new ArgumentNullException(nameof(url));
}
var cancellationToken = new CancellationTokenSource();
cancellationToken.CancelAfter(timeout * 1000);
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("......");
await downloader.DownloadFileTaskAsync(address: url, cancellationToken: cancellationToken.Token);
downloadOpt = null;
}
public async Task DownloadFileAsync(IWebProxy webProxy, string url, string fileName, IProgress<double> 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 cancellationToken = new CancellationTokenSource();
cancellationToken.CancelAfter(timeout * 1000);
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);
}
}
};
await downloader.DownloadFileTaskAsync(url, fileName, cancellationToken: cancellationToken.Token);
downloadOpt = null;
}
}
}

View File

@@ -26,14 +26,14 @@ namespace v2rayN.Base
} }
else else
{ {
HttpClientHelper httpClientHelper = new HttpClientHelper(); HttpClientHelper httpClientHelper = new();
HttpClientHandler handler = new HttpClientHandler() { UseCookies = false }; HttpClientHandler handler = new() { UseCookies = false };
httpClientHelper.httpClient = new HttpClient(handler); httpClientHelper.httpClient = new HttpClient(handler);
return httpClientHelper; return httpClientHelper;
} }
} }
public async Task<string> GetAsync(string url) public async Task<string?> GetAsync(string url)
{ {
if (string.IsNullOrEmpty(url)) if (string.IsNullOrEmpty(url))
{ {
@@ -43,7 +43,7 @@ namespace v2rayN.Base
return await response.Content.ReadAsStringAsync(); return await response.Content.ReadAsStringAsync();
} }
public async Task<string> GetAsync(HttpClient client, string url, CancellationToken token) public async Task<string?> GetAsync(HttpClient client, string url, CancellationToken token)
{ {
if (string.IsNullOrEmpty(url)) if (string.IsNullOrEmpty(url))
{ {
@@ -54,7 +54,7 @@ namespace v2rayN.Base
{ {
throw new Exception(string.Format("{0}", response.StatusCode)); throw new Exception(string.Format("{0}", response.StatusCode));
} }
return await response.Content.ReadAsStringAsync(); return await response.Content.ReadAsStringAsync(token);
} }
public async Task PutAsync(string url, Dictionary<string, string> headers) public async Task PutAsync(string url, Dictionary<string, string> headers)
@@ -71,11 +71,11 @@ namespace v2rayN.Base
{ {
if (string.IsNullOrEmpty(url)) if (string.IsNullOrEmpty(url))
{ {
throw new ArgumentNullException("url"); throw new ArgumentNullException(nameof(url));
} }
if (string.IsNullOrEmpty(fileName)) if (string.IsNullOrEmpty(fileName))
{ {
throw new ArgumentNullException("fileName"); throw new ArgumentNullException(nameof(fileName));
} }
if (File.Exists(fileName)) if (File.Exists(fileName))
{ {
@@ -89,13 +89,11 @@ namespace v2rayN.Base
throw new Exception(string.Format("{0}", response.StatusCode)); throw new Exception(string.Format("{0}", response.StatusCode));
} }
var total = response.Content.Headers.ContentLength.HasValue ? response.Content.Headers.ContentLength.Value : -1L; var total = response.Content.Headers.ContentLength ?? -1L;
var canReportProgress = total != -1 && progress != null; var canReportProgress = total != -1 && progress != null;
using (var stream = await response.Content.ReadAsStreamAsync()) using var stream = await response.Content.ReadAsStreamAsync(token);
{ using var file = File.Create(fileName);
using (var file = File.Create(fileName))
{
var totalRead = 0L; var totalRead = 0L;
var buffer = new byte[1024 * 1024]; var buffer = new byte[1024 * 1024];
var isMoreToRead = true; var isMoreToRead = true;
@@ -105,7 +103,7 @@ namespace v2rayN.Base
{ {
token.ThrowIfCancellationRequested(); token.ThrowIfCancellationRequested();
var read = await stream.ReadAsync(buffer, 0, buffer.Length, token); var read = await stream.ReadAsync(buffer, token);
if (read == 0) if (read == 0)
{ {
@@ -132,21 +130,18 @@ namespace v2rayN.Base
} }
} }
} while (isMoreToRead); } while (isMoreToRead);
file.Close();
if (canReportProgress) if (canReportProgress)
{ {
progress.Report(101); progress.Report(101);
} }
} }
}
}
public async Task DownloadDataAsync4Speed(HttpClient client, string url, IProgress<string> progress, CancellationToken token) public async Task DownloadDataAsync4Speed(HttpClient client, string url, IProgress<string> progress, CancellationToken token)
{ {
if (string.IsNullOrEmpty(url)) if (string.IsNullOrEmpty(url))
{ {
throw new ArgumentNullException("url"); throw new ArgumentNullException(nameof(url));
} }
var response = await client.GetAsync(url, HttpCompletionOption.ResponseHeadersRead, token); var response = await client.GetAsync(url, HttpCompletionOption.ResponseHeadersRead, token);
@@ -159,8 +154,7 @@ namespace v2rayN.Base
//var total = response.Content.Headers.ContentLength.HasValue ? response.Content.Headers.ContentLength.Value : -1L; //var total = response.Content.Headers.ContentLength.HasValue ? response.Content.Headers.ContentLength.Value : -1L;
//var canReportProgress = total != -1 && progress != null; //var canReportProgress = total != -1 && progress != null;
using (var stream = await response.Content.ReadAsStreamAsync()) using var stream = await response.Content.ReadAsStreamAsync(token);
{
var totalRead = 0L; var totalRead = 0L;
var buffer = new byte[1024 * 64]; var buffer = new byte[1024 * 64];
var isMoreToRead = true; var isMoreToRead = true;
@@ -182,7 +176,7 @@ namespace v2rayN.Base
} }
} }
var read = await stream.ReadAsync(buffer, 0, buffer.Length, token); var read = await stream.ReadAsync(buffer, token);
if (read == 0) if (read == 0)
{ {
@@ -210,7 +204,6 @@ namespace v2rayN.Base
} }
} while (isMoreToRead); } while (isMoreToRead);
} }
}
} }
} }

View File

@@ -6,7 +6,7 @@ namespace v2rayN.Base
{ {
public sealed class SqliteHelper public sealed class SqliteHelper
{ {
private static readonly Lazy<SqliteHelper> _instance = new Lazy<SqliteHelper>(() => new()); private static readonly Lazy<SqliteHelper> _instance = new(() => new());
public static SqliteHelper Instance => _instance.Value; public static SqliteHelper Instance => _instance.Value;
private string _connstr; private string _connstr;
public SQLiteConnection _db; public SQLiteConnection _db;

View File

@@ -34,7 +34,7 @@ namespace v2rayN.Base
public static IEnumerable<string> NonWhiteSpaceLines(this TextReader reader) public static IEnumerable<string> NonWhiteSpaceLines(this TextReader reader)
{ {
string line; string? line;
while ((line = reader.ReadLine()) != null) while ((line = reader.ReadLine()) != null)
{ {
if (line.IsWhiteSpace()) continue; if (line.IsWhiteSpace()) continue;

View File

@@ -17,7 +17,7 @@ namespace v2rayN.Converters
return new SolidColorBrush(Colors.IndianRed); return new SolidColorBrush(Colors.IndianRed);
} }
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) public object? ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{ {
return null; return null;
} }

View File

@@ -21,10 +21,7 @@ namespace v2rayN.Converters
catch catch
{ {
} }
if (MyFont is null) MyFont ??= new FontFamily("Microsoft YaHei");
{
MyFont = new FontFamily("Microsoft YaHei");
}
} }
} }
} }

View File

@@ -3,6 +3,8 @@
class Global class Global
{ {
#region const #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 v2rayWebsiteUrl = @"https://www.v2fly.org/";
public const string AboutUrl = @"https://github.com/2dust/v2rayN"; public const string AboutUrl = @"https://github.com/2dust/v2rayN";
public const string UpdateUrl = AboutUrl + @"/releases"; public const string UpdateUrl = AboutUrl + @"/releases";
@@ -17,7 +19,6 @@
public const string tuicCoreUrl = "https://github.com/EAimTY/tuic/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 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 geoUrl = "https://github.com/Loyalsoldier/v2ray-rules-dat/releases/latest/download/{0}.dat";
public const string SpeedTestUrl = @"http://cachefly.cachefly.net/10mb.test";
public const string SpeedPingTestUrl = @"https://www.google.com/generate_204"; public const string SpeedPingTestUrl = @"https://www.google.com/generate_204";
public const string CustomRoutingListUrl = @"https://raw.githubusercontent.com/2dust/v2rayCustomRoutingList/master/"; public const string CustomRoutingListUrl = @"https://raw.githubusercontent.com/2dust/v2rayCustomRoutingList/master/";
@@ -79,26 +80,26 @@
public const string SpeedUnit = ""; public const string SpeedUnit = "";
public const int MinFontSize = 10; public const int MinFontSize = 10;
public static readonly List<string> IEProxyProtocols = new List<string> { public static readonly List<string> IEProxyProtocols = new() {
"{ip}:{http_port}", "{ip}:{http_port}",
"socks={ip}:{socks_port}", "socks={ip}:{socks_port}",
"http={ip}:{http_port};https={ip}:{http_port};ftp={ip}:{http_port};socks={ip}:{socks_port}", "http={ip}:{http_port};https={ip}:{http_port};ftp={ip}:{http_port};socks={ip}:{socks_port}",
"http=http://{ip}:{http_port};https=http://{ip}:{http_port}", "http=http://{ip}:{http_port};https=http://{ip}:{http_port}",
"" ""
}; };
public static readonly List<string> vmessSecuritys = new List<string> { "aes-128-gcm", "chacha20-poly1305", "auto", "none", "zero" }; public static readonly List<string> vmessSecuritys = new() { "aes-128-gcm", "chacha20-poly1305", "auto", "none", "zero" };
public static readonly List<string> ssSecuritys = new List<string> { "aes-256-gcm", "aes-128-gcm", "chacha20-poly1305", "chacha20-ietf-poly1305", "none", "plain" }; public static readonly List<string> ssSecuritys = new() { "aes-256-gcm", "aes-128-gcm", "chacha20-poly1305", "chacha20-ietf-poly1305", "none", "plain" };
public static readonly List<string> ssSecuritysInSagerNet = new List<string> { "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<string> 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<string> ssSecuritysInXray = new List<string> { "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<string> 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<string> xtlsFlows = new List<string> { "", "xtls-rprx-origin", "xtls-rprx-origin-udp443", "xtls-rprx-direct", "xtls-rprx-direct-udp443", "xtls-rprx-vision", "xtls-rprx-vision-udp443" }; public static readonly List<string> xtlsFlows = new() { "", "xtls-rprx-origin", "xtls-rprx-origin-udp443", "xtls-rprx-direct", "xtls-rprx-direct-udp443", "xtls-rprx-vision", "xtls-rprx-vision-udp443" };
public static readonly List<string> networks = new List<string> { "tcp", "kcp", "ws", "h2", "quic", "grpc" }; public static readonly List<string> networks = new() { "tcp", "kcp", "ws", "h2", "quic", "grpc" };
public static readonly List<string> kcpHeaderTypes = new List<string> { "srtp", "utp", "wechat-video", "dtls", "wireguard" }; public static readonly List<string> kcpHeaderTypes = new() { "srtp", "utp", "wechat-video", "dtls", "wireguard" };
public static readonly List<string> coreTypes = new List<string> { "v2fly", "SagerNet", "Xray", "v2fly_v5" }; public static readonly List<string> coreTypes = new() { "v2fly", "SagerNet", "Xray", "v2fly_v5" };
public static readonly List<string> domainStrategys = new List<string> { "AsIs", "IPIfNonMatch", "IPOnDemand" }; public static readonly List<string> domainStrategys = new() { "AsIs", "IPIfNonMatch", "IPOnDemand" };
public static readonly List<string> domainMatchers = new List<string> { "linear", "mph", "" }; public static readonly List<string> domainMatchers = new() { "linear", "mph", "" };
public static readonly List<string> fingerprints = new List<string> { "chrome", "firefox", "safari", "ios", "android", "edge", "360", "qq", "random", "randomized", "" }; public static readonly List<string> fingerprints = new() { "chrome", "firefox", "safari", "ios", "android", "edge", "360", "qq", "random", "randomized", "" };
public static readonly List<string> userAgent = new List<string> { "chrome", "firefox", "safari", "edge", "none" }; public static readonly List<string> userAgent = new() { "chrome", "firefox", "safari", "edge", "none" };
public static readonly Dictionary<string, string> userAgentTxt = new Dictionary<string, string> public static readonly Dictionary<string, string> 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" }, {"chrome","Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.131 Safari/537.36" },
{"firefox","Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:90.0) Gecko/20100101 Firefox/90.0" }, {"firefox","Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:90.0) Gecko/20100101 Firefox/90.0" },
@@ -106,16 +107,17 @@
{"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" }, {"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",""} {"none",""}
}; };
public static readonly List<string> allowInsecures = new List<string> { "true", "false", "" }; public static readonly List<string> allowInsecures = new() { "true", "false", "" };
public static readonly List<string> domainStrategy4Freedoms = new List<string> { "AsIs", "UseIP", "UseIPv4", "UseIPv6", "" }; public static readonly List<string> domainStrategy4Freedoms = new() { "AsIs", "UseIP", "UseIPv4", "UseIPv6", "" };
public static readonly List<string> Languages = new List<string> { "zh-Hans", "en", "fa-Ir", "ru" }; public static readonly List<string> Languages = new() { "zh-Hans", "en", "fa-Ir", "ru" };
public static readonly List<string> alpns = new List<string> { "h2", "http/1.1", "h2,http/1.1", "" }; public static readonly List<string> alpns = new() { "h2", "http/1.1", "h2,http/1.1", "" };
public static readonly List<string> LogLevel = new List<string> { "debug", "info", "warning", "error", "none" }; public static readonly List<string> LogLevel = new() { "debug", "info", "warning", "error", "none" };
public static readonly List<string> InboundTags = new List<string> { "socks", "http", "socks2", "http2" }; public static readonly List<string> InboundTags = new() { "socks", "http", "socks2", "http2" };
public static readonly List<string> Protocols = new List<string> { "http", "tls", "bittorrent" }; public static readonly List<string> Protocols = new() { "http", "tls", "bittorrent" };
public static readonly List<string> TunMtus = new List<string> { "9000", "1500" }; public static readonly List<string> TunMtus = new() { "9000", "1500" };
public static readonly List<string> TunStacks = new List<string> { "gvisor", "system" }; public static readonly List<string> TunStacks = new() { "gvisor", "system" };
public static readonly List<string> PresetMsgFilters = new List<string> { "^(?!.*proxy).*$", "^(?!.*direct).*$", "" }; public static readonly List<string> PresetMsgFilters = new() { "proxy", "direct", "block", "" };
public static readonly List<string> SpeedTestUrls = new() { @"http://cachefly.cachefly.net/100mb.test", @"http://cachefly.cachefly.net/10mb.test" };
#endregion #endregion

View File

@@ -13,7 +13,7 @@ namespace v2rayN.Handler
class ConfigHandler class ConfigHandler
{ {
private static string configRes = Global.ConfigFileName; private static string configRes = Global.ConfigFileName;
private static readonly object objLock = new object(); private static readonly object objLock = new();
#region ConfigHandler #region ConfigHandler
@@ -43,18 +43,17 @@ namespace v2rayN.Handler
if (config == null) if (config == null)
{ {
config = new Config config = new Config
{
};
}
if (config.coreBasicItem == null)
{
config.coreBasicItem = new()
{ {
logEnabled = false, logEnabled = false,
loglevel = "warning", loglevel = "warning",
//Mux
muxEnabled = false, muxEnabled = false,
enableStatistics = false,
statisticsFreshRate = 1,
enableRoutingAdvanced = true
}; };
} }
@@ -62,7 +61,7 @@ namespace v2rayN.Handler
if (config.inbound == null) if (config.inbound == null)
{ {
config.inbound = new List<InItem>(); config.inbound = new List<InItem>();
InItem inItem = new InItem InItem inItem = new()
{ {
protocol = Global.InboundSocks, protocol = Global.InboundSocks,
localPort = 10808, localPort = 10808,
@@ -87,10 +86,17 @@ namespace v2rayN.Handler
config.inbound[0].protocol = Global.InboundSocks; config.inbound[0].protocol = Global.InboundSocks;
} }
} }
//路由规则 if (config.routingBasicItem == null)
if (Utils.IsNullOrEmpty(config.domainStrategy))
{ {
config.domainStrategy = Global.domainStrategys[0];//"IPIfNonMatch"; config.routingBasicItem = new()
{
enableRoutingAdvanced = true
};
}
//路由规则
if (Utils.IsNullOrEmpty(config.routingBasicItem.domainStrategy))
{
config.routingBasicItem.domainStrategy = Global.domainStrategys[0];//"IPIfNonMatch";
} }
//if (Utils.IsNullOrEmpty(config.domainMatcher)) //if (Utils.IsNullOrEmpty(config.domainMatcher))
//{ //{
@@ -130,6 +136,14 @@ namespace v2rayN.Handler
mtu = 9000, mtu = 9000,
}; };
} }
if (config.guiItem == null)
{
config.guiItem = new()
{
enableStatistics = false,
statisticsFreshRate = 1,
};
}
if (config.uiItem == null) if (config.uiItem == null)
{ {
config.uiItem = new UIItem() config.uiItem = new UIItem()
@@ -150,14 +164,6 @@ namespace v2rayN.Handler
{ {
config.constItem = new ConstItem(); config.constItem = new ConstItem();
} }
if (Utils.IsNullOrEmpty(config.constItem.speedTestUrl))
{
config.constItem.speedTestUrl = Global.SpeedTestUrl;
}
if (Utils.IsNullOrEmpty(config.constItem.speedPingTestUrl))
{
config.constItem.speedPingTestUrl = Global.SpeedPingTestUrl;
}
if (Utils.IsNullOrEmpty(config.constItem.defIEProxyExceptions)) if (Utils.IsNullOrEmpty(config.constItem.defIEProxyExceptions))
{ {
config.constItem.defIEProxyExceptions = Global.IEProxyExceptions; config.constItem.defIEProxyExceptions = Global.IEProxyExceptions;
@@ -167,9 +173,26 @@ namespace v2rayN.Handler
// config.remoteDNS = "1.1.1.1"; // config.remoteDNS = "1.1.1.1";
//} //}
if (config.statisticsFreshRate > 100 || config.statisticsFreshRate < 1) if (config.speedTestItem == null)
{ {
config.statisticsFreshRate = 1; 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.guiItem.statisticsFreshRate is > 100 or < 1)
{
config.guiItem.statisticsFreshRate = 1;
} }
if (config == null) if (config == null)
@@ -182,7 +205,7 @@ namespace v2rayN.Handler
} }
LazyConfig.Instance.SetConfig(ref config); LazyConfig.Instance.SetConfig(config);
return 0; return 0;
} }
/// <summary> /// <summary>
@@ -288,20 +311,45 @@ namespace v2rayN.Handler
} }
config = Utils.FromJson<Config>(Utils.ToJson(configOld)); config = Utils.FromJson<Config>(Utils.ToJson(configOld));
if (config.tunModeItem == null)
if (config.coreBasicItem == null)
{ {
config.tunModeItem = new TunModeItem config.coreBasicItem = new()
{ {
enableTun = false, logEnabled = configOld.logEnabled,
showWindow = true, loglevel = configOld.loglevel,
mtu = 9000, 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,
statisticsFreshRate = configOld.statisticsFreshRate,
keepOlderDedupl = configOld.keepOlderDedupl,
ignoreGeoUpdateCore = configOld.ignoreGeoUpdateCore,
autoUpdateInterval = configOld.autoUpdateInterval,
checkPreReleaseUpdate = configOld.checkPreReleaseUpdate,
enableSecurityProtocolTls13 = configOld.enableSecurityProtocolTls13,
trayMenuServersLimit = configOld.trayMenuServersLimit,
}; };
} }
GetDefaultServer(ref config); GetDefaultServer(ref config);
GetDefaultRouting(ref config); GetDefaultRouting(ref config);
SaveConfig(ref config); SaveConfig(ref config);
LazyConfig.Instance.SetConfig(ref config); LoadConfig(ref config);
return 0; return 0;
} }
@@ -390,14 +438,14 @@ namespace v2rayN.Handler
/// <param name="config"></param> /// <param name="config"></param>
/// <param name="item"></param> /// <param name="item"></param>
/// <returns></returns> /// <returns></returns>
public static int SetDefaultServer(ref Config config, ProfileItem item) public static int SetDefaultServerIndex(ref Config config, string? indexId)
{ {
if (item == null) if (Utils.IsNullOrEmpty(indexId))
{ {
return -1; return -1;
} }
config.indexId = item.indexId; config.indexId = indexId;
Global.reloadCore = true; Global.reloadCore = true;
ToJsonFile(config); ToJsonFile(config);
@@ -405,34 +453,34 @@ namespace v2rayN.Handler
return 0; return 0;
} }
public static int SetDefaultServer(Config config, List<ProfileItem> lstProfile) public static int SetDefaultServer(Config config, List<ProfileItemModel> lstProfile)
{ {
if (lstProfile.Exists(t => t.indexId == config.indexId)) if (lstProfile.Exists(t => t.indexId == config.indexId))
{ {
return 0; return 0;
} }
var allItems = LazyConfig.Instance.ProfileItemIndexs("");
if (SqliteHelper.Instance.Table<ProfileItem>().Where(t => t.indexId == config.indexId).Count() > 0) if (allItems.Where(t => t == config.indexId).Any())
{ {
return 0; return 0;
} }
if (lstProfile.Count > 0) if (lstProfile.Count > 0)
{ {
return SetDefaultServer(ref config, lstProfile[0]); return SetDefaultServerIndex(ref config, lstProfile[0].indexId);
} }
if (SqliteHelper.Instance.Table<ProfileItem>().Count() > 0) if (allItems.Count > 0)
{ {
return SetDefaultServer(ref config, SqliteHelper.Instance.Table<ProfileItem>().FirstOrDefault()); return SetDefaultServerIndex(ref config, allItems.FirstOrDefault());
} }
return -1; return -1;
} }
public static ProfileItem GetDefaultServer(ref Config config) public static ProfileItem? GetDefaultServer(ref Config config)
{ {
var item = LazyConfig.Instance.GetProfileItem(config.indexId); var item = LazyConfig.Instance.GetProfileItem(config.indexId);
if (item is null) if (item is null)
{ {
var item2 = SqliteHelper.Instance.Table<ProfileItem>().FirstOrDefault(); var item2 = SqliteHelper.Instance.Table<ProfileItem>().FirstOrDefault();
SetDefaultServer(ref config, item2); SetDefaultServerIndex(ref config, item2?.indexId);
return item2; return item2;
} }
@@ -457,9 +505,10 @@ namespace v2rayN.Handler
for (int i = 0; i < lstProfile.Count; i++) for (int i = 0; i < lstProfile.Count; i++)
{ {
lstProfile[i].sort = (i + 1) * 10; ProfileExHandler.Instance.SetSort(lstProfile[i].indexId, (i + 1) * 10);
} }
var sort = 0;
switch (eMove) switch (eMove)
{ {
case EMove.Top: case EMove.Top:
@@ -468,7 +517,7 @@ namespace v2rayN.Handler
{ {
return 0; return 0;
} }
lstProfile[index].sort = lstProfile[0].sort - 1; sort = ProfileExHandler.Instance.GetSort(lstProfile[0].indexId) - 1;
break; break;
} }
@@ -478,7 +527,7 @@ namespace v2rayN.Handler
{ {
return 0; return 0;
} }
lstProfile[index].sort = lstProfile[index - 1].sort - 1; sort = ProfileExHandler.Instance.GetSort(lstProfile[index - 1].indexId) - 1;
break; break;
} }
@@ -489,7 +538,7 @@ namespace v2rayN.Handler
{ {
return 0; return 0;
} }
lstProfile[index].sort = lstProfile[index + 1].sort + 1; sort = ProfileExHandler.Instance.GetSort(lstProfile[index + 1].indexId) + 1;
break; break;
} }
@@ -499,18 +548,16 @@ namespace v2rayN.Handler
{ {
return 0; return 0;
} }
lstProfile[index].sort = lstProfile[lstProfile.Count - 1].sort + 1; sort = ProfileExHandler.Instance.GetSort(lstProfile[^1].indexId) + 1;
break; break;
} }
case EMove.Position: case EMove.Position:
lstProfile[index].sort = pos * 10 + 1; sort = pos * 10 + 1;
break; break;
} }
SqliteHelper.Instance.UpdateAll(lstProfile); ProfileExHandler.Instance.SetSort(lstProfile[index].indexId, sort);
return 0; return 0;
} }
@@ -638,7 +685,7 @@ namespace v2rayN.Handler
} }
if (Utils.IsNullOrEmpty(profileItem.allowInsecure)) if (Utils.IsNullOrEmpty(profileItem.allowInsecure))
{ {
profileItem.allowInsecure = config.defAllowInsecure.ToString().ToLower(); profileItem.allowInsecure = config.coreBasicItem.defAllowInsecure.ToString().ToLower();
} }
AddServerCommon(ref config, profileItem); AddServerCommon(ref config, profileItem);
@@ -650,11 +697,29 @@ namespace v2rayN.Handler
public static int SortServers(ref Config config, string subId, EServerColName name, bool asc) public static int SortServers(ref Config config, string subId, EServerColName name, bool asc)
{ {
var lstModel = LazyConfig.Instance.ProfileItems(subId, ""); var lstModel = LazyConfig.Instance.ProfileItems(subId, "");
var lstProfile = Utils.FromJson<List<ProfileItem>>(Utils.ToJson(lstModel)); if (lstModel.Count <= 0)
if (lstProfile.Count <= 0)
{ {
return -1; 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();
var propertyName = string.Empty; var propertyName = string.Empty;
switch (name) switch (name)
{ {
@@ -688,7 +753,7 @@ namespace v2rayN.Handler
} }
for (int i = 0; i < lstProfile.Count; i++) for (int i = 0; i < lstProfile.Count; i++)
{ {
lstProfile[i].sort = (i + 1) * 10; ProfileExHandler.Instance.SetSort(lstProfile[i].indexId, (i + 1) * 10);
} }
if (name == EServerColName.delay) if (name == EServerColName.delay)
{ {
@@ -697,7 +762,7 @@ namespace v2rayN.Handler
{ {
if (item.delay <= 0) if (item.delay <= 0)
{ {
item.sort = maxSort; ProfileExHandler.Instance.SetSort(item.indexId, maxSort);
} }
} }
} }
@@ -708,13 +773,11 @@ namespace v2rayN.Handler
{ {
if (item.speed <= 0) if (item.speed <= 0)
{ {
item.sort = maxSort; ProfileExHandler.Instance.SetSort(item.indexId, maxSort);
} }
} }
} }
SqliteHelper.Instance.UpdateAll(lstProfile);
return 0; return 0;
} }
@@ -745,9 +808,9 @@ namespace v2rayN.Handler
public static int DedupServerList(ref Config config, ref List<ProfileItem> lstProfile) public static int DedupServerList(ref Config config, ref List<ProfileItem> lstProfile)
{ {
List<ProfileItem> source = lstProfile; List<ProfileItem> source = lstProfile;
bool keepOlder = config.keepOlderDedupl; bool keepOlder = config.guiItem.keepOlderDedupl;
List<ProfileItem> list = new List<ProfileItem>(); List<ProfileItem> list = new();
if (!keepOlder) source.Reverse(); // Remove the early items first if (!keepOlder) source.Reverse(); // Remove the early items first
foreach (ProfileItem item in source) foreach (ProfileItem item in source)
@@ -772,7 +835,7 @@ namespace v2rayN.Handler
profileItem.configVersion = 2; profileItem.configVersion = 2;
if (Utils.IsNullOrEmpty(profileItem.allowInsecure)) if (Utils.IsNullOrEmpty(profileItem.allowInsecure))
{ {
profileItem.allowInsecure = config.defAllowInsecure.ToString().ToLower(); profileItem.allowInsecure = config.coreBasicItem.defAllowInsecure.ToString().ToLower();
} }
if (!Utils.IsNullOrEmpty(profileItem.network) && !Global.networks.Contains(profileItem.network)) if (!Utils.IsNullOrEmpty(profileItem.network) && !Global.networks.Contains(profileItem.network))
{ {
@@ -782,15 +845,8 @@ namespace v2rayN.Handler
if (Utils.IsNullOrEmpty(profileItem.indexId)) if (Utils.IsNullOrEmpty(profileItem.indexId))
{ {
profileItem.indexId = Utils.GetGUID(false); profileItem.indexId = Utils.GetGUID(false);
if (profileItem.sort <= 0) var maxSort = ProfileExHandler.Instance.GetMaxSort();
{ ProfileExHandler.Instance.SetSort(profileItem.indexId, maxSort + 1);
var maxSort = 0;
if (SqliteHelper.Instance.Table<ProfileItem>().Count() > 0)
{
maxSort = SqliteHelper.Instance.Table<ProfileItem>().Max(t => t == null ? 0 : t.sort);
}
profileItem.sort = maxSort + 1;
}
} }
else if (profileItem.indexId == config.indexId) else if (profileItem.indexId == config.indexId)
{ {
@@ -881,11 +937,11 @@ namespace v2rayN.Handler
} }
int countServers = 0; int countServers = 0;
var maxSort = 0; //var maxSort = 0;
if (SqliteHelper.Instance.Table<ProfileItem>().Count() > 0) //if (SqliteHelper.Instance.Table<ProfileItem>().Count() > 0)
{ //{
maxSort = SqliteHelper.Instance.Table<ProfileItem>().Max(t => t.sort); // maxSort = SqliteHelper.Instance.Table<ProfileItem>().Max(t => t.sort);
} //}
string[] arrData = clipboardData.Split(Environment.NewLine.ToCharArray()); string[] arrData = clipboardData.Split(Environment.NewLine.ToCharArray());
foreach (string str in arrData) foreach (string str in arrData)
{ {
@@ -923,7 +979,7 @@ namespace v2rayN.Handler
} }
profileItem.subid = subid; profileItem.subid = subid;
profileItem.isSub = isSub; profileItem.isSub = isSub;
profileItem.sort = maxSort + countServers + 1; //profileItem.sort = maxSort + countServers + 1;
if (profileItem.configType == EConfigType.VMess) if (profileItem.configType == EConfigType.VMess)
{ {
@@ -973,9 +1029,19 @@ namespace v2rayN.Handler
return -1; return -1;
} }
ProfileItem profileItem = new ProfileItem(); //判断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 //Is v2ray configuration
V2rayConfig v2rayConfig = Utils.FromJson<V2rayConfig>(clipboardData); V2rayConfig? v2rayConfig = Utils.FromJson<V2rayConfig>(clipboardData);
if (v2rayConfig != null if (v2rayConfig != null
&& v2rayConfig.inbounds != null && v2rayConfig.inbounds != null
&& v2rayConfig.inbounds.Count > 0 && v2rayConfig.inbounds.Count > 0
@@ -990,9 +1056,7 @@ namespace v2rayN.Handler
profileItem.remarks = "v2ray_custom"; profileItem.remarks = "v2ray_custom";
} }
//Is Clash configuration //Is Clash configuration
else if (clipboardData.IndexOf("port") >= 0 else if (Containss(clipboardData, "port", "socks-port", "proxies"))
&& clipboardData.IndexOf("socks-port") >= 0
&& clipboardData.IndexOf("proxies") >= 0)
{ {
var fileName = Utils.GetTempPath($"{Utils.GetGUID(false)}.yaml"); var fileName = Utils.GetTempPath($"{Utils.GetGUID(false)}.yaml");
File.WriteAllText(fileName, clipboardData); File.WriteAllText(fileName, clipboardData);
@@ -1002,12 +1066,7 @@ namespace v2rayN.Handler
profileItem.remarks = "clash_custom"; profileItem.remarks = "clash_custom";
} }
//Is hysteria configuration //Is hysteria configuration
else if (clipboardData.IndexOf("server") >= 0 else if (Containss(clipboardData, "server", "up", "down", "listen", "<html>", "<body>"))
&& clipboardData.IndexOf("up") >= 0
&& clipboardData.IndexOf("down") >= 0
&& clipboardData.IndexOf("listen") >= 0
&& clipboardData.IndexOf("<html>") < 0
&& clipboardData.IndexOf("<body>") < 0)
{ {
var fileName = Utils.GetTempPath($"{Utils.GetGUID(false)}.json"); var fileName = Utils.GetTempPath($"{Utils.GetGUID(false)}.json");
File.WriteAllText(fileName, clipboardData); File.WriteAllText(fileName, clipboardData);
@@ -1017,10 +1076,7 @@ namespace v2rayN.Handler
profileItem.remarks = "hysteria_custom"; profileItem.remarks = "hysteria_custom";
} }
//Is naiveproxy configuration //Is naiveproxy configuration
else if (clipboardData.IndexOf("listen") >= 0 else if (Containss(clipboardData, "listen", "proxy", "<html>", "<body>"))
&& clipboardData.IndexOf("proxy") >= 0
&& clipboardData.IndexOf("<html>") < 0
&& clipboardData.IndexOf("<body>") < 0)
{ {
var fileName = Utils.GetTempPath($"{Utils.GetGUID(false)}.json"); var fileName = Utils.GetTempPath($"{Utils.GetGUID(false)}.json");
File.WriteAllText(fileName, clipboardData); File.WriteAllText(fileName, clipboardData);
@@ -1120,7 +1176,7 @@ namespace v2rayN.Handler
public static int AddBatchServers(ref Config config, string clipboardData, string subid, bool isSub) public static int AddBatchServers(ref Config config, string clipboardData, string subid, bool isSub)
{ {
List<ProfileItem> lstOriSub = null; List<ProfileItem>? lstOriSub = null;
if (isSub && !Utils.IsNullOrEmpty(subid)) if (isSub && !Utils.IsNullOrEmpty(subid))
{ {
lstOriSub = LazyConfig.Instance.ProfileItems(subid); lstOriSub = LazyConfig.Instance.ProfileItems(subid);
@@ -1165,7 +1221,7 @@ namespace v2rayN.Handler
return 0; return 0;
} }
SubItem subItem = new SubItem SubItem subItem = new()
{ {
id = string.Empty, id = string.Empty,
remarks = "import_sub", remarks = "import_sub",
@@ -1437,7 +1493,7 @@ namespace v2rayN.Handler
{ {
if (SqliteHelper.Instance.Table<RoutingItem>().Where(t => t.id == routingItem.id).Count() > 0) if (SqliteHelper.Instance.Table<RoutingItem>().Where(t => t.id == routingItem.id).Count() > 0)
{ {
config.routingIndexId = routingItem.id; config.routingBasicItem.routingIndexId = routingItem.id;
} }
Global.reloadCore = true; Global.reloadCore = true;
@@ -1448,7 +1504,7 @@ namespace v2rayN.Handler
} }
public static RoutingItem GetDefaultRouting(ref Config config) public static RoutingItem GetDefaultRouting(ref Config config)
{ {
var item = LazyConfig.Instance.GetRoutingItem(config.routingIndexId); var item = LazyConfig.Instance.GetRoutingItem(config.routingBasicItem.routingIndexId);
if (item is null) if (item is null)
{ {
var item2 = SqliteHelper.Instance.Table<RoutingItem>().FirstOrDefault(t => t.locked == false); var item2 = SqliteHelper.Instance.Table<RoutingItem>().FirstOrDefault(t => t.locked == false);
@@ -1461,13 +1517,16 @@ namespace v2rayN.Handler
public static int InitBuiltinRouting(ref Config config, bool blImportAdvancedRules = false) public static int InitBuiltinRouting(ref Config config, bool blImportAdvancedRules = false)
{ {
if (blImportAdvancedRules || LazyConfig.Instance.RoutingItems().Count <= 0) var items = LazyConfig.Instance.RoutingItems();
if (blImportAdvancedRules || items.Count <= 0)
{ {
var maxSort = items.Count;
//Bypass the mainland //Bypass the mainland
var item2 = new RoutingItem() var item2 = new RoutingItem()
{ {
remarks = "绕过大陆(Whitelist)", remarks = "绕过大陆(Whitelist)",
url = string.Empty, url = string.Empty,
sort = maxSort + 1,
}; };
AddBatchRoutingRules(ref item2, Utils.GetEmbedText(Global.CustomRoutingFileName + "white")); AddBatchRoutingRules(ref item2, Utils.GetEmbedText(Global.CustomRoutingFileName + "white"));
@@ -1476,6 +1535,7 @@ namespace v2rayN.Handler
{ {
remarks = "黑名单(Blacklist)", remarks = "黑名单(Blacklist)",
url = string.Empty, url = string.Empty,
sort = maxSort + 2,
}; };
AddBatchRoutingRules(ref item3, Utils.GetEmbedText(Global.CustomRoutingFileName + "black")); AddBatchRoutingRules(ref item3, Utils.GetEmbedText(Global.CustomRoutingFileName + "black"));
@@ -1484,6 +1544,7 @@ namespace v2rayN.Handler
{ {
remarks = "全局(Global)", remarks = "全局(Global)",
url = string.Empty, url = string.Empty,
sort = maxSort + 3,
}; };
AddBatchRoutingRules(ref item1, Utils.GetEmbedText(Global.CustomRoutingFileName + "global")); AddBatchRoutingRules(ref item1, Utils.GetEmbedText(Global.CustomRoutingFileName + "global"));

View File

@@ -25,7 +25,7 @@ namespace v2rayN.Handler
/// <param name="msg"></param> /// <param name="msg"></param>
/// <param name="content"></param> /// <param name="content"></param>
/// <returns></returns> /// <returns></returns>
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; content = string.Empty;
try try
@@ -43,7 +43,7 @@ namespace v2rayN.Handler
} }
else else
{ {
V2rayConfig v2rayConfig = null; V2rayConfig? v2rayConfig = null;
if (GenerateClientConfigContent(node, false, ref v2rayConfig, out msg) != 0) if (GenerateClientConfigContent(node, false, ref v2rayConfig, out msg) != 0)
{ {
return -1; return -1;
@@ -73,29 +73,29 @@ namespace v2rayN.Handler
{ {
if (blExport) if (blExport)
{ {
if (config.logEnabled) if (config.coreBasicItem.logEnabled)
{ {
v2rayConfig.log.loglevel = config.loglevel; v2rayConfig.log.loglevel = config.coreBasicItem.loglevel;
} }
else else
{ {
v2rayConfig.log.loglevel = config.loglevel; v2rayConfig.log.loglevel = config.coreBasicItem.loglevel;
v2rayConfig.log.access = ""; v2rayConfig.log.access = "";
v2rayConfig.log.error = ""; v2rayConfig.log.error = "";
} }
} }
else else
{ {
if (config.logEnabled) if (config.coreBasicItem.logEnabled)
{ {
var dtNow = DateTime.Now; var dtNow = DateTime.Now;
v2rayConfig.log.loglevel = config.loglevel; v2rayConfig.log.loglevel = config.coreBasicItem.loglevel;
v2rayConfig.log.access = Utils.GetLogPath($"Vaccess_{dtNow.ToString("yyyy-MM-dd")}.txt"); v2rayConfig.log.access = Utils.GetLogPath($"Vaccess_{dtNow:yyyy-MM-dd}.txt");
v2rayConfig.log.error = Utils.GetLogPath($"Verror_{dtNow.ToString("yyyy-MM-dd")}.txt"); v2rayConfig.log.error = Utils.GetLogPath($"Verror_{dtNow:yyyy-MM-dd}.txt");
} }
else else
{ {
v2rayConfig.log.loglevel = config.loglevel; v2rayConfig.log.loglevel = config.coreBasicItem.loglevel;
v2rayConfig.log.access = ""; v2rayConfig.log.access = "";
v2rayConfig.log.error = ""; v2rayConfig.log.error = "";
} }
@@ -114,11 +114,11 @@ namespace v2rayN.Handler
{ {
v2rayConfig.inbounds = new List<Inbounds>(); v2rayConfig.inbounds = new List<Inbounds>();
Inbounds inbound = GetInbound(config.inbound[0], Global.InboundSocks, 0, true); Inbounds? inbound = GetInbound(config.inbound[0], Global.InboundSocks, 0, true);
v2rayConfig.inbounds.Add(inbound); v2rayConfig.inbounds.Add(inbound);
//http //http
Inbounds inbound2 = GetInbound(config.inbound[0], Global.InboundHttp, 1, false); Inbounds? inbound2 = GetInbound(config.inbound[0], Global.InboundHttp, 1, false);
v2rayConfig.inbounds.Add(inbound2); v2rayConfig.inbounds.Add(inbound2);
if (config.inbound[0].allowLANConn) if (config.inbound[0].allowLANConn)
@@ -157,7 +157,7 @@ namespace v2rayN.Handler
return 0; return 0;
} }
private static Inbounds GetInbound(InItem inItem, string tag, int offset, bool bSocks) private static Inbounds? GetInbound(InItem inItem, string tag, int offset, bool bSocks)
{ {
string result = Utils.GetEmbedText(Global.v2raySampleInbound); string result = Utils.GetEmbedText(Global.v2raySampleInbound);
if (Utils.IsNullOrEmpty(result)) if (Utils.IsNullOrEmpty(result))
@@ -187,10 +187,10 @@ namespace v2rayN.Handler
if (v2rayConfig.routing != null if (v2rayConfig.routing != null
&& v2rayConfig.routing.rules != null) && v2rayConfig.routing.rules != null)
{ {
v2rayConfig.routing.domainStrategy = config.domainStrategy; v2rayConfig.routing.domainStrategy = config.routingBasicItem.domainStrategy;
v2rayConfig.routing.domainMatcher = Utils.IsNullOrEmpty(config.domainMatcher) ? null : config.domainMatcher; v2rayConfig.routing.domainMatcher = Utils.IsNullOrEmpty(config.routingBasicItem.domainMatcher) ? null : config.routingBasicItem.domainMatcher;
if (config.enableRoutingAdvanced) if (config.routingBasicItem.enableRoutingAdvanced)
{ {
var routing = ConfigHandler.GetDefaultRouting(ref config); var routing = ConfigHandler.GetDefaultRouting(ref config);
if (routing != null) if (routing != null)
@@ -348,8 +348,8 @@ namespace v2rayN.Handler
} }
//Mux //Mux
outbound.mux.enabled = config.muxEnabled; outbound.mux.enabled = config.coreBasicItem.muxEnabled;
outbound.mux.concurrency = config.muxEnabled ? 8 : -1; outbound.mux.concurrency = config.coreBasicItem.muxEnabled ? 8 : -1;
boundStreamSettings(node, "out", outbound.streamSettings); boundStreamSettings(node, "out", outbound.streamSettings);
@@ -405,7 +405,7 @@ namespace v2rayN.Handler
if (!Utils.IsNullOrEmpty(node.security) if (!Utils.IsNullOrEmpty(node.security)
&& !Utils.IsNullOrEmpty(node.id)) && !Utils.IsNullOrEmpty(node.id))
{ {
SocksUsersItem socksUsersItem = new SocksUsersItem SocksUsersItem socksUsersItem = new()
{ {
user = node.security, user = node.security,
pass = node.id, pass = node.id,
@@ -452,8 +452,8 @@ namespace v2rayN.Handler
usersItem.encryption = node.security; usersItem.encryption = node.security;
//Mux //Mux
outbound.mux.enabled = config.muxEnabled; outbound.mux.enabled = config.coreBasicItem.muxEnabled;
outbound.mux.concurrency = config.muxEnabled ? 8 : -1; outbound.mux.concurrency = config.coreBasicItem.muxEnabled ? 8 : -1;
boundStreamSettings(node, "out", outbound.streamSettings); boundStreamSettings(node, "out", outbound.streamSettings);
@@ -548,15 +548,15 @@ namespace v2rayN.Handler
string host = node.requestHost.TrimEx(); string host = node.requestHost.TrimEx();
string sni = node.sni; string sni = node.sni;
string useragent = ""; string useragent = "";
if (!config.defUserAgent.IsNullOrEmpty()) if (!config.coreBasicItem.defUserAgent.IsNullOrEmpty())
{ {
try try
{ {
useragent = Global.userAgentTxt[config.defUserAgent]; useragent = Global.userAgentTxt[config.coreBasicItem.defUserAgent];
} }
catch (KeyNotFoundException) catch (KeyNotFoundException)
{ {
useragent = config.defUserAgent; useragent = config.coreBasicItem.defUserAgent;
} }
} }
@@ -565,11 +565,11 @@ namespace v2rayN.Handler
{ {
streamSettings.security = node.streamSecurity; streamSettings.security = node.streamSecurity;
TlsSettings tlsSettings = new TlsSettings TlsSettings tlsSettings = new()
{ {
allowInsecure = Utils.ToBool(node.allowInsecure.IsNullOrEmpty() ? config.defAllowInsecure.ToString().ToLower() : node.allowInsecure), allowInsecure = Utils.ToBool(node.allowInsecure.IsNullOrEmpty() ? config.coreBasicItem.defAllowInsecure.ToString().ToLower() : node.allowInsecure),
alpn = node.GetAlpn(), alpn = node.GetAlpn(),
fingerprint = node.fingerprint.IsNullOrEmpty() ? config.defFingerprint : node.fingerprint fingerprint = node.fingerprint.IsNullOrEmpty() ? config.coreBasicItem.defFingerprint : node.fingerprint
}; };
if (!string.IsNullOrWhiteSpace(sni)) if (!string.IsNullOrWhiteSpace(sni))
{ {
@@ -587,11 +587,11 @@ namespace v2rayN.Handler
{ {
streamSettings.security = node.streamSecurity; streamSettings.security = node.streamSecurity;
TlsSettings xtlsSettings = new TlsSettings TlsSettings xtlsSettings = new()
{ {
allowInsecure = Utils.ToBool(node.allowInsecure.IsNullOrEmpty() ? config.defAllowInsecure.ToString().ToLower() : node.allowInsecure), allowInsecure = Utils.ToBool(node.allowInsecure.IsNullOrEmpty() ? config.coreBasicItem.defAllowInsecure.ToString().ToLower() : node.allowInsecure),
alpn = node.GetAlpn(), alpn = node.GetAlpn(),
fingerprint = node.fingerprint.IsNullOrEmpty() ? config.defFingerprint : node.fingerprint fingerprint = node.fingerprint.IsNullOrEmpty() ? config.coreBasicItem.defFingerprint : node.fingerprint
}; };
if (!string.IsNullOrWhiteSpace(sni)) if (!string.IsNullOrWhiteSpace(sni))
{ {
@@ -608,7 +608,7 @@ namespace v2rayN.Handler
switch (node.GetNetwork()) switch (node.GetNetwork())
{ {
case "kcp": case "kcp":
KcpSettings kcpSettings = new KcpSettings KcpSettings kcpSettings = new()
{ {
mtu = config.kcpItem.mtu, mtu = config.kcpItem.mtu,
tti = config.kcpItem.tti tti = config.kcpItem.tti
@@ -644,12 +644,8 @@ namespace v2rayN.Handler
break; break;
//ws //ws
case "ws": case "ws":
WsSettings wsSettings = new WsSettings WsSettings wsSettings = new();
{ wsSettings.headers = new Headers();
};
wsSettings.headers = new Headers
{
};
string path = node.path; string path = node.path;
if (!string.IsNullOrWhiteSpace(host)) if (!string.IsNullOrWhiteSpace(host))
{ {
@@ -675,7 +671,7 @@ namespace v2rayN.Handler
break; break;
//h2 //h2
case "h2": case "h2":
HttpSettings httpSettings = new HttpSettings(); HttpSettings httpSettings = new();
if (!string.IsNullOrWhiteSpace(host)) if (!string.IsNullOrWhiteSpace(host))
{ {
@@ -691,7 +687,7 @@ namespace v2rayN.Handler
break; break;
//quic //quic
case "quic": case "quic":
QuicSettings quicsettings = new QuicSettings QuicSettings quicsettings = new()
{ {
security = host, security = host,
key = node.path, key = node.path,
@@ -714,7 +710,7 @@ namespace v2rayN.Handler
} }
break; break;
case "grpc": case "grpc":
var grpcSettings = new GrpcSettings GrpcSettings grpcSettings = new()
{ {
serviceName = node.path, serviceName = node.path,
multiMode = (node.headerType == Global.GrpcmultiMode), multiMode = (node.headerType == Global.GrpcmultiMode),
@@ -730,7 +726,7 @@ namespace v2rayN.Handler
//tcp //tcp
if (node.headerType.Equals(Global.TcpHeaderHttp)) if (node.headerType.Equals(Global.TcpHeaderHttp))
{ {
TcpSettings tcpSettings = new TcpSettings TcpSettings tcpSettings = new()
{ {
header = new Header header = new Header
{ {
@@ -799,7 +795,7 @@ namespace v2rayN.Handler
} }
else else
{ {
List<string> servers = new List<string>(); List<string> servers = new();
string[] arrDNS = config.remoteDNS.Split(','); string[] arrDNS = config.remoteDNS.Split(',');
foreach (string str in arrDNS) foreach (string str in arrDNS)
@@ -825,12 +821,12 @@ namespace v2rayN.Handler
private static int statistic(Config config, ref V2rayConfig v2rayConfig) private static int statistic(Config config, ref V2rayConfig v2rayConfig)
{ {
if (config.enableStatistics) if (config.guiItem.enableStatistics)
{ {
string tag = Global.InboundAPITagName; string tag = Global.InboundAPITagName;
API apiObj = new API(); API apiObj = new();
Policy policyObj = new Policy(); Policy policyObj = new();
SystemPolicy policySystemSetting = new SystemPolicy(); SystemPolicy policySystemSetting = new();
string[] services = { "StatsService" }; string[] services = { "StatsService" };
@@ -847,8 +843,8 @@ namespace v2rayN.Handler
if (!v2rayConfig.inbounds.Exists(item => item.tag == tag)) if (!v2rayConfig.inbounds.Exists(item => item.tag == tag))
{ {
Inbounds apiInbound = new Inbounds(); Inbounds apiInbound = new();
Inboundsettings apiInboundSettings = new Inboundsettings(); Inboundsettings apiInboundSettings = new();
apiInbound.tag = tag; apiInbound.tag = tag;
apiInbound.listen = Global.Loopback; apiInbound.listen = Global.Loopback;
apiInbound.port = Global.statePort; apiInbound.port = Global.statePort;
@@ -860,7 +856,7 @@ namespace v2rayN.Handler
if (!v2rayConfig.routing.rules.Exists(item => item.outboundTag == tag)) if (!v2rayConfig.routing.rules.Exists(item => item.outboundTag == tag))
{ {
RulesItem apiRoutingRule = new RulesItem RulesItem apiRoutingRule = new()
{ {
inboundTag = new List<string> { tag }, inboundTag = new List<string> { tag },
outboundTag = tag, outboundTag = tag,
@@ -957,7 +953,7 @@ namespace v2rayN.Handler
return 0; return 0;
} }
public static int GenerateClientConfigContent(ProfileItem node, bool blExport, ref V2rayConfig v2rayConfig, out string msg) public static int GenerateClientConfigContent(ProfileItem node, bool blExport, ref V2rayConfig? v2rayConfig, out string msg)
{ {
try try
{ {
@@ -1034,7 +1030,7 @@ namespace v2rayN.Handler
return -1; return -1;
} }
V2rayConfig v2rayConfig = Utils.FromJson<V2rayConfig>(result); V2rayConfig? v2rayConfig = Utils.FromJson<V2rayConfig>(result);
if (v2rayConfig == null) if (v2rayConfig == null)
{ {
msg = ResUI.FailedGenDefaultConfiguration; msg = ResUI.FailedGenDefaultConfiguration;
@@ -1123,10 +1119,10 @@ namespace v2rayN.Handler
#region Import (export) client/server configuration #region Import (export) client/server configuration
public static ProfileItem ImportFromClientConfig(string fileName, out string msg) public static ProfileItem? ImportFromClientConfig(string fileName, out string msg)
{ {
msg = string.Empty; msg = string.Empty;
ProfileItem profileItem = new ProfileItem(); ProfileItem profileItem = new();
try try
{ {
@@ -1137,7 +1133,7 @@ namespace v2rayN.Handler
return null; return null;
} }
V2rayConfig v2rayConfig = Utils.FromJson<V2rayConfig>(result); V2rayConfig? v2rayConfig = Utils.FromJson<V2rayConfig>(result);
if (v2rayConfig == null) if (v2rayConfig == null)
{ {
msg = ResUI.FailedConversionConfiguration; msg = ResUI.FailedConversionConfiguration;
@@ -1262,10 +1258,10 @@ namespace v2rayN.Handler
return profileItem; return profileItem;
} }
public static ProfileItem ImportFromServerConfig(string fileName, out string msg) public static ProfileItem? ImportFromServerConfig(string fileName, out string msg)
{ {
msg = string.Empty; msg = string.Empty;
ProfileItem profileItem = new ProfileItem(); ProfileItem profileItem = new();
try try
{ {
@@ -1276,7 +1272,7 @@ namespace v2rayN.Handler
return null; return null;
} }
V2rayConfig v2rayConfig = Utils.FromJson<V2rayConfig>(result); V2rayConfig? v2rayConfig = Utils.FromJson<V2rayConfig>(result);
if (v2rayConfig == null) if (v2rayConfig == null)
{ {
msg = ResUI.FailedConversionConfiguration; msg = ResUI.FailedConversionConfiguration;
@@ -1401,7 +1397,7 @@ namespace v2rayN.Handler
public static int Export2ClientConfig(ProfileItem node, string fileName, out string msg) public static int Export2ClientConfig(ProfileItem node, string fileName, out string msg)
{ {
V2rayConfig v2rayConfig = null; V2rayConfig? v2rayConfig = null;
if (GenerateClientConfigContent(node, true, ref v2rayConfig, out msg) != 0) if (GenerateClientConfigContent(node, true, ref v2rayConfig, out msg) != 0)
{ {
return -1; return -1;
@@ -1440,14 +1436,14 @@ namespace v2rayN.Handler
return ""; return "";
} }
V2rayConfig v2rayConfig = Utils.FromJson<V2rayConfig>(result); V2rayConfig? v2rayConfig = Utils.FromJson<V2rayConfig>(result);
if (v2rayConfig == null) if (v2rayConfig == null)
{ {
msg = ResUI.FailedGenDefaultConfiguration; msg = ResUI.FailedGenDefaultConfiguration;
return ""; return "";
} }
List<IPEndPoint> lstIpEndPoints = new List<IPEndPoint>(); List<IPEndPoint> lstIpEndPoints = new();
List<TcpConnectionInformation> lstTcpConns = new List<TcpConnectionInformation>(); List<TcpConnectionInformation> lstTcpConns = new();
try try
{ {
lstIpEndPoints.AddRange(IPGlobalProperties.GetIPGlobalProperties().GetActiveTcpListeners()); lstIpEndPoints.AddRange(IPGlobalProperties.GetIPGlobalProperties().GetActiveTcpListeners());
@@ -1477,7 +1473,7 @@ namespace v2rayN.Handler
{ {
continue; continue;
} }
if (it.configType == EConfigType.VMess || it.configType == EConfigType.VLESS) if (it.configType is EConfigType.VMess or EConfigType.VLESS)
{ {
var item2 = LazyConfig.Instance.GetProfileItem(it.indexId); var item2 = LazyConfig.Instance.GetProfileItem(it.indexId);
if (item2 is null || Utils.IsNullOrEmpty(item2.id) || !Utils.IsGuidByParse(item2.id)) if (item2 is null || Utils.IsNullOrEmpty(item2.id) || !Utils.IsGuidByParse(item2.id))
@@ -1513,7 +1509,7 @@ namespace v2rayN.Handler
it.allowTest = true; it.allowTest = true;
//inbound //inbound
Inbounds inbound = new Inbounds Inbounds inbound = new()
{ {
listen = Global.Loopback, listen = Global.Loopback,
port = port, port = port,
@@ -1523,7 +1519,7 @@ namespace v2rayN.Handler
v2rayConfig.inbounds.Add(inbound); v2rayConfig.inbounds.Add(inbound);
//outbound //outbound
V2rayConfig v2rayConfigCopy = Utils.FromJson<V2rayConfig>(result); V2rayConfig? v2rayConfigCopy = Utils.FromJson<V2rayConfig>(result);
var item = LazyConfig.Instance.GetProfileItem(it.indexId); var item = LazyConfig.Instance.GetProfileItem(it.indexId);
if (item is null) if (item is null)
{ {
@@ -1540,7 +1536,7 @@ namespace v2rayN.Handler
v2rayConfig.outbounds.Add(v2rayConfigCopy.outbounds[0]); v2rayConfig.outbounds.Add(v2rayConfigCopy.outbounds[0]);
//rule //rule
RulesItem rule = new RulesItem RulesItem rule = new()
{ {
inboundTag = new List<string> { inbound.tag }, inboundTag = new List<string> { inbound.tag },
outboundTag = v2rayConfigCopy.outbounds[0].tag, outboundTag = v2rayConfigCopy.outbounds[0].tag,

View File

@@ -12,14 +12,17 @@ namespace v2rayN.Handler
class CoreHandler class CoreHandler
{ {
private static string _coreCConfigRes = Global.coreConfigFileName; private static string _coreCConfigRes = Global.coreConfigFileName;
private CoreInfo _coreInfo; private CoreInfo? _coreInfo;
private int _processId = 0; private int _processId = 0;
private Process _process; private Process? _process;
Action<bool, string> _updateFunc; Action<bool, string> _updateFunc;
public CoreHandler(Action<bool, string> update) public CoreHandler(Action<bool, string> update)
{ {
_updateFunc = update; _updateFunc = update;
Environment.SetEnvironmentVariable("v2ray.location.asset", Utils.GetBinPath(""), EnvironmentVariableTarget.Process);
Environment.SetEnvironmentVariable("xray.location.asset", Utils.GetBinPath(""), EnvironmentVariableTarget.Process);
} }
public void LoadCore(Config config) public void LoadCore(Config config)
@@ -105,7 +108,7 @@ namespace v2rayN.Handler
Process[] existing = Process.GetProcessesByName(vName); Process[] existing = Process.GetProcessesByName(vName);
foreach (Process p in existing) foreach (Process p in existing)
{ {
string path = p.MainModule.FileName; string? path = p.MainModule?.FileName;
if (path == $"{Utils.GetBinPath(vName, _coreInfo.coreType)}.exe") if (path == $"{Utils.GetBinPath(vName, _coreInfo.coreType)}.exe")
{ {
KillProcess(p); KillProcess(p);
@@ -170,7 +173,8 @@ namespace v2rayN.Handler
string fileName = CoreFindexe(_coreInfo); string fileName = CoreFindexe(_coreInfo);
if (fileName == "") return; if (fileName == "") return;
Process p = new Process var displayLog = node.configType != EConfigType.Custom || node.displayLog;
Process p = new()
{ {
StartInfo = new ProcessStartInfo StartInfo = new ProcessStartInfo
{ {
@@ -178,18 +182,18 @@ namespace v2rayN.Handler
Arguments = _coreInfo.arguments, Arguments = _coreInfo.arguments,
WorkingDirectory = Utils.GetConfigPath(), WorkingDirectory = Utils.GetConfigPath(),
UseShellExecute = false, UseShellExecute = false,
RedirectStandardOutput = node.displayLog, RedirectStandardOutput = displayLog,
RedirectStandardError = node.displayLog, RedirectStandardError = displayLog,
CreateNoWindow = true, CreateNoWindow = true,
StandardOutputEncoding = node.displayLog ? Encoding.UTF8 : null, StandardOutputEncoding = displayLog ? Encoding.UTF8 : null,
StandardErrorEncoding = node.displayLog ? Encoding.UTF8 : null, StandardErrorEncoding = displayLog ? Encoding.UTF8 : null,
} }
}; };
if (node.displayLog) if (displayLog)
{ {
p.OutputDataReceived += (sender, e) => p.OutputDataReceived += (sender, e) =>
{ {
if (!String.IsNullOrEmpty(e.Data)) if (!string.IsNullOrEmpty(e.Data))
{ {
string msg = e.Data + Environment.NewLine; string msg = e.Data + Environment.NewLine;
ShowMsg(false, msg); ShowMsg(false, msg);
@@ -197,7 +201,7 @@ namespace v2rayN.Handler
}; };
} }
p.Start(); p.Start();
if (node.displayLog) if (displayLog)
{ {
p.BeginOutputReadLine(); p.BeginOutputReadLine();
} }
@@ -205,7 +209,7 @@ namespace v2rayN.Handler
if (p.WaitForExit(1000)) if (p.WaitForExit(1000))
{ {
throw new Exception(node.displayLog ? p.StandardError.ReadToEnd() : "启动进程失败并退出 (Failed to start the process and exited)"); throw new Exception(displayLog ? p.StandardError.ReadToEnd() : "启动进程失败并退出 (Failed to start the process and exited)");
} }
Global.processJob.AddProcess(p.Handle); Global.processJob.AddProcess(p.Handle);
@@ -228,7 +232,7 @@ namespace v2rayN.Handler
string fileName = CoreFindexe(coreInfo); string fileName = CoreFindexe(coreInfo);
if (fileName == "") return -1; if (fileName == "") return -1;
Process p = new Process Process p = new()
{ {
StartInfo = new ProcessStartInfo StartInfo = new ProcessStartInfo
{ {

View File

@@ -16,7 +16,7 @@ namespace v2rayN.Handler
{ {
public event EventHandler<ResultEventArgs> UpdateCompleted; public event EventHandler<ResultEventArgs> UpdateCompleted;
public event ErrorEventHandler Error; public event ErrorEventHandler? Error;
public class ResultEventArgs : EventArgs public class ResultEventArgs : EventArgs
@@ -33,20 +33,13 @@ namespace v2rayN.Handler
public async Task<int> DownloadDataAsync(string url, WebProxy webProxy, int downloadTimeout, Action<bool, string> update) public async Task<int> DownloadDataAsync(string url, WebProxy webProxy, int downloadTimeout, Action<bool, string> update)
{ {
var hasValue = false;
try try
{ {
Utils.SetSecurityProtocol(LazyConfig.Instance.GetConfig().enableSecurityProtocolTls13); Utils.SetSecurityProtocol(LazyConfig.Instance.GetConfig().guiItem.enableSecurityProtocolTls13);
var client = new HttpClient(new SocketsHttpHandler()
{
Proxy = webProxy
});
var progress = new Progress<string>(); var progress = new Progress<string>();
progress.ProgressChanged += (sender, value) => progress.ProgressChanged += (sender, value) =>
{ {
hasValue = true;
if (update != null) if (update != null)
{ {
string msg = $"{value}"; string msg = $"{value}";
@@ -54,16 +47,12 @@ namespace v2rayN.Handler
} }
}; };
var cancellationToken = new CancellationTokenSource(); await DownloaderHelper.Instance.DownloadDataAsync4Speed(webProxy,
cancellationToken.CancelAfter(downloadTimeout * 1000);
await HttpClientHelper.GetInstance().DownloadDataAsync4Speed(client,
url, url,
progress, progress,
cancellationToken.Token); downloadTimeout);
} }
catch (Exception ex) catch (Exception ex)
{
if (!hasValue)
{ {
update(false, ex.Message); update(false, ex.Message);
if (ex.InnerException != null) if (ex.InnerException != null)
@@ -71,7 +60,6 @@ namespace v2rayN.Handler
update(false, ex.InnerException.Message); update(false, ex.InnerException.Message);
} }
} }
}
return 0; return 0;
} }
@@ -79,30 +67,25 @@ namespace v2rayN.Handler
{ {
try try
{ {
Utils.SetSecurityProtocol(LazyConfig.Instance.GetConfig().enableSecurityProtocolTls13); Utils.SetSecurityProtocol(LazyConfig.Instance.GetConfig().guiItem.enableSecurityProtocolTls13);
UpdateCompleted?.Invoke(this, new ResultEventArgs(false, ResUI.Downloading)); UpdateCompleted?.Invoke(this, new ResultEventArgs(false, ResUI.Downloading));
var client = new HttpClient(new SocketsHttpHandler()
{
Proxy = GetWebProxy(blProxy)
});
var progress = new Progress<double>(); var progress = new Progress<double>();
progress.ProgressChanged += (sender, value) => progress.ProgressChanged += (sender, value) =>
{ {
if (UpdateCompleted != null) if (UpdateCompleted != null)
{ {
string msg = $"...{value}%"; string msg = $"...{value}%";
UpdateCompleted(this, new ResultEventArgs(value > 100 ? true : false, msg)); UpdateCompleted(this, new ResultEventArgs(value > 100, msg));
} }
}; };
var cancellationToken = new CancellationTokenSource(); var webProxy = GetWebProxy(blProxy);
_ = HttpClientHelper.GetInstance().DownloadFileAsync(client, _ = DownloaderHelper.Instance.DownloadFileAsync(webProxy,
url, url,
Utils.GetTempPath(Utils.GetDownloadFileName(url)), Utils.GetTempPath(Utils.GetDownloadFileName(url)),
progress, progress,
cancellationToken.Token); downloadTimeout);
} }
catch (Exception ex) catch (Exception ex)
{ {
@@ -116,20 +99,20 @@ namespace v2rayN.Handler
} }
} }
public async Task<string> UrlRedirectAsync(string url, bool blProxy) public async Task<string?> UrlRedirectAsync(string url, bool blProxy)
{ {
Utils.SetSecurityProtocol(LazyConfig.Instance.GetConfig().enableSecurityProtocolTls13); Utils.SetSecurityProtocol(LazyConfig.Instance.GetConfig().guiItem.enableSecurityProtocolTls13);
var webRequestHandler = new SocketsHttpHandler var webRequestHandler = new SocketsHttpHandler
{ {
AllowAutoRedirect = false, AllowAutoRedirect = false,
Proxy = GetWebProxy(blProxy) Proxy = GetWebProxy(blProxy)
}; };
HttpClient client = new HttpClient(webRequestHandler); HttpClient client = new(webRequestHandler);
HttpResponseMessage response = await client.GetAsync(url); HttpResponseMessage response = await client.GetAsync(url);
if (response.StatusCode.ToString() == "Redirect") if (response.StatusCode.ToString() == "Redirect")
{ {
return response.Headers.Location.ToString(); return response.Headers.Location?.ToString();
} }
else else
{ {
@@ -138,15 +121,77 @@ namespace v2rayN.Handler
} }
} }
public async Task<string?> TryDownloadString(string url, bool blProxy, string userAgent)
{
try
{
var result1 = await DownloadStringAsync(url, blProxy, userAgent);
if (!Utils.IsNullOrEmpty(result1))
{
return result1;
}
}
catch (Exception ex)
{
Utils.SaveLog(ex.Message, ex);
Error?.Invoke(this, new ErrorEventArgs(ex));
if (ex.InnerException != null)
{
Error?.Invoke(this, new ErrorEventArgs(ex.InnerException));
}
}
try
{
var result2 = await DownloadStringViaDownloader(url, blProxy, userAgent);
if (!Utils.IsNullOrEmpty(result2))
{
return result2;
}
}
catch (Exception ex)
{
Utils.SaveLog(ex.Message, ex);
Error?.Invoke(this, new ErrorEventArgs(ex));
if (ex.InnerException != null)
{
Error?.Invoke(this, new ErrorEventArgs(ex.InnerException));
}
}
try
{
using var wc = new WebClient();
wc.Proxy = GetWebProxy(blProxy);
var result3 = await wc.DownloadStringTaskAsync(url);
if (!Utils.IsNullOrEmpty(result3))
{
return result3;
}
}
catch (Exception ex)
{
Utils.SaveLog(ex.Message, ex);
Error?.Invoke(this, new ErrorEventArgs(ex));
if (ex.InnerException != null)
{
Error?.Invoke(this, new ErrorEventArgs(ex.InnerException));
}
}
return null;
}
/// <summary> /// <summary>
/// DownloadString /// DownloadString
/// </summary> /// </summary>
/// <param name="url"></param> /// <param name="url"></param>
public async Task<string> DownloadStringAsync(string url, bool blProxy, string userAgent) public async Task<string?> DownloadStringAsync(string url, bool blProxy, string userAgent)
{ {
try try
{ {
Utils.SetSecurityProtocol(LazyConfig.Instance.GetConfig().enableSecurityProtocolTls13); Utils.SetSecurityProtocol(LazyConfig.Instance.GetConfig().guiItem.enableSecurityProtocolTls13);
var client = new HttpClient(new SocketsHttpHandler() var client = new HttpClient(new SocketsHttpHandler()
{ {
Proxy = GetWebProxy(blProxy) Proxy = GetWebProxy(blProxy)
@@ -158,7 +203,7 @@ namespace v2rayN.Handler
} }
client.DefaultRequestHeaders.UserAgent.TryParseAdd(userAgent); client.DefaultRequestHeaders.UserAgent.TryParseAdd(userAgent);
Uri uri = new Uri(url); Uri uri = new(url);
//Authorization Header //Authorization Header
if (!Utils.IsNullOrEmpty(uri.UserInfo)) if (!Utils.IsNullOrEmpty(uri.UserInfo))
{ {
@@ -183,7 +228,39 @@ namespace v2rayN.Handler
return null; return null;
} }
public int RunAvailabilityCheck(WebProxy webProxy) /// <summary>
/// DownloadString
/// </summary>
/// <param name="url"></param>
public async Task<string?> DownloadStringViaDownloader(string url, bool blProxy, string userAgent)
{
try
{
Utils.SetSecurityProtocol(LazyConfig.Instance.GetConfig().guiItem.enableSecurityProtocolTls13);
var webProxy = GetWebProxy(blProxy);
if (Utils.IsNullOrEmpty(userAgent))
{
userAgent = $"{Utils.GetVersion(false)}";
}
var result = await DownloaderHelper.Instance.DownloadStringAsync(webProxy, url, userAgent, 30);
return result;
}
catch (Exception ex)
{
Utils.SaveLog(ex.Message, ex);
Error?.Invoke(this, new ErrorEventArgs(ex));
if (ex.InnerException != null)
{
Error?.Invoke(this, new ErrorEventArgs(ex.InnerException));
}
}
return null;
}
public int RunAvailabilityCheck(WebProxy? webProxy)
{ {
try try
{ {
@@ -196,7 +273,7 @@ namespace v2rayN.Handler
try try
{ {
var config = LazyConfig.Instance.GetConfig(); var config = LazyConfig.Instance.GetConfig();
string status = GetRealPingTime(config.constItem.speedPingTestUrl, webProxy, 10, out int responseTime); string status = GetRealPingTime(config.speedTestItem.speedPingTestUrl, webProxy, 10, out int responseTime);
bool noError = Utils.IsNullOrEmpty(status); bool noError = Utils.IsNullOrEmpty(status);
return noError ? responseTime : -1; return noError ? responseTime : -1;
} }
@@ -223,12 +300,11 @@ namespace v2rayN.Handler
myHttpWebRequest.Timeout = downloadTimeout * 1000; myHttpWebRequest.Timeout = downloadTimeout * 1000;
myHttpWebRequest.Proxy = webProxy; myHttpWebRequest.Proxy = webProxy;
Stopwatch timer = new Stopwatch(); Stopwatch timer = new();
timer.Start(); timer.Start();
HttpWebResponse myHttpWebResponse = (HttpWebResponse)myHttpWebRequest.GetResponse(); HttpWebResponse myHttpWebResponse = (HttpWebResponse)myHttpWebRequest.GetResponse();
if (myHttpWebResponse.StatusCode != HttpStatusCode.OK if (myHttpWebResponse.StatusCode is not HttpStatusCode.OK and not HttpStatusCode.NoContent)
&& myHttpWebResponse.StatusCode != HttpStatusCode.NoContent)
{ {
msg = myHttpWebResponse.StatusDescription; msg = myHttpWebResponse.StatusDescription;
} }
@@ -245,7 +321,7 @@ namespace v2rayN.Handler
return msg; return msg;
} }
private WebProxy GetWebProxy(bool blProxy) private WebProxy? GetWebProxy(bool blProxy)
{ {
if (!blProxy) if (!blProxy)
{ {
@@ -262,11 +338,11 @@ namespace v2rayN.Handler
private bool SocketCheck(string ip, int port) private bool SocketCheck(string ip, int port)
{ {
Socket sock = null; Socket? sock = null;
try try
{ {
IPAddress ipa = IPAddress.Parse(ip); IPAddress ipa = IPAddress.Parse(ip);
IPEndPoint point = new IPEndPoint(ipa, port); IPEndPoint point = new(ipa, port);
sock = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); sock = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
sock.Connect(point); sock.Connect(point);
return true; return true;

View File

@@ -5,7 +5,7 @@ namespace v2rayN.Handler
{ {
public sealed class LazyConfig public sealed class LazyConfig
{ {
private static readonly Lazy<LazyConfig> _instance = new Lazy<LazyConfig>(() => new()); private static readonly Lazy<LazyConfig> _instance = new(() => new());
private Config _config; private Config _config;
private List<CoreInfo> coreInfos; private List<CoreInfo> coreInfos;
@@ -17,11 +17,12 @@ namespace v2rayN.Handler
SqliteHelper.Instance.CreateTable<ProfileItem>(); SqliteHelper.Instance.CreateTable<ProfileItem>();
SqliteHelper.Instance.CreateTable<ServerStatItem>(); SqliteHelper.Instance.CreateTable<ServerStatItem>();
SqliteHelper.Instance.CreateTable<RoutingItem>(); SqliteHelper.Instance.CreateTable<RoutingItem>();
SqliteHelper.Instance.CreateTable<ProfileExItem>();
} }
#region Config #region Config
public void SetConfig(ref Config config) public void SetConfig(Config config)
{ {
_config = config; _config = config;
} }
@@ -81,6 +82,18 @@ namespace v2rayN.Handler
return SqliteHelper.Instance.Table<ProfileItem>().Where(t => t.subid == subid).ToList(); return SqliteHelper.Instance.Table<ProfileItem>().Where(t => t.subid == subid).ToList();
} }
} }
public List<string> ProfileItemIndexs(string subid)
{
if (Utils.IsNullOrEmpty(subid))
{
return SqliteHelper.Instance.Table<ProfileItem>().Select(t => t.indexId).ToList();
}
else
{
return SqliteHelper.Instance.Table<ProfileItem>().Where(t => t.subid == subid).Select(t => t.indexId).ToList();
}
}
public List<ProfileItemModel> ProfileItems(string subid, string filter) public List<ProfileItemModel> ProfileItems(string subid, string filter)
{ {
@@ -101,12 +114,11 @@ namespace v2rayN.Handler
} }
sql += $" and a.remarks like '%{filter}%'"; sql += $" and a.remarks like '%{filter}%'";
} }
sql += " order by a.sort";
return SqliteHelper.Instance.Query<ProfileItemModel>(sql).ToList(); return SqliteHelper.Instance.Query<ProfileItemModel>(sql).ToList();
} }
public ProfileItem GetProfileItem(string indexId) public ProfileItem? GetProfileItem(string indexId)
{ {
if (Utils.IsNullOrEmpty(indexId)) if (Utils.IsNullOrEmpty(indexId))
{ {
@@ -115,31 +127,9 @@ namespace v2rayN.Handler
return SqliteHelper.Instance.Table<ProfileItem>().FirstOrDefault(it => it.indexId == indexId); return SqliteHelper.Instance.Table<ProfileItem>().FirstOrDefault(it => it.indexId == indexId);
} }
public Task SetTestResult(string indexId, string delayVal, string speedVal)
{
string sql = string.Empty;
if (!Utils.IsNullOrEmpty(delayVal) && !Utils.IsNullOrEmpty(speedVal))
{
int.TryParse(delayVal, out int delay);
decimal.TryParse(speedVal, out decimal speed);
sql = $"update ProfileItem set delay={delay},speed={speed} where indexId = '{indexId}'";
}
else if (!Utils.IsNullOrEmpty(delayVal))
{
int.TryParse(delayVal, out int delay);
sql = $"update ProfileItem set delay={delay} where indexId = '{indexId}'";
}
else if (!Utils.IsNullOrEmpty(speedVal))
{
decimal.TryParse(speedVal, out decimal speed);
sql = $"update ProfileItem set speed={speed} where indexId = '{indexId}'";
}
return SqliteHelper.Instance.ExecuteAsync(sql);
}
public List<RoutingItem> RoutingItems() public List<RoutingItem> RoutingItems()
{ {
return SqliteHelper.Instance.Table<RoutingItem>().Where(it => it.locked == false).ToList(); return SqliteHelper.Instance.Table<RoutingItem>().Where(it => it.locked == false).OrderBy(t => t.sort).ToList();
} }
public RoutingItem GetRoutingItem(string id) public RoutingItem GetRoutingItem(string id)
{ {
@@ -183,7 +173,7 @@ namespace v2rayN.Handler
return item.coreType; return item.coreType;
} }
public CoreInfo GetCoreInfo(ECoreType coreType) public CoreInfo? GetCoreInfo(ECoreType coreType)
{ {
if (coreInfos == null) if (coreInfos == null)
{ {
@@ -192,7 +182,7 @@ namespace v2rayN.Handler
return coreInfos.Where(t => t.coreType == coreType).FirstOrDefault(); return coreInfos.Where(t => t.coreType == coreType).FirstOrDefault();
} }
public List<CoreInfo> GetCoreInfos() public List<CoreInfo>? GetCoreInfos()
{ {
if (coreInfos == null) if (coreInfos == null)
{ {
@@ -203,13 +193,13 @@ namespace v2rayN.Handler
private void InitCoreInfo() private void InitCoreInfo()
{ {
coreInfos = new List<CoreInfo>(); coreInfos = new(16);
coreInfos.Add(new CoreInfo coreInfos.Add(new CoreInfo
{ {
coreType = ECoreType.v2rayN, coreType = ECoreType.v2rayN,
coreUrl = Global.NUrl, coreUrl = Global.NUrl,
coreReleaseApiUrl = Global.NUrl.Replace(@"https://github.com", @"https://api.github.com/repos"), coreReleaseApiUrl = Global.NUrl.Replace(Global.githubUrl, Global.githubApiUrl),
coreDownloadUrl32 = Global.NUrl + "/download/{0}/v2rayN.zip", coreDownloadUrl32 = Global.NUrl + "/download/{0}/v2rayN.zip",
coreDownloadUrl64 = Global.NUrl + "/download/{0}/v2rayN.zip", coreDownloadUrl64 = Global.NUrl + "/download/{0}/v2rayN.zip",
}); });
@@ -220,7 +210,7 @@ namespace v2rayN.Handler
coreExes = new List<string> { "wv2ray", "v2ray" }, coreExes = new List<string> { "wv2ray", "v2ray" },
arguments = "", arguments = "",
coreUrl = Global.v2flyCoreUrl, coreUrl = Global.v2flyCoreUrl,
coreReleaseApiUrl = Global.v2flyCoreUrl.Replace(@"https://github.com", @"https://api.github.com/repos"), coreReleaseApiUrl = Global.v2flyCoreUrl.Replace(Global.githubUrl, Global.githubApiUrl),
coreDownloadUrl32 = Global.v2flyCoreUrl + "/download/{0}/v2ray-windows-{1}.zip", coreDownloadUrl32 = Global.v2flyCoreUrl + "/download/{0}/v2ray-windows-{1}.zip",
coreDownloadUrl64 = Global.v2flyCoreUrl + "/download/{0}/v2ray-windows-{1}.zip", coreDownloadUrl64 = Global.v2flyCoreUrl + "/download/{0}/v2ray-windows-{1}.zip",
match = "V2Ray", match = "V2Ray",
@@ -234,7 +224,7 @@ namespace v2rayN.Handler
coreExes = new List<string> { "SagerNet", "v2ray" }, coreExes = new List<string> { "SagerNet", "v2ray" },
arguments = "run", arguments = "run",
coreUrl = Global.SagerNetCoreUrl, coreUrl = Global.SagerNetCoreUrl,
coreReleaseApiUrl = Global.SagerNetCoreUrl.Replace(@"https://github.com", @"https://api.github.com/repos"), coreReleaseApiUrl = Global.SagerNetCoreUrl.Replace(Global.githubUrl, Global.githubApiUrl),
coreDownloadUrl32 = Global.SagerNetCoreUrl + "/download/{0}/v2ray-windows-{1}.zip", coreDownloadUrl32 = Global.SagerNetCoreUrl + "/download/{0}/v2ray-windows-{1}.zip",
coreDownloadUrl64 = Global.SagerNetCoreUrl + "/download/{0}/v2ray-windows-{1}.zip", coreDownloadUrl64 = Global.SagerNetCoreUrl + "/download/{0}/v2ray-windows-{1}.zip",
match = "V2Ray", match = "V2Ray",
@@ -248,7 +238,7 @@ namespace v2rayN.Handler
coreExes = new List<string> { "v2ray" }, coreExes = new List<string> { "v2ray" },
arguments = "run", arguments = "run",
coreUrl = Global.v2flyCoreUrl, coreUrl = Global.v2flyCoreUrl,
coreReleaseApiUrl = Global.v2flyCoreUrl.Replace(@"https://github.com", @"https://api.github.com/repos"), coreReleaseApiUrl = Global.v2flyCoreUrl.Replace(Global.githubUrl, Global.githubApiUrl),
coreDownloadUrl32 = Global.v2flyCoreUrl + "/download/{0}/v2ray-windows-{1}.zip", coreDownloadUrl32 = Global.v2flyCoreUrl + "/download/{0}/v2ray-windows-{1}.zip",
coreDownloadUrl64 = Global.v2flyCoreUrl + "/download/{0}/v2ray-windows-{1}.zip", coreDownloadUrl64 = Global.v2flyCoreUrl + "/download/{0}/v2ray-windows-{1}.zip",
match = "V2Ray", match = "V2Ray",
@@ -262,7 +252,7 @@ namespace v2rayN.Handler
coreExes = new List<string> { "xray", "wxray" }, coreExes = new List<string> { "xray", "wxray" },
arguments = "", arguments = "",
coreUrl = Global.xrayCoreUrl, coreUrl = Global.xrayCoreUrl,
coreReleaseApiUrl = Global.xrayCoreUrl.Replace(@"https://github.com", @"https://api.github.com/repos"), coreReleaseApiUrl = Global.xrayCoreUrl.Replace(Global.githubUrl, Global.githubApiUrl),
coreDownloadUrl32 = Global.xrayCoreUrl + "/download/{0}/Xray-windows-{1}.zip", coreDownloadUrl32 = Global.xrayCoreUrl + "/download/{0}/Xray-windows-{1}.zip",
coreDownloadUrl64 = Global.xrayCoreUrl + "/download/{0}/Xray-windows-{1}.zip", coreDownloadUrl64 = Global.xrayCoreUrl + "/download/{0}/Xray-windows-{1}.zip",
match = "Xray", match = "Xray",
@@ -276,7 +266,7 @@ namespace v2rayN.Handler
coreExes = new List<string> { "clash-windows-amd64-v3", "clash-windows-amd64", "clash-windows-386", "clash" }, coreExes = new List<string> { "clash-windows-amd64-v3", "clash-windows-amd64", "clash-windows-386", "clash" },
arguments = "-f config.json", arguments = "-f config.json",
coreUrl = Global.clashCoreUrl, coreUrl = Global.clashCoreUrl,
coreReleaseApiUrl = Global.clashCoreUrl.Replace(@"https://github.com", @"https://api.github.com/repos"), coreReleaseApiUrl = Global.clashCoreUrl.Replace(Global.githubUrl, Global.githubApiUrl),
coreDownloadUrl32 = Global.clashCoreUrl + "/download/{0}/clash-windows-386-{0}.zip", coreDownloadUrl32 = Global.clashCoreUrl + "/download/{0}/clash-windows-386-{0}.zip",
coreDownloadUrl64 = Global.clashCoreUrl + "/download/{0}/clash-windows-amd64-{0}.zip", coreDownloadUrl64 = Global.clashCoreUrl + "/download/{0}/clash-windows-amd64-{0}.zip",
match = "v", match = "v",
@@ -290,7 +280,7 @@ namespace v2rayN.Handler
coreExes = new List<string> { "Clash.Meta-windows-amd64-compatible", "Clash.Meta-windows-amd64", "Clash.Meta-windows-386", "Clash.Meta", "clash" }, coreExes = new List<string> { "Clash.Meta-windows-amd64-compatible", "Clash.Meta-windows-amd64", "Clash.Meta-windows-386", "Clash.Meta", "clash" },
arguments = "-f config.json", arguments = "-f config.json",
coreUrl = Global.clashMetaCoreUrl, coreUrl = Global.clashMetaCoreUrl,
coreReleaseApiUrl = Global.clashMetaCoreUrl.Replace(@"https://github.com", @"https://api.github.com/repos"), coreReleaseApiUrl = Global.clashMetaCoreUrl.Replace(Global.githubUrl, Global.githubApiUrl),
coreDownloadUrl32 = Global.clashMetaCoreUrl + "/download/{0}/Clash.Meta-windows-386-{0}.zip", coreDownloadUrl32 = Global.clashMetaCoreUrl + "/download/{0}/Clash.Meta-windows-386-{0}.zip",
coreDownloadUrl64 = Global.clashMetaCoreUrl + "/download/{0}/Clash.Meta-windows-amd64-compatible-{0}.zip", coreDownloadUrl64 = Global.clashMetaCoreUrl + "/download/{0}/Clash.Meta-windows-amd64-compatible-{0}.zip",
match = "v", match = "v",
@@ -304,7 +294,7 @@ namespace v2rayN.Handler
coreExes = new List<string> { "hysteria-windows-amd64", "hysteria-windows-386", "hysteria" }, coreExes = new List<string> { "hysteria-windows-amd64", "hysteria-windows-386", "hysteria" },
arguments = "", arguments = "",
coreUrl = Global.hysteriaCoreUrl, coreUrl = Global.hysteriaCoreUrl,
coreReleaseApiUrl = Global.hysteriaCoreUrl.Replace(@"https://github.com", @"https://api.github.com/repos"), coreReleaseApiUrl = Global.hysteriaCoreUrl.Replace(Global.githubUrl, Global.githubApiUrl),
coreDownloadUrl32 = Global.hysteriaCoreUrl + "/download/{0}/hysteria-windows-386.exe", coreDownloadUrl32 = Global.hysteriaCoreUrl + "/download/{0}/hysteria-windows-386.exe",
coreDownloadUrl64 = Global.hysteriaCoreUrl + "/download/{0}/hysteria-windows-amd64.exe", coreDownloadUrl64 = Global.hysteriaCoreUrl + "/download/{0}/hysteria-windows-amd64.exe",
redirectInfo = true, redirectInfo = true,

View File

@@ -12,7 +12,7 @@ namespace v2rayN.Handler
{ {
public sealed class MainFormHandler public sealed class MainFormHandler
{ {
private static readonly Lazy<MainFormHandler> instance = new Lazy<MainFormHandler>(() => new MainFormHandler()); private static readonly Lazy<MainFormHandler> instance = new(() => new());
//Action<bool, string> _updateUI; //Action<bool, string> _updateUI;
//private DownloadHandle downloadHandle2; //private DownloadHandle downloadHandle2;
@@ -42,19 +42,14 @@ namespace v2rayN.Handler
{ {
return new Icon(fileName); return new Icon(fileName);
} }
switch (index) return index switch
{ {
case 0: 0 => Properties.Resources.NotifyIcon1,
return Properties.Resources.NotifyIcon1; 1 => Properties.Resources.NotifyIcon2,
case 1: 2 => Properties.Resources.NotifyIcon3,
return Properties.Resources.NotifyIcon2; 3 => Properties.Resources.NotifyIcon2,
case 2: _ => Properties.Resources.NotifyIcon1, // default
return Properties.Resources.NotifyIcon3; };
case 3:
return Properties.Resources.NotifyIcon2;
}
return Properties.Resources.NotifyIcon1;
} }
catch (Exception ex) catch (Exception ex)
{ {
@@ -82,11 +77,11 @@ namespace v2rayN.Handler
return BitmapFrame.Create(new Uri($"pack://application:,,,/Resources/NotifyIcon{index}.ico", UriKind.RelativeOrAbsolute)); return BitmapFrame.Create(new Uri($"pack://application:,,,/Resources/NotifyIcon{index}.ico", UriKind.RelativeOrAbsolute));
} }
private Icon GetNotifyIcon4Routing(Config config) private Icon? GetNotifyIcon4Routing(Config config)
{ {
try try
{ {
if (!config.enableRoutingAdvanced) if (!config.routingBasicItem.enableRoutingAdvanced)
{ {
return null; return null;
} }
@@ -107,9 +102,9 @@ namespace v2rayN.Handler
int width = 128; int width = 128;
int height = 128; int height = 128;
Bitmap bitmap = new Bitmap(width, height); Bitmap bitmap = new(width, height);
Graphics graphics = Graphics.FromImage(bitmap); Graphics graphics = Graphics.FromImage(bitmap);
SolidBrush drawBrush = new SolidBrush(color); SolidBrush drawBrush = new(color);
graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias; graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
//graphics.FillRectangle(drawBrush, new Rectangle(0, 0, width, height)); //graphics.FillRectangle(drawBrush, new Rectangle(0, 0, width, height));
@@ -143,7 +138,7 @@ namespace v2rayN.Handler
return; return;
} }
SaveFileDialog fileDialog = new SaveFileDialog SaveFileDialog fileDialog = new()
{ {
Filter = "Config|*.json", Filter = "Config|*.json",
FilterIndex = 2, FilterIndex = 2,
@@ -176,14 +171,13 @@ namespace v2rayN.Handler
{ {
return; return;
} }
if (item.configType != EConfigType.VMess if (item.configType is not EConfigType.VMess and not EConfigType.VLESS)
&& item.configType != EConfigType.VLESS)
{ {
UI.Show(ResUI.NonVmessService); UI.Show(ResUI.NonVmessService);
return; return;
} }
SaveFileDialog fileDialog = new SaveFileDialog SaveFileDialog fileDialog = new()
{ {
Filter = "Config|*.json", Filter = "Config|*.json",
FilterIndex = 2, FilterIndex = 2,
@@ -212,14 +206,14 @@ namespace v2rayN.Handler
public void BackupGuiNConfig(Config config, bool auto = false) public void BackupGuiNConfig(Config config, bool auto = false)
{ {
string fileName = $"guiNConfig_{DateTime.Now.ToString("yyyy_MM_dd_HH_mm_ss_fff")}.json"; string fileName = $"guiNConfig_{DateTime.Now:yyyy_MM_dd_HH_mm_ss_fff}.json";
if (auto) if (auto)
{ {
fileName = Utils.GetBackupPath(fileName); fileName = Utils.GetBackupPath(fileName);
} }
else else
{ {
SaveFileDialog fileDialog = new SaveFileDialog SaveFileDialog fileDialog = new()
{ {
FileName = fileName, FileName = fileName,
Filter = "guiNConfig|*.json", Filter = "guiNConfig|*.json",
@@ -254,7 +248,7 @@ namespace v2rayN.Handler
public bool RestoreGuiNConfig(ref Config config) public bool RestoreGuiNConfig(ref Config config)
{ {
var fileContent = string.Empty; var fileContent = string.Empty;
using (OpenFileDialog fileDialog = new OpenFileDialog()) using (OpenFileDialog fileDialog = new())
{ {
fileDialog.InitialDirectory = Utils.GetBackupPath(""); fileDialog.InitialDirectory = Utils.GetBackupPath("");
fileDialog.Filter = "guiNConfig|*.json|All|*.*"; fileDialog.Filter = "guiNConfig|*.json|All|*.*";
@@ -286,7 +280,7 @@ namespace v2rayN.Handler
BackupGuiNConfig(config, true); BackupGuiNConfig(config, true);
config = resConfig; config = resConfig;
LazyConfig.Instance.SetConfig(ref config); LazyConfig.Instance.SetConfig(config);
return true; return true;
} }
@@ -309,9 +303,9 @@ namespace v2rayN.Handler
{ {
var dtNow = DateTime.Now; var dtNow = DateTime.Now;
if (config.autoUpdateSubInterval > 0) if (config.guiItem.autoUpdateSubInterval > 0)
{ {
if ((dtNow - autoUpdateSubTime).Hours % config.autoUpdateSubInterval == 0) if ((dtNow - autoUpdateSubTime).Hours % config.guiItem.autoUpdateSubInterval == 0)
{ {
updateHandle.UpdateSubscriptionProcess(config, "", true, (bool success, string msg) => updateHandle.UpdateSubscriptionProcess(config, "", true, (bool success, string msg) =>
{ {
@@ -324,9 +318,9 @@ namespace v2rayN.Handler
Thread.Sleep(60000); Thread.Sleep(60000);
} }
if (config.autoUpdateInterval > 0) if (config.guiItem.autoUpdateInterval > 0)
{ {
if ((dtNow - autoUpdateGeoTime).Hours % config.autoUpdateInterval == 0) if ((dtNow - autoUpdateGeoTime).Hours % config.guiItem.autoUpdateInterval == 0)
{ {
updateHandle.UpdateGeoFile("geosite", config, (bool success, string msg) => updateHandle.UpdateGeoFile("geosite", config, (bool success, string msg) =>
{ {
@@ -381,12 +375,12 @@ namespace v2rayN.Handler
try try
{ {
HotkeyManager.Current.AddOrReplace(((int)item.eGlobalHotkey).ToString(), gesture, handler); HotkeyManager.Current.AddOrReplace(((int)item.eGlobalHotkey).ToString(), gesture, handler);
var msg = string.Format(ResUI.RegisterGlobalHotkeySuccessfully, $"{item.eGlobalHotkey.ToString()}"); var msg = string.Format(ResUI.RegisterGlobalHotkeySuccessfully, $"{item.eGlobalHotkey}");
update(false, msg); update(false, msg);
} }
catch (Exception ex) catch (Exception ex)
{ {
var msg = string.Format(ResUI.RegisterGlobalHotkeyFailed, $"{item.eGlobalHotkey.ToString()}", ex.Message); var msg = string.Format(ResUI.RegisterGlobalHotkeyFailed, $"{item.eGlobalHotkey}", ex.Message);
update(false, msg); update(false, msg);
Utils.SaveLog(msg); Utils.SaveLog(msg);
} }

View File

@@ -0,0 +1,114 @@
using v2rayN.Base;
using v2rayN.Mode;
namespace v2rayN.Handler
{
class ProfileExHandler
{
private static readonly Lazy<ProfileExHandler> _instance = new(() => new());
private List<ProfileExItem> _lstProfileEx;
public List<ProfileExItem> ProfileExs => _lstProfileEx;
public static ProfileExHandler Instance => _instance.Value;
public ProfileExHandler()
{
Init();
}
private void Init()
{
SqliteHelper.Instance.Execute($"delete from ProfileExItem where indexId not in ( select indexId from ProfileItem )");
_lstProfileEx = SqliteHelper.Instance.Table<ProfileExItem>().ToList();
}
private void AddProfileEx(string indexId, ref ProfileExItem profileEx)
{
profileEx = new()
{
indexId = indexId,
delay = 0,
speed = 0,
sort = 0
};
_lstProfileEx.Add(profileEx);
//SqliteHelper.Instance.Replace(profileEx);
}
public void ClearAll()
{
SqliteHelper.Instance.Execute($"delete from ProfileExItem ");
_lstProfileEx = new();
}
public void SaveTo()
{
try
{
foreach (var item in _lstProfileEx)
{
SqliteHelper.Instance.Replace(item);
}
//SqliteHelper.Instance.UpdateAll(_lstProfileEx);
}
catch (Exception ex)
{
Utils.SaveLog(ex.Message, ex);
}
}
public Task SetTestDelay(string indexId, string delayVal)
{
var profileEx = _lstProfileEx.FirstOrDefault(t => t.indexId == indexId);
if (profileEx == null)
{
AddProfileEx(indexId, ref profileEx);
}
int.TryParse(delayVal, out int delay);
profileEx.delay = delay;
return Task.CompletedTask;
}
public Task SetTestSpeed(string indexId, string speedVal)
{
var profileEx = _lstProfileEx.FirstOrDefault(t => t.indexId == indexId);
if (profileEx == null)
{
AddProfileEx(indexId, ref profileEx);
}
decimal.TryParse(speedVal, out decimal speed);
profileEx.speed = speed;
return Task.CompletedTask;
}
public void SetSort(string indexId, int sort)
{
var profileEx = _lstProfileEx.FirstOrDefault(t => t.indexId == indexId);
if (profileEx == null)
{
AddProfileEx(indexId, ref profileEx);
}
profileEx.sort = sort;
}
public int GetSort(string indexId)
{
var profileEx = _lstProfileEx.FirstOrDefault(t => t.indexId == indexId);
if (profileEx == null)
{
return 0;
}
return profileEx.sort;
}
public int GetMaxSort()
{
if (_lstProfileEx.Count <= 0)
{
return 0;
}
return _lstProfileEx.Max(t => t == null ? 0 : t.sort);
}
}
}

View File

@@ -10,16 +10,16 @@ namespace v2rayN.Handler
return SetProxy(null, null, 1); return SetProxy(null, null, 1);
} }
public static bool SetProxy(string strProxy, string exceptions, int type) public static bool SetProxy(string? strProxy, string? exceptions, int type)
{ {
InternetPerConnOptionList list = new InternetPerConnOptionList(); InternetPerConnOptionList list = new();
int optionCount = 1; int optionCount = 1;
if (type == 1) if (type == 1)
{ {
optionCount = 1; optionCount = 1;
} }
else if (type == 2 || type == 4) else if (type is 2 or 4)
{ {
optionCount = Utils.IsNullOrEmpty(exceptions) ? 2 : 3; optionCount = Utils.IsNullOrEmpty(exceptions) ? 2 : 3;
} }
@@ -71,12 +71,12 @@ namespace v2rayN.Handler
{ {
if (Environment.Is64BitOperatingSystem) if (Environment.Is64BitOperatingSystem)
{ {
IntPtr opt = new IntPtr(optionsPtr.ToInt64() + (i * optSize)); IntPtr opt = new(optionsPtr.ToInt64() + (i * optSize));
Marshal.StructureToPtr(options[i], opt, false); Marshal.StructureToPtr(options[i], opt, false);
} }
else else
{ {
IntPtr opt = new IntPtr(optionsPtr.ToInt32() + (i * optSize)); IntPtr opt = new(optionsPtr.ToInt32() + (i * optSize));
Marshal.StructureToPtr(options[i], opt, false); Marshal.StructureToPtr(options[i], opt, false);
} }
} }
@@ -84,7 +84,7 @@ namespace v2rayN.Handler
list.options = optionsPtr; list.options = optionsPtr;
// and then make a pointer out of the whole list // and then make a pointer out of the whole list
IntPtr ipcoListPtr = Marshal.AllocCoTaskMem((int)list.dwSize); IntPtr ipcoListPtr = Marshal.AllocCoTaskMem(list.dwSize);
Marshal.StructureToPtr(list, ipcoListPtr, false); Marshal.StructureToPtr(list, ipcoListPtr, false);
// and finally, call the API method! // and finally, call the API method!
@@ -189,24 +189,21 @@ namespace v2rayN.Handler
//判断是否使用代理 //判断是否使用代理
public static bool UsedProxy() public static bool UsedProxy()
{ {
RegistryKey rk = Registry.CurrentUser.OpenSubKey(@"Software\Microsoft\Windows\CurrentVersion\Internet Settings", true); using RegistryKey? rk = Registry.CurrentUser.OpenSubKey(@"Software\Microsoft\Windows\CurrentVersion\Internet Settings", true);
if (rk.GetValue("ProxyEnable").ToString() == "1") if (rk?.GetValue("ProxyEnable")?.ToString() == "1")
{ {
rk.Close();
return true; return true;
} }
else else
{ {
rk.Close();
return false; return false;
} }
} }
//获得代理的IP和端口 //获得代理的IP和端口
public static string GetProxyProxyServer() public static string? GetProxyProxyServer()
{ {
RegistryKey rk = Registry.CurrentUser.OpenSubKey(@"Software\Microsoft\Windows\CurrentVersion\Internet Settings", true); using RegistryKey? rk = Registry.CurrentUser.OpenSubKey(@"Software\Microsoft\Windows\CurrentVersion\Internet Settings", true);
string ProxyServer = rk.GetValue("ProxyServer").ToString(); string ProxyServer = rk.GetValue("ProxyServer").ToString();
rk.Close();
return ProxyServer; return ProxyServer;
} }

View File

@@ -9,13 +9,13 @@ namespace v2rayN.Handler
/// </summary> /// </summary>
public class QRCodeHelper public class QRCodeHelper
{ {
public static DrawingImage GetQRCode(string strContent) public static DrawingImage? GetQRCode(string strContent)
{ {
try try
{ {
QRCodeGenerator qrGenerator = new QRCodeGenerator(); QRCodeGenerator qrGenerator = new();
QRCodeData qrCodeData = qrGenerator.CreateQrCode(strContent, QRCodeGenerator.ECCLevel.H); QRCodeData qrCodeData = qrGenerator.CreateQrCode(strContent, QRCodeGenerator.ECCLevel.H);
XamlQRCode qrCode = new XamlQRCode(qrCodeData); XamlQRCode qrCode = new(qrCodeData);
DrawingImage qrCodeAsXaml = qrCode.GetGraphic(40); DrawingImage qrCodeAsXaml = qrCode.GetGraphic(40);
return qrCodeAsXaml; return qrCodeAsXaml;
} }

View File

@@ -17,32 +17,22 @@ namespace v2rayN.Handler
/// </summary> /// </summary>
/// <param name="item"></param> /// <param name="item"></param>
/// <returns></returns> /// <returns></returns>
public static string GetShareUrl(ProfileItem item) public static string? GetShareUrl(ProfileItem item)
{ {
try try
{ {
string url = string.Empty; string? url = string.Empty;
switch (item.configType) url = item.configType switch
{ {
case EConfigType.VMess: EConfigType.VMess => ShareVmess(item),
url = ShareVmess(item); EConfigType.Shadowsocks => ShareShadowsocks(item),
break; EConfigType.Socks => ShareSocks(item),
case EConfigType.Shadowsocks: EConfigType.Trojan => ShareTrojan(item),
url = ShareShadowsocks(item); EConfigType.VLESS => ShareVLESS(item),
break; _ => null,
case EConfigType.Socks: };
url = ShareSocks(item);
break;
case EConfigType.Trojan:
url = ShareTrojan(item);
break;
case EConfigType.VLESS:
url = ShareVLESS(item);
break;
default:
break;
}
return url; return url;
} }
catch (Exception ex) catch (Exception ex)
@@ -56,7 +46,7 @@ namespace v2rayN.Handler
{ {
string url = string.Empty; string url = string.Empty;
VmessQRCode vmessQRCode = new VmessQRCode VmessQRCode vmessQRCode = new()
{ {
v = item.configVersion.ToString(), v = item.configVersion.ToString(),
ps = item.remarks.TrimEx(), //备注也许很长 ; ps = item.remarks.TrimEx(), //备注也许很长 ;
@@ -177,7 +167,7 @@ namespace v2rayN.Handler
return Utils.IsIpv6(address) ? $"[{address}]" : address; return Utils.IsIpv6(address) ? $"[{address}]" : address;
} }
private static int GetStdTransport(ProfileItem item, string securityDef, ref Dictionary<string, string> dicQuery) private static int GetStdTransport(ProfileItem item, string? securityDef, ref Dictionary<string, string> dicQuery)
{ {
if (!Utils.IsNullOrEmpty(item.flow)) if (!Utils.IsNullOrEmpty(item.flow))
{ {
@@ -260,7 +250,7 @@ namespace v2rayN.Handler
if (!Utils.IsNullOrEmpty(item.path)) if (!Utils.IsNullOrEmpty(item.path))
{ {
dicQuery.Add("serviceName", Utils.UrlEncode(item.path)); dicQuery.Add("serviceName", Utils.UrlEncode(item.path));
if (item.headerType == Global.GrpcgunMode || item.headerType == Global.GrpcmultiMode) if (item.headerType is Global.GrpcgunMode or Global.GrpcmultiMode)
{ {
dicQuery.Add("mode", Utils.UrlEncode(item.headerType)); dicQuery.Add("mode", Utils.UrlEncode(item.headerType));
} }
@@ -278,13 +268,13 @@ namespace v2rayN.Handler
/// <summary> /// <summary>
/// 从剪贴板导入URL /// 从剪贴板导入URL
/// </summary> /// </summary>
/// <param name="fileName"></param>
/// <param name="msg"></param> /// <param name="msg"></param>
/// <returns></returns> /// <returns></returns>
public static ProfileItem ImportFromClipboardConfig(string clipboardData, out string msg) public static ProfileItem? ImportFromClipboardConfig(string clipboardData, out string msg)
{ {
msg = string.Empty; msg = string.Empty;
ProfileItem profileItem = new ProfileItem();
ProfileItem profileItem = new();
try try
{ {
@@ -368,7 +358,7 @@ namespace v2rayN.Handler
return profileItem; return profileItem;
} }
private static ProfileItem ResolveVmess(string result, out string msg) private static ProfileItem? ResolveVmess(string result, out string msg)
{ {
msg = string.Empty; msg = string.Empty;
var profileItem = new ProfileItem var profileItem = new ProfileItem
@@ -376,11 +366,11 @@ namespace v2rayN.Handler
configType = EConfigType.VMess configType = EConfigType.VMess
}; };
result = result.Substring(Global.vmessProtocol.Length); result = result[Global.vmessProtocol.Length..];
result = Utils.Base64Decode(result); result = Utils.Base64Decode(result);
//转成Json //转成Json
VmessQRCode vmessQRCode = Utils.FromJson<VmessQRCode>(result); VmessQRCode? vmessQRCode = Utils.FromJson<VmessQRCode>(result);
if (vmessQRCode == null) if (vmessQRCode == null)
{ {
msg = ResUI.FailedConversionConfiguration; msg = ResUI.FailedConversionConfiguration;
@@ -418,17 +408,17 @@ namespace v2rayN.Handler
return profileItem; return profileItem;
} }
private static ProfileItem ResolveVmess4Kitsunebi(string result) private static ProfileItem? ResolveVmess4Kitsunebi(string result)
{ {
ProfileItem profileItem = new ProfileItem ProfileItem profileItem = new()
{ {
configType = EConfigType.VMess configType = EConfigType.VMess
}; };
result = result.Substring(Global.vmessProtocol.Length); result = result[Global.vmessProtocol.Length..];
int indexSplit = result.IndexOf("?"); int indexSplit = result.IndexOf("?");
if (indexSplit > 0) if (indexSplit > 0)
{ {
result = result.Substring(0, indexSplit); result = result[..indexSplit];
} }
result = Utils.Base64Decode(result); result = Utils.Base64Decode(result);
@@ -439,7 +429,7 @@ namespace v2rayN.Handler
} }
string[] arr21 = arr1[0].Split(':'); string[] arr21 = arr1[0].Split(':');
string[] arr22 = arr1[1].Split(':'); string[] arr22 = arr1[1].Split(':');
if (arr21.Length != 2 || arr21.Length != 2) if (arr21.Length != 2 || arr22.Length != 2)
{ {
return null; return null;
} }
@@ -456,15 +446,15 @@ namespace v2rayN.Handler
return profileItem; return profileItem;
} }
private static ProfileItem ResolveStdVmess(string result) private static ProfileItem? ResolveStdVmess(string result)
{ {
ProfileItem i = new ProfileItem ProfileItem i = new()
{ {
configType = EConfigType.VMess, configType = EConfigType.VMess,
security = "auto" security = "auto"
}; };
Uri u = new Uri(result); Uri u = new(result);
i.address = u.IdnHost; i.address = u.IdnHost;
i.port = u.Port; i.port = u.Port;
@@ -537,7 +527,7 @@ namespace v2rayN.Handler
return i; return i;
} }
private static ProfileItem ResolveSip002(string result) private static ProfileItem? ResolveSip002(string result)
{ {
Uri parsedUrl; Uri parsedUrl;
try try
@@ -548,7 +538,7 @@ namespace v2rayN.Handler
{ {
return null; return null;
} }
ProfileItem server = new ProfileItem ProfileItem server = new()
{ {
remarks = parsedUrl.GetComponents(UriComponents.Fragment, UriFormat.Unescaped), remarks = parsedUrl.GetComponents(UriComponents.Fragment, UriFormat.Unescaped),
address = parsedUrl.IdnHost, address = parsedUrl.IdnHost,
@@ -556,7 +546,7 @@ namespace v2rayN.Handler
}; };
string rawUserInfo = parsedUrl.GetComponents(UriComponents.UserInfo, UriFormat.UriEscaped); string rawUserInfo = parsedUrl.GetComponents(UriComponents.UserInfo, UriFormat.UriEscaped);
//2022-blake3 //2022-blake3
if (rawUserInfo.Contains(":")) if (rawUserInfo.Contains(':'))
{ {
string[] userInfoParts = rawUserInfo.Split(new[] { ':' }, 2); string[] userInfoParts = rawUserInfo.Split(new[] { ':' }, 2);
if (userInfoParts.Length != 2) if (userInfoParts.Length != 2)
@@ -600,16 +590,16 @@ namespace v2rayN.Handler
return server; return server;
} }
private static readonly Regex UrlFinder = new Regex(@"ss://(?<base64>[A-Za-z0-9+-/=_]+)(?:#(?<tag>\S+))?", RegexOptions.IgnoreCase); private static readonly Regex UrlFinder = new(@"ss://(?<base64>[A-Za-z0-9+-/=_]+)(?:#(?<tag>\S+))?", RegexOptions.IgnoreCase | RegexOptions.Compiled);
private static readonly Regex DetailsParser = new Regex(@"^((?<method>.+?):(?<password>.*)@(?<hostname>.+?):(?<port>\d+?))$", RegexOptions.IgnoreCase); private static readonly Regex DetailsParser = new(@"^((?<method>.+?):(?<password>.*)@(?<hostname>.+?):(?<port>\d+?))$", RegexOptions.IgnoreCase | RegexOptions.Compiled);
private static ProfileItem ResolveSSLegacy(string result) private static ProfileItem? ResolveSSLegacy(string result)
{ {
var match = UrlFinder.Match(result); var match = UrlFinder.Match(result);
if (!match.Success) if (!match.Success)
return null; return null;
ProfileItem server = new ProfileItem(); ProfileItem server = new();
var base64 = match.Groups["base64"].Value.TrimEnd('/'); var base64 = match.Groups["base64"].Value.TrimEnd('/');
var tag = match.Groups["tag"].Value; var tag = match.Groups["tag"].Value;
if (!Utils.IsNullOrEmpty(tag)) if (!Utils.IsNullOrEmpty(tag))
@@ -635,16 +625,16 @@ namespace v2rayN.Handler
} }
private static readonly Regex StdVmessUserInfo = new Regex( private static readonly Regex StdVmessUserInfo = new(
@"^(?<network>[a-z]+)(\+(?<streamSecurity>[a-z]+))?:(?<id>[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})$"); @"^(?<network>[a-z]+)(\+(?<streamSecurity>[a-z]+))?:(?<id>[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})$", RegexOptions.Compiled);
private static ProfileItem ResolveSocks(string result) private static ProfileItem? ResolveSocks(string result)
{ {
ProfileItem profileItem = new ProfileItem ProfileItem profileItem = new()
{ {
configType = EConfigType.Socks configType = EConfigType.Socks
}; };
result = result.Substring(Global.socksProtocol.Length); result = result[Global.socksProtocol.Length..];
//remark //remark
int indexRemark = result.IndexOf("#"); int indexRemark = result.IndexOf("#");
if (indexRemark > 0) if (indexRemark > 0)
@@ -654,7 +644,7 @@ namespace v2rayN.Handler
profileItem.remarks = Utils.UrlDecode(result.Substring(indexRemark + 1, result.Length - indexRemark - 1)); profileItem.remarks = Utils.UrlDecode(result.Substring(indexRemark + 1, result.Length - indexRemark - 1));
} }
catch { } catch { }
result = result.Substring(0, indexRemark); result = result[..indexRemark];
} }
//part decode //part decode
int indexS = result.IndexOf("@"); int indexS = result.IndexOf("@");
@@ -678,15 +668,15 @@ namespace v2rayN.Handler
{ {
return null; return null;
} }
profileItem.address = arr1[1].Substring(0, indexPort); profileItem.address = arr1[1][..indexPort];
profileItem.port = Utils.ToInt(arr1[1].Substring(indexPort + 1, arr1[1].Length - (indexPort + 1))); profileItem.port = Utils.ToInt(arr1[1][(indexPort + 1)..]);
profileItem.security = arr21[0]; profileItem.security = arr21[0];
profileItem.id = arr21[1]; profileItem.id = arr21[1];
return profileItem; return profileItem;
} }
private static ProfileItem ResolveSocksNew(string result) private static ProfileItem? ResolveSocksNew(string result)
{ {
Uri parsedUrl; Uri parsedUrl;
try try
@@ -697,7 +687,7 @@ namespace v2rayN.Handler
{ {
return null; return null;
} }
ProfileItem server = new ProfileItem ProfileItem server = new()
{ {
remarks = parsedUrl.GetComponents(UriComponents.Fragment, UriFormat.Unescaped), remarks = parsedUrl.GetComponents(UriComponents.Fragment, UriFormat.Unescaped),
address = parsedUrl.IdnHost, address = parsedUrl.IdnHost,
@@ -719,12 +709,12 @@ namespace v2rayN.Handler
private static ProfileItem ResolveTrojan(string result) private static ProfileItem ResolveTrojan(string result)
{ {
ProfileItem item = new ProfileItem ProfileItem item = new()
{ {
configType = EConfigType.Trojan configType = EConfigType.Trojan
}; };
Uri url = new Uri(result); Uri url = new(result);
item.address = url.IdnHost; item.address = url.IdnHost;
item.port = url.Port; item.port = url.Port;
@@ -738,13 +728,13 @@ namespace v2rayN.Handler
} }
private static ProfileItem ResolveStdVLESS(string result) private static ProfileItem ResolveStdVLESS(string result)
{ {
ProfileItem item = new ProfileItem ProfileItem item = new()
{ {
configType = EConfigType.VLESS, configType = EConfigType.VLESS,
security = "none" security = "none"
}; };
Uri url = new Uri(result); Uri url = new(result);
item.address = url.IdnHost; item.address = url.IdnHost;
item.port = url.Port; item.port = url.Port;

View File

@@ -34,6 +34,10 @@ namespace v2rayN.Handler
{ {
continue; continue;
} }
if (it.port <= 0)
{
continue;
}
_selecteds.Add(new ServerTestItem() _selecteds.Add(new ServerTestItem()
{ {
indexId = it.indexId, indexId = it.indexId,
@@ -108,24 +112,24 @@ namespace v2rayN.Handler
private void RunPing() private void RunPing()
{ {
RunPingSub((ServerTestItem it) => RunPingSub(async (ServerTestItem it) =>
{ {
long time = Ping(it.address); long time = Ping(it.address);
var output = FormatOut(time, Global.DelayUnit); var output = FormatOut(time, Global.DelayUnit);
LazyConfig.Instance.SetTestResult(it.indexId, output, ""); await ProfileExHandler.Instance.SetTestDelay(it.indexId, output);
UpdateFunc(it.indexId, output); UpdateFunc(it.indexId, output);
}); });
} }
private void RunTcping() private void RunTcping()
{ {
RunPingSub((ServerTestItem it) => RunPingSub(async (ServerTestItem it) =>
{ {
int time = GetTcpingTime(it.address, it.port); int time = GetTcpingTime(it.address, it.port);
var output = FormatOut(time, Global.DelayUnit); var output = FormatOut(time, Global.DelayUnit);
LazyConfig.Instance.SetTestResult(it.indexId, output, ""); await ProfileExHandler.Instance.SetTestDelay(it.indexId, output);
UpdateFunc(it.indexId, output); UpdateFunc(it.indexId, output);
}); });
} }
@@ -146,7 +150,7 @@ namespace v2rayN.Handler
DownloadHandle downloadHandle = new DownloadHandle(); DownloadHandle downloadHandle = new DownloadHandle();
//Thread.Sleep(5000); //Thread.Sleep(5000);
List<Task> tasks = new List<Task>(); List<Task> tasks = new();
foreach (var it in _selecteds) foreach (var it in _selecteds)
{ {
if (!it.allowTest) if (!it.allowTest)
@@ -157,16 +161,15 @@ namespace v2rayN.Handler
{ {
continue; continue;
} }
tasks.Add(Task.Run(() => tasks.Add(Task.Run(async () =>
{ {
try try
{ {
LazyConfig.Instance.SetTestResult(it.indexId, "-1", "");
WebProxy webProxy = new WebProxy(Global.Loopback, it.port); WebProxy webProxy = new(Global.Loopback, it.port);
string output = GetRealPingTime(downloadHandle, webProxy); string output = GetRealPingTime(downloadHandle, webProxy);
LazyConfig.Instance.SetTestResult(it.indexId, output, ""); await ProfileExHandler.Instance.SetTestDelay(it.indexId, output);
UpdateFunc(it.indexId, output); UpdateFunc(it.indexId, output);
int.TryParse(output, out int delay); int.TryParse(output, out int delay);
it.delay = delay; it.delay = delay;
@@ -187,6 +190,7 @@ namespace v2rayN.Handler
finally finally
{ {
if (pid > 0) _coreHandler.CoreStopPid(pid); if (pid > 0) _coreHandler.CoreStopPid(pid);
ProfileExHandler.Instance.SaveTo();
} }
return Task.CompletedTask; return Task.CompletedTask;
@@ -195,10 +199,10 @@ namespace v2rayN.Handler
private async Task RunSpeedTestAsync() private async Task RunSpeedTestAsync()
{ {
int pid = -1; int pid = -1;
if (_actionType == ESpeedActionType.Mixedtest) //if (_actionType == ESpeedActionType.Mixedtest)
{ //{
_selecteds = _selecteds.OrderBy(t => t.delay).ToList(); // _selecteds = _selecteds.OrderBy(t => t.delay).ToList();
} //}
pid = _coreHandler.LoadCoreConfigString(_config, _selecteds); pid = _coreHandler.LoadCoreConfigString(_config, _selecteds);
if (pid < 0) if (pid < 0)
@@ -207,10 +211,11 @@ namespace v2rayN.Handler
return; return;
} }
string url = _config.constItem.speedTestUrl; string url = _config.speedTestItem.speedTestUrl;
DownloadHandle downloadHandle = new DownloadHandle(); var timeout = _config.speedTestItem.speedTestTimeout;
DownloadHandle downloadHandle = new();
var timeout = 8;
foreach (var it in _selecteds) foreach (var it in _selecteds)
{ {
if (!it.allowTest) if (!it.allowTest)
@@ -221,24 +226,24 @@ namespace v2rayN.Handler
{ {
continue; continue;
} }
if (it.delay < 0) //if (it.delay < 0)
{ //{
UpdateFunc(it.indexId, "", ResUI.SpeedtestingSkip); // UpdateFunc(it.indexId, "", ResUI.SpeedtestingSkip);
continue; // continue;
} //}
_ = LazyConfig.Instance.SetTestResult(it.indexId, "", "-1"); await ProfileExHandler.Instance.SetTestSpeed(it.indexId, "-1");
var item = LazyConfig.Instance.GetProfileItem(it.indexId); var item = LazyConfig.Instance.GetProfileItem(it.indexId);
if (item is null) continue; if (item is null) continue;
WebProxy webProxy = new WebProxy(Global.Loopback, it.port); WebProxy webProxy = new(Global.Loopback, it.port);
await downloadHandle.DownloadDataAsync(url, webProxy, timeout, (bool success, string msg) => await downloadHandle.DownloadDataAsync(url, webProxy, timeout, async (bool success, string msg) =>
{ {
decimal.TryParse(msg, out decimal dec); decimal.TryParse(msg, out decimal dec);
if (dec > 0) if (dec > 0)
{ {
_ = LazyConfig.Instance.SetTestResult(it.indexId, "", msg); await ProfileExHandler.Instance.SetTestSpeed(it.indexId, msg);
} }
UpdateFunc(it.indexId, "", msg); UpdateFunc(it.indexId, "", msg);
}); });
@@ -249,19 +254,74 @@ namespace v2rayN.Handler
_coreHandler.CoreStopPid(pid); _coreHandler.CoreStopPid(pid);
} }
UpdateFunc("", ResUI.SpeedtestingCompleted); UpdateFunc("", ResUI.SpeedtestingCompleted);
ProfileExHandler.Instance.SaveTo();
} }
private async Task RunSpeedTestMulti()
{
int pid = -1;
pid = _coreHandler.LoadCoreConfigString(_config, _selecteds);
if (pid < 0)
{
UpdateFunc("", ResUI.FailedToRunCore);
return;
}
string url = _config.speedTestItem.speedTestUrl;
var timeout = _config.speedTestItem.speedTestTimeout;
DownloadHandle downloadHandle = new();
foreach (var it in _selecteds)
{
if (!it.allowTest)
{
continue;
}
if (it.configType == EConfigType.Custom)
{
continue;
}
await ProfileExHandler.Instance.SetTestSpeed(it.indexId, "-1");
var item = LazyConfig.Instance.GetProfileItem(it.indexId);
if (item is null) continue;
WebProxy webProxy = new(Global.Loopback, it.port);
_ = downloadHandle.DownloadDataAsync(url, webProxy, timeout, async (bool success, string msg) =>
{
decimal.TryParse(msg, out decimal dec);
if (dec > 0)
{
await ProfileExHandler.Instance.SetTestSpeed(it.indexId, msg);
}
UpdateFunc(it.indexId, "", msg);
});
Thread.Sleep(2000);
}
Thread.Sleep((timeout + 2) * 1000);
if (pid > 0)
{
_coreHandler.CoreStopPid(pid);
}
UpdateFunc("", ResUI.SpeedtestingCompleted);
ProfileExHandler.Instance.SaveTo();
}
private async Task RunMixedtestAsync() private async Task RunMixedtestAsync()
{ {
await RunRealPing(); await RunRealPing();
Thread.Sleep(1000); Thread.Sleep(1000);
await RunSpeedTestAsync(); await RunSpeedTestMulti();
} }
public string GetRealPingTime(DownloadHandle downloadHandle, WebProxy webProxy) public string GetRealPingTime(DownloadHandle downloadHandle, WebProxy webProxy)
{ {
string status = downloadHandle.GetRealPingTime(_config.constItem.speedPingTestUrl, webProxy, 10, out int responseTime); string status = downloadHandle.GetRealPingTime(_config.speedTestItem.speedPingTestUrl, webProxy, 10, out int responseTime);
//string output = Utils.IsNullOrEmpty(status) ? FormatOut(responseTime, "ms") : status; //string output = Utils.IsNullOrEmpty(status) ? FormatOut(responseTime, "ms") : status;
return FormatOut(Utils.IsNullOrEmpty(status) ? responseTime : -1, Global.DelayUnit); return FormatOut(Utils.IsNullOrEmpty(status) ? responseTime : -1, Global.DelayUnit);
} }
@@ -278,11 +338,11 @@ namespace v2rayN.Handler
ipAddress = ipHostInfo.AddressList[0]; ipAddress = ipHostInfo.AddressList[0];
} }
Stopwatch timer = new Stopwatch(); Stopwatch timer = new();
timer.Start(); timer.Start();
IPEndPoint endPoint = new IPEndPoint(ipAddress, port); IPEndPoint endPoint = new(ipAddress, port);
Socket clientSocket = new Socket(endPoint.AddressFamily, SocketType.Stream, ProtocolType.Tcp); using Socket clientSocket = new(endPoint.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
IAsyncResult result = clientSocket.BeginConnect(endPoint, null, null); IAsyncResult result = clientSocket.BeginConnect(endPoint, null, null);
if (!result.AsyncWaitHandle.WaitOne(TimeSpan.FromSeconds(5))) if (!result.AsyncWaitHandle.WaitOne(TimeSpan.FromSeconds(5)))
@@ -291,7 +351,6 @@ namespace v2rayN.Handler
timer.Stop(); timer.Stop();
responseTime = timer.Elapsed.Milliseconds; responseTime = timer.Elapsed.Milliseconds;
clientSocket.Close();
} }
catch (Exception ex) catch (Exception ex)
{ {
@@ -313,7 +372,7 @@ namespace v2rayN.Handler
{ {
int timeout = 30; int timeout = 30;
int echoNum = 2; int echoNum = 2;
Ping pingSender = new Ping(); using Ping pingSender = new();
for (int i = 0; i < echoNum; i++) for (int i = 0; i < echoNum; i++)
{ {
PingReply reply = pingSender.Send(host, timeout); PingReply reply = pingSender.Send(host, timeout);

View File

@@ -13,7 +13,7 @@ namespace v2rayN.Handler
private Channel channel_; private Channel channel_;
private StatsService.StatsServiceClient client_; private StatsService.StatsServiceClient client_;
private bool exitFlag_; private bool exitFlag_;
private ServerStatItem _serverStatItem; private ServerStatItem? _serverStatItem;
private List<ServerStatItem> _lstServerStat; private List<ServerStatItem> _lstServerStat;
public List<ServerStatItem> ServerStat => _lstServerStat; public List<ServerStatItem> ServerStat => _lstServerStat;
@@ -27,7 +27,7 @@ namespace v2rayN.Handler
public StatisticsHandler(Mode.Config config, Action<ServerSpeedItem> update) public StatisticsHandler(Mode.Config config, Action<ServerSpeedItem> update)
{ {
config_ = config; config_ = config;
Enable = config.enableStatistics; Enable = config.guiItem.enableStatistics;
updateFunc_ = update; updateFunc_ = update;
exitFlag_ = false; exitFlag_ = false;
@@ -70,7 +70,7 @@ namespace v2rayN.Handler
{ {
if (Enable && channel_.State == ChannelState.Ready) if (Enable && channel_.State == ChannelState.Ready)
{ {
QueryStatsResponse res = null; QueryStatsResponse? res = null;
try try
{ {
res = client_.QueryStats(new QueryStatsRequest() { Pattern = "", Reset = true }); res = client_.QueryStats(new QueryStatsRequest() { Pattern = "", Reset = true });
@@ -103,7 +103,7 @@ namespace v2rayN.Handler
} }
} }
} }
var sleep = config_.statisticsFreshRate < 1 ? 1 : config_.statisticsFreshRate; var sleep = config_.guiItem.statisticsFreshRate < 1 ? 1 : config_.guiItem.statisticsFreshRate;
Thread.Sleep(1000 * sleep); Thread.Sleep(1000 * sleep);
channel_.ConnectAsync(); channel_.ConnectAsync();
} }
@@ -229,7 +229,7 @@ namespace v2rayN.Handler
try try
{ {
// TCP stack please do me a favor // TCP stack please do me a favor
TcpListener l = new TcpListener(IPAddress.Loopback, 0); TcpListener l = new(IPAddress.Loopback, 0);
l.Start(); l.Start();
int port = ((IPEndPoint)l.LocalEndpoint).Port; int port = ((IPEndPoint)l.LocalEndpoint).Port;
l.Stop(); l.Stop();

View File

@@ -20,7 +20,7 @@ namespace v2rayN.Handler
// <proxy-server><CR-LF> // <proxy-server><CR-LF>
// <bypass-list><CR-LF> // <bypass-list><CR-LF>
// <pac-url> // <pac-url>
private static SysproxyConfig _userSettings = null; private static SysproxyConfig? _userSettings = null;
enum RET_ERRORS : int enum RET_ERRORS : int
{ {
@@ -154,11 +154,10 @@ namespace v2rayN.Handler
// using event to avoid hanging when redirect standard output/error // using event to avoid hanging when redirect standard output/error
// ref: https://stackoverflow.com/questions/139593/processstartinfo-hanging-on-waitforexit-why // ref: https://stackoverflow.com/questions/139593/processstartinfo-hanging-on-waitforexit-why
// and http://blog.csdn.net/zhangweixing0/article/details/7356841 // and http://blog.csdn.net/zhangweixing0/article/details/7356841
using (AutoResetEvent outputWaitHandle = new AutoResetEvent(false)) using AutoResetEvent outputWaitHandle = new(false);
using (AutoResetEvent errorWaitHandle = new AutoResetEvent(false)) using AutoResetEvent errorWaitHandle = new(false);
{ using Process process = new();
using (Process process = new Process())
{
// Configure the process using the StartInfo properties. // Configure the process using the StartInfo properties.
process.StartInfo.FileName = Utils.GetTempPath("sysproxy.exe"); process.StartInfo.FileName = Utils.GetTempPath("sysproxy.exe");
process.StartInfo.Arguments = arguments; process.StartInfo.Arguments = arguments;
@@ -174,8 +173,8 @@ namespace v2rayN.Handler
process.StartInfo.CreateNoWindow = true; process.StartInfo.CreateNoWindow = true;
StringBuilder output = new StringBuilder(); StringBuilder output = new(1024);
StringBuilder error = new StringBuilder(); StringBuilder error = new(1024);
process.OutputDataReceived += (sender, e) => process.OutputDataReceived += (sender, e) =>
{ {
@@ -232,8 +231,6 @@ namespace v2rayN.Handler
// _queryStr = stdout; // _queryStr = stdout;
//} //}
} }
}
}
} }

View File

@@ -3,17 +3,18 @@ using System.IO;
using System.Reactive.Linq; using System.Reactive.Linq;
using v2rayN.Handler; using v2rayN.Handler;
using v2rayN.Mode; using v2rayN.Mode;
using v2rayN.Resx;
namespace v2rayN.Base namespace v2rayN.Base
{ {
public sealed class TunHandler public sealed class TunHandler
{ {
private static readonly Lazy<TunHandler> _instance = new Lazy<TunHandler>(() => new()); private static readonly Lazy<TunHandler> _instance = new(() => new());
public static TunHandler Instance => _instance.Value; public static TunHandler Instance => _instance.Value;
private string _tunConfigName = "tunConfig.json"; private string _tunConfigName = "tunConfig.json";
private static Config _config; private static Config _config;
private CoreInfo coreInfo; private CoreInfo coreInfo;
private Process _process; private Process? _process;
private static int _socksPort; private static int _socksPort;
private static bool _needRestart = true; private static bool _needRestart = true;
private static bool _isRunning = false; private static bool _isRunning = false;
@@ -60,6 +61,7 @@ namespace v2rayN.Base
{ {
return; return;
} }
CoreStartTest();
CoreStart(); CoreStart();
} }
} }
@@ -101,6 +103,7 @@ namespace v2rayN.Base
configStr = configStr.Replace("$stack$", $"{_config.tunModeItem.stack}"); configStr = configStr.Replace("$stack$", $"{_config.tunModeItem.stack}");
//logs //logs
configStr = configStr.Replace("$log_disabled$", $"aaa{(!_config.tunModeItem.enabledLog).ToString().ToLower()}");
if (_config.tunModeItem.showWindow) if (_config.tunModeItem.showWindow)
{ {
configStr = configStr.Replace("$log_output$", $""); configStr = configStr.Replace("$log_output$", $"");
@@ -108,7 +111,7 @@ namespace v2rayN.Base
else else
{ {
var dtNow = DateTime.Now; var dtNow = DateTime.Now;
var log_output = $"\"output\": \"{Utils.GetLogPath($"singbox_{dtNow.ToString("yyyy-MM-dd")}.txt")}\", "; var log_output = $"\"output\": \"{Utils.GetLogPath($"singbox_{dtNow:yyyy-MM-dd}.txt")}\", ";
configStr = configStr.Replace("$log_output$", $"{log_output.Replace(@"\", @"\\")}"); configStr = configStr.Replace("$log_output$", $"{log_output.Replace(@"\", @"\\")}");
} }
@@ -116,8 +119,8 @@ namespace v2rayN.Base
configStr = configStr.Replace("$socksPort$", $"{_socksPort}"); configStr = configStr.Replace("$socksPort$", $"{_socksPort}");
//exe //exe
List<string> lstDnsExe = new List<string>(); List<string> lstDnsExe = new();
List<string> lstDirectExe = new List<string>(); List<string> lstDirectExe = new();
var coreInfos = LazyConfig.Instance.GetCoreInfos(); var coreInfos = LazyConfig.Instance.GetCoreInfos();
foreach (var it in coreInfos) foreach (var it in coreInfos)
{ {
@@ -225,7 +228,8 @@ namespace v2rayN.Base
} }
if (Utils.IsNullOrEmpty(fileName)) if (Utils.IsNullOrEmpty(fileName))
{ {
string msg = string.Format(ResUI.NotFoundCore, Utils.GetBinPath("", coreInfo.coreType), string.Join(", ", coreInfo.coreExes.ToArray()), coreInfo.coreUrl);
Utils.SaveLog(msg);
} }
return fileName; return fileName;
} }
@@ -235,12 +239,12 @@ namespace v2rayN.Base
try try
{ {
string fileName = CoreFindexe(); string fileName = CoreFindexe();
if (fileName == "") if (Utils.IsNullOrEmpty(fileName))
{ {
return; return;
} }
var showWindow = _config.tunModeItem.showWindow; var showWindow = _config.tunModeItem.showWindow;
Process p = new Process Process p = new()
{ {
StartInfo = new ProcessStartInfo StartInfo = new ProcessStartInfo
{ {
@@ -293,5 +297,47 @@ namespace v2rayN.Base
Utils.SaveLog(ex.Message, ex); Utils.SaveLog(ex.Message, ex);
} }
} }
private int CoreStartTest()
{
Utils.SaveLog("Tun mode configuration file test start");
try
{
string fileName = CoreFindexe();
if (fileName == "")
{
return -1;
}
Process p = new Process
{
StartInfo = new ProcessStartInfo
{
FileName = fileName,
Arguments = $"run -c \"{Utils.GetConfigPath(_tunConfigName)}\"",
WorkingDirectory = Utils.GetConfigPath(),
UseShellExecute = false,
CreateNoWindow = true,
RedirectStandardError = true,
Verb = "runas",
}
};
p.Start();
if (p.WaitForExit(2000))
{
throw new Exception(p.StandardError.ReadToEnd());
}
KillProcess(p);
return 0;
}
catch (Exception ex)
{
Utils.SaveLog(ex.Message, ex);
return -1;
}
finally
{
Utils.SaveLog("Tun mode configuration file test end");
}
}
} }
} }

View File

@@ -35,11 +35,7 @@ namespace v2rayN.Handler
_updateFunc = update; _updateFunc = update;
var url = string.Empty; var url = string.Empty;
DownloadHandle downloadHandle = null; DownloadHandle downloadHandle = new();
if (downloadHandle == null)
{
downloadHandle = new DownloadHandle();
downloadHandle.UpdateCompleted += (sender2, args) => downloadHandle.UpdateCompleted += (sender2, args) =>
{ {
if (args.Success) if (args.Success)
@@ -50,7 +46,7 @@ namespace v2rayN.Handler
{ {
string fileName = Utils.GetTempPath(Utils.GetDownloadFileName(url)); string fileName = Utils.GetTempPath(Utils.GetDownloadFileName(url));
fileName = Utils.UrlEncode(fileName); fileName = Utils.UrlEncode(fileName);
Process process = new Process Process process = new()
{ {
StartInfo = new ProcessStartInfo StartInfo = new ProcessStartInfo
{ {
@@ -79,7 +75,6 @@ namespace v2rayN.Handler
{ {
_updateFunc(false, args.GetException().Message); _updateFunc(false, args.GetException().Message);
}; };
}
AbsoluteCompleted += (sender2, args) => AbsoluteCompleted += (sender2, args) =>
{ {
if (args.Success) if (args.Success)
@@ -106,10 +101,7 @@ namespace v2rayN.Handler
_updateFunc = update; _updateFunc = update;
var url = string.Empty; var url = string.Empty;
DownloadHandle downloadHandle = null; DownloadHandle downloadHandle = new();
if (downloadHandle == null)
{
downloadHandle = new DownloadHandle();
downloadHandle.UpdateCompleted += (sender2, args) => downloadHandle.UpdateCompleted += (sender2, args) =>
{ {
if (args.Success) if (args.Success)
@@ -135,7 +127,6 @@ namespace v2rayN.Handler
{ {
_updateFunc(true, args.GetException().Message); _updateFunc(true, args.GetException().Message);
}; };
}
AbsoluteCompleted += (sender2, args) => AbsoluteCompleted += (sender2, args) =>
{ {
@@ -213,10 +204,10 @@ namespace v2rayN.Handler
url = Utils.GetPunycode(url); url = Utils.GetPunycode(url);
_updateFunc(false, $"{hashCode}{ResUI.MsgStartGettingSubscriptions}"); _updateFunc(false, $"{hashCode}{ResUI.MsgStartGettingSubscriptions}");
var result = await downloadHandle.DownloadStringAsync(url, blProxy, userAgent); var result = await downloadHandle.TryDownloadString(url, blProxy, userAgent);
if (blProxy && Utils.IsNullOrEmpty(result)) if (blProxy && Utils.IsNullOrEmpty(result))
{ {
result = await downloadHandle.DownloadStringAsync(url, false, userAgent); result = await downloadHandle.TryDownloadString(url, false, userAgent);
} }
if (Utils.IsNullOrEmpty(result)) if (Utils.IsNullOrEmpty(result))
@@ -226,7 +217,7 @@ namespace v2rayN.Handler
else else
{ {
_updateFunc(false, $"{hashCode}{ResUI.MsgGetSubscriptionSuccessfully}"); _updateFunc(false, $"{hashCode}{ResUI.MsgGetSubscriptionSuccessfully}");
if (result.Length < 99) if (result!.Length < 99)
{ {
_updateFunc(false, $"{hashCode}{result}"); _updateFunc(false, $"{hashCode}{result}");
} }
@@ -262,11 +253,7 @@ namespace v2rayN.Handler
_updateFunc = update; _updateFunc = update;
var url = string.Format(Global.geoUrl, geoName); var url = string.Format(Global.geoUrl, geoName);
DownloadHandle downloadHandle = null; DownloadHandle downloadHandle = new();
if (downloadHandle == null)
{
downloadHandle = new DownloadHandle();
downloadHandle.UpdateCompleted += (sender2, args) => downloadHandle.UpdateCompleted += (sender2, args) =>
{ {
if (args.Success) if (args.Success)
@@ -278,11 +265,13 @@ namespace v2rayN.Handler
string fileName = Utils.GetTempPath(Utils.GetDownloadFileName(url)); string fileName = Utils.GetTempPath(Utils.GetDownloadFileName(url));
if (File.Exists(fileName)) if (File.Exists(fileName))
{ {
Global.coreTypes.ForEach(it => //Global.coreTypes.ForEach(it =>
{ //{
string targetPath = Utils.GetBinPath($"{geoName}.dat", (ECoreType)Enum.Parse(typeof(ECoreType), it)); // string targetPath = Utils.GetBinPath($"{geoName}.dat", (ECoreType)Enum.Parse(typeof(ECoreType), it));
// File.Copy(fileName, targetPath, true);
//});
string targetPath = Utils.GetBinPath($"{geoName}.dat");
File.Copy(fileName, targetPath, true); File.Copy(fileName, targetPath, true);
});
File.Delete(fileName); File.Delete(fileName);
//_updateFunc(true, ""); //_updateFunc(true, "");
@@ -302,7 +291,6 @@ namespace v2rayN.Handler
{ {
_updateFunc(false, args.GetException().Message); _updateFunc(false, args.GetException().Message);
}; };
}
askToDownload(downloadHandle, url, false); askToDownload(downloadHandle, url, false);
} }
@@ -372,7 +360,7 @@ namespace v2rayN.Handler
return ""; return "";
} }
Process p = new Process(); using Process p = new();
p.StartInfo.FileName = filePath; p.StartInfo.FileName = filePath;
p.StartInfo.Arguments = coreInfo.versionArg; p.StartInfo.Arguments = coreInfo.versionArg;
p.StartInfo.WorkingDirectory = Utils.StartupPath(); p.StartInfo.WorkingDirectory = Utils.StartupPath();

View File

@@ -8,150 +8,31 @@
{ {
#region property #region property
/// <summary> public string indexId { get; set; }
/// 允许日志
/// </summary>
public bool logEnabled
{
get; set;
}
/// <summary>
/// 日志等级
/// </summary>
public string loglevel
{
get; set;
}
public string indexId
{
get; set;
}
/// <summary>
/// 允许Mux多路复用
/// </summary>
public bool muxEnabled
{
get; set;
}
/// <summary>
///
/// </summary>
public ESysProxyType sysProxyType
{
get; set;
}
public bool autoRun { get; set; }
/// <summary>
/// 启用实时网速和流量统计
/// </summary>
public bool enableStatistics
{
get; set;
}
/// <summary>
/// 去重时优先保留较旧(顶部)节点
/// </summary>
public bool keepOlderDedupl
{
get; set;
}
/// <summary>
/// 视图刷新率
/// </summary>
public int statisticsFreshRate
{
get; set;
}
/// <summary>
/// 自定义远程DNS
/// </summary>
public string remoteDNS
{
get; set;
}
public string remoteDNS { get; set; }
/// <summary> /// <summary>
/// Outbound Freedom domainStrategy /// Outbound Freedom domainStrategy
/// </summary> /// </summary>
public string domainStrategy4Freedom public string domainStrategy4Freedom { get; set; }
{
get; set;
}
/// <summary> public ESysProxyType sysProxyType { get; set; }
/// 是否允许不安全连接 public string systemProxyExceptions { get; set; }
/// </summary>
public bool defAllowInsecure { get; set; }
public string defFingerprint { get; set; }
/// <summary>
/// 默认用户代理
/// </summary>
public string defUserAgent { get; set; }
/// <summary>
/// 域名解析策略
/// </summary>
public string domainStrategy
{
get; set;
}
public string domainMatcher
{
get; set;
}
public string routingIndexId { get; set; }
public bool enableRoutingAdvanced
{
get; set;
}
public bool ignoreGeoUpdateCore
{
get; set;
}
/// <summary>
/// systemProxyExceptions
/// </summary>
public string systemProxyExceptions
{
get; set;
}
public string systemProxyAdvancedProtocol { get; set; } public string systemProxyAdvancedProtocol { get; set; }
public int autoUpdateInterval { get; set; } = 10;
public int autoUpdateSubInterval { get; set; } = 10;
public bool checkPreReleaseUpdate { get; set; } = false;
public bool enableSecurityProtocolTls13
{
get; set;
}
public int trayMenuServersLimit { get; set; } = 20;
#endregion #endregion
#region other entities #region other entities
public CoreBasicItem coreBasicItem { get; set; }
public TunModeItem tunModeItem { get; set; } public TunModeItem tunModeItem { get; set; }
public KcpItem kcpItem { get; set; } public KcpItem kcpItem { get; set; }
public GrpcItem grpcItem { get; set; } public GrpcItem grpcItem { get; set; }
public RoutingBasicItem routingBasicItem { get; set; }
public GUIItem guiItem { get; set; }
public UIItem uiItem { get; set; } public UIItem uiItem { get; set; }
public ConstItem constItem { get; set; } public ConstItem constItem { get; set; }
public SpeedTestItem speedTestItem { get; set; }
public List<InItem> inbound { get; set; } public List<InItem> inbound { get; set; }
public List<KeyEventItem> globalHotkeys { get; set; } public List<KeyEventItem> globalHotkeys { get; set; }
public List<CoreTypeItem> coreTypeItem { get; set; } public List<CoreTypeItem> coreTypeItem { get; set; }

View File

@@ -2,6 +2,37 @@
namespace v2rayN.Mode namespace v2rayN.Mode
{ {
[Serializable]
public class CoreBasicItem
{
/// <summary>
/// 允许日志
/// </summary>
public bool logEnabled { get; set; }
/// <summary>
/// 日志等级
/// </summary>
public string loglevel { get; set; }
/// <summary>
/// 允许Mux多路复用
/// </summary>
public bool muxEnabled { get; set; }
/// <summary>
/// 是否允许不安全连接
/// </summary>
public bool defAllowInsecure { get; set; }
public string defFingerprint { get; set; }
/// <summary>
/// 默认用户代理
/// </summary>
public string defUserAgent { get; set; }
}
[Serializable] [Serializable]
public class InItem public class InItem
{ {
@@ -51,6 +82,30 @@ namespace v2rayN.Mode
public int initial_windows_size { get; set; } public int initial_windows_size { get; set; }
} }
[Serializable]
public class GUIItem
{
public bool autoRun { get; set; }
public bool enableStatistics { get; set; }
public int statisticsFreshRate { get; set; }
public bool keepOlderDedupl { get; set; }
public bool ignoreGeoUpdateCore { get; set; } = true;
public int autoUpdateInterval { get; set; } = 10;
public int autoUpdateSubInterval { get; set; } = 10;
public bool checkPreReleaseUpdate { get; set; } = false;
public bool enableSecurityProtocolTls13 { get; set; }
public int trayMenuServersLimit { get; set; } = 20;
}
[Serializable] [Serializable]
public class UIItem public class UIItem
{ {
@@ -67,14 +122,13 @@ namespace v2rayN.Mode
public bool enableDragDropSort { get; set; } public bool enableDragDropSort { get; set; }
public bool doubleClick2Activate { get; set; } public bool doubleClick2Activate { get; set; }
public bool autoHideStartup { get; set; } = true; public bool autoHideStartup { get; set; } = true;
public string mainMsgFilter { get; set; }
public Dictionary<string, int> mainLvColWidth { get; set; } public Dictionary<string, int> mainLvColWidth { get; set; }
} }
[Serializable] [Serializable]
public class ConstItem public class ConstItem
{ {
public string speedTestUrl { get; set; }
public string speedPingTestUrl { get; set; }
public string defIEProxyExceptions { get; set; } public string defIEProxyExceptions { get; set; }
} }
@@ -106,6 +160,7 @@ namespace v2rayN.Mode
{ {
public bool enableTun { get; set; } public bool enableTun { get; set; }
public bool showWindow { get; set; } public bool showWindow { get; set; }
public bool enabledLog { get; set; }
public bool strictRoute { get; set; } public bool strictRoute { get; set; }
public string stack { get; set; } public string stack { get; set; }
public int mtu { get; set; } public int mtu { get; set; }
@@ -117,4 +172,25 @@ namespace v2rayN.Mode
public List<string> proxyProcess { get; set; } public List<string> proxyProcess { get; set; }
} }
[Serializable]
public class SpeedTestItem
{
public int speedTestTimeout { get; set; }
public string speedTestUrl { get; set; }
public string speedPingTestUrl { get; set; }
}
[Serializable]
public class RoutingBasicItem
{
/// <summary>
/// 域名解析策略
/// </summary>
public string domainStrategy { get; set; }
public string domainMatcher { get; set; }
public string routingIndexId { get; set; }
public bool enableRoutingAdvanced { get; set; }
}
} }

View File

@@ -0,0 +1,14 @@
using SQLite;
namespace v2rayN.Mode
{
[Serializable]
public class ProfileExItem
{
[PrimaryKey]
public string indexId { get; set; }
public int delay { get; set; }
public decimal speed { get; set; }
public int sort { get; set; }
}
}

View File

@@ -11,7 +11,6 @@ namespace v2rayN.Mode
indexId = string.Empty; indexId = string.Empty;
configType = EConfigType.VMess; configType = EConfigType.VMess;
configVersion = 2; configVersion = 2;
sort = 0;
address = string.Empty; address = string.Empty;
port = 0; port = 0;
id = string.Empty; id = string.Empty;
@@ -107,11 +106,6 @@ namespace v2rayN.Mode
get; set; get; set;
} }
public int sort
{
get; set;
}
/// <summary> /// <summary>
/// 远程服务器地址 /// 远程服务器地址
/// </summary> /// </summary>
@@ -202,9 +196,6 @@ namespace v2rayN.Mode
get; set; get; set;
} }
public int delay { get; set; }
public decimal speed { get; set; }
/// <summary> /// <summary>
/// SubItem id /// SubItem id
/// </summary> /// </summary>

View File

@@ -5,6 +5,9 @@
{ {
public bool isActive { get; set; } public bool isActive { get; set; }
public string subRemarks { get; set; } public string subRemarks { get; set; }
public int delay { get; set; }
public decimal speed { get; set; }
public int sort { get; set; }
public string delayVal { get; set; } public string delayVal { get; set; }
public string speedVal { get; set; } public string speedVal { get; set; }
public string todayUp { get; set; } public string todayUp { get; set; }

View File

@@ -15,6 +15,7 @@ namespace v2rayN.Mode
public bool locked { get; set; } public bool locked { get; set; }
public string customIcon { get; set; } public string customIcon { get; set; }
public string domainStrategy { get; set; } public string domainStrategy { get; set; }
public int sort { get; set; }
} }
} }

View File

@@ -70,7 +70,7 @@ namespace v2rayN.Resx {
} }
/// <summary> /// <summary>
/// 查找类似 All servers 的本地化字符串。 /// 查找类似 All 的本地化字符串。
/// </summary> /// </summary>
public static string AllGroupServers { public static string AllGroupServers {
get { get {
@@ -790,7 +790,7 @@ namespace v2rayN.Resx {
} }
/// <summary> /// <summary>
/// 查找类似 One-click test Latency and speed (Ctrl+E) 的本地化字符串。 /// 查找类似 One-click multi test Latency and speed (Ctrl+E) 的本地化字符串。
/// </summary> /// </summary>
public static string menuMixedTestServer { public static string menuMixedTestServer {
get { get {
@@ -2564,7 +2564,7 @@ namespace v2rayN.Resx {
} }
/// <summary> /// <summary>
/// 查找类似 Record local logs 的本地化字符串。 /// 查找类似 Enable Log 的本地化字符串。
/// </summary> /// </summary>
public static string TbSettingsLogEnabled { public static string TbSettingsLogEnabled {
get { get {
@@ -2689,6 +2689,24 @@ namespace v2rayN.Resx {
} }
} }
/// <summary>
/// 查找类似 SpeedTest Single Timeout Value 的本地化字符串。
/// </summary>
public static string TbSettingsSpeedTestTimeout {
get {
return ResourceManager.GetString("TbSettingsSpeedTestTimeout", resourceCulture);
}
}
/// <summary>
/// 查找类似 SpeedTest Url 的本地化字符串。
/// </summary>
public static string TbSettingsSpeedTestUrl {
get {
return ResourceManager.GetString("TbSettingsSpeedTestUrl", resourceCulture);
}
}
/// <summary> /// <summary>
/// 查找类似 Start on boot 的本地化字符串。 /// 查找类似 Start on boot 的本地化字符串。
/// </summary> /// </summary>
@@ -3050,7 +3068,7 @@ namespace v2rayN.Resx {
} }
/// <summary> /// <summary>
/// 查找类似 *QUIC securty 的本地化字符串。 /// 查找类似 *QUIC security 的本地化字符串。
/// </summary> /// </summary>
public static string TransportRequestHostTip4 { public static string TransportRequestHostTip4 {
get { get {

View File

@@ -419,7 +419,7 @@
<value>*h2 host Separated by commas (,)</value> <value>*h2 host Separated by commas (,)</value>
</data> </data>
<data name="TransportRequestHostTip4" xml:space="preserve"> <data name="TransportRequestHostTip4" xml:space="preserve">
<value>*QUIC securty</value> <value>*QUIC security</value>
</data> </data>
<data name="TransportHeaderTypeTip1" xml:space="preserve"> <data name="TransportHeaderTypeTip1" xml:space="preserve">
<value>*tcp camouflage type</value> <value>*tcp camouflage type</value>
@@ -449,7 +449,7 @@
<value>Ungrouped</value> <value>Ungrouped</value>
</data> </data>
<data name="AllGroupServers" xml:space="preserve"> <data name="AllGroupServers" xml:space="preserve">
<value>All servers</value> <value>All</value>
</data> </data>
<data name="FillServerAddressCustom" xml:space="preserve"> <data name="FillServerAddressCustom" xml:space="preserve">
<value>Please browse to import server configuration</value> <value>Please browse to import server configuration</value>
@@ -815,7 +815,7 @@
<value>Keep older when deduplication</value> <value>Keep older when deduplication</value>
</data> </data>
<data name="TbSettingsLogEnabled" xml:space="preserve"> <data name="TbSettingsLogEnabled" xml:space="preserve">
<value>Record local logs</value> <value>Enable Log</value>
</data> </data>
<data name="TbSettingsLogLevel" xml:space="preserve"> <data name="TbSettingsLogLevel" xml:space="preserve">
<value>Log Level</value> <value>Log Level</value>
@@ -1022,7 +1022,7 @@
<value>RouteOnly</value> <value>RouteOnly</value>
</data> </data>
<data name="menuMixedTestServer" xml:space="preserve"> <data name="menuMixedTestServer" xml:space="preserve">
<value>One-click test Latency and speed (Ctrl+E)</value> <value>One-click multi test Latency and speed (Ctrl+E)</value>
</data> </data>
<data name="LvTestDelay" xml:space="preserve"> <data name="LvTestDelay" xml:space="preserve">
<value>Delay(ms)</value> <value>Delay(ms)</value>
@@ -1120,4 +1120,10 @@
<data name="TbSettingsTunModeBypassModeTip" xml:space="preserve"> <data name="TbSettingsTunModeBypassModeTip" xml:space="preserve">
<value>Enable: If no route matches, the final proxy</value> <value>Enable: If no route matches, the final proxy</value>
</data> </data>
<data name="TbSettingsSpeedTestTimeout" xml:space="preserve">
<value>SpeedTest Single Timeout Value</value>
</data>
<data name="TbSettingsSpeedTestUrl" xml:space="preserve">
<value>SpeedTest Url</value>
</data>
</root> </root>

File diff suppressed because it is too large Load Diff

View File

@@ -130,7 +130,7 @@
<value>配置格式不正确</value> <value>配置格式不正确</value>
</data> </data>
<data name="CustomServerTips" xml:space="preserve"> <data name="CustomServerTips" xml:space="preserve">
<value>注意,自定义配置完全依赖您自己的配置,不能使用所有设置功能。如需使用系统代理请手修改监听端口。</value> <value>注意,自定义配置完全依赖您自己的配置,不能使用所有设置功能。如需使用系统代理请手修改监听端口。</value>
</data> </data>
<data name="Downloading" xml:space="preserve"> <data name="Downloading" xml:space="preserve">
<value>下载开始...</value> <value>下载开始...</value>
@@ -148,7 +148,7 @@
<value>生成默认配置文件失败</value> <value>生成默认配置文件失败</value>
</data> </data>
<data name="FailedGetDefaultConfiguration" xml:space="preserve"> <data name="FailedGetDefaultConfiguration" xml:space="preserve">
<value>取默认配置失败</value> <value>取默认配置失败</value>
</data> </data>
<data name="FailedImportedCustomServer" xml:space="preserve"> <data name="FailedImportedCustomServer" xml:space="preserve">
<value>导入自定义配置服务器失败</value> <value>导入自定义配置服务器失败</value>
@@ -449,7 +449,7 @@
<value>未分组服务器</value> <value>未分组服务器</value>
</data> </data>
<data name="AllGroupServers" xml:space="preserve"> <data name="AllGroupServers" xml:space="preserve">
<value>所有服务器</value> <value>所有</value>
</data> </data>
<data name="FillServerAddressCustom" xml:space="preserve"> <data name="FillServerAddressCustom" xml:space="preserve">
<value>请浏览导入服务器配置</value> <value>请浏览导入服务器配置</value>
@@ -815,7 +815,7 @@
<value>去重时保留序号较小的项</value> <value>去重时保留序号较小的项</value>
</data> </data>
<data name="TbSettingsLogEnabled" xml:space="preserve"> <data name="TbSettingsLogEnabled" xml:space="preserve">
<value>记录本地日志(默认关闭)</value> <value>启用日志(默认关闭)</value>
</data> </data>
<data name="TbSettingsLogLevel" xml:space="preserve"> <data name="TbSettingsLogLevel" xml:space="preserve">
<value>日志等级</value> <value>日志等级</value>
@@ -905,7 +905,7 @@
<value>路由</value> <value>路由</value>
</data> </data>
<data name="NotRunAsAdmin" xml:space="preserve"> <data name="NotRunAsAdmin" xml:space="preserve">
<value>以管理员身份运行</value> <value>以管理员身份运行</value>
</data> </data>
<data name="RunAsAdmin" xml:space="preserve"> <data name="RunAsAdmin" xml:space="preserve">
<value>以管理员身份运行</value> <value>以管理员身份运行</value>
@@ -1022,7 +1022,7 @@
<value>RouteOnly</value> <value>RouteOnly</value>
</data> </data>
<data name="menuMixedTestServer" xml:space="preserve"> <data name="menuMixedTestServer" xml:space="preserve">
<value>一键测试延迟和速度 (Ctrl+E)</value> <value>一键多线程测试延迟和速度 (Ctrl+E)</value>
</data> </data>
<data name="LvTestDelay" xml:space="preserve"> <data name="LvTestDelay" xml:space="preserve">
<value>延迟(ms)</value> <value>延迟(ms)</value>
@@ -1120,4 +1120,10 @@
<data name="TbSettingsTunModeBypassModeTip" xml:space="preserve"> <data name="TbSettingsTunModeBypassModeTip" xml:space="preserve">
<value>启用:路由无匹配则最终代理</value> <value>启用:路由无匹配则最终代理</value>
</data> </data>
<data name="TbSettingsSpeedTestTimeout" xml:space="preserve">
<value>测速单个超时值</value>
</data>
<data name="TbSettingsSpeedTestUrl" xml:space="preserve">
<value>测速文件地址</value>
</data>
</root> </root>

View File

@@ -1,6 +1,6 @@
{ {
"log": { "log": {
"disabled": false, "disabled": $log_disabled$,
"level": "debug", "level": "debug",
$log_output$ $log_output$
"timestamp": true "timestamp": true

View File

@@ -10,8 +10,7 @@ namespace v2rayN.Tool
{ {
try try
{ {
using (FileStream fs = new FileStream(fileName, FileMode.Create, FileAccess.Write)) File.WriteAllBytes(fileName, content);
fs.Write(content, 0, content.Length);
return true; return true;
} }
catch (Exception ex) catch (Exception ex)
@@ -25,20 +24,9 @@ namespace v2rayN.Tool
{ {
try try
{ {
// Because the uncompressed size of the file is unknown, using FileStream fs = File.Create(fileName);
// we are using an arbitrary buffer size. using GZipStream input = new(new MemoryStream(content), CompressionMode.Decompress, false);
byte[] buffer = new byte[4096]; input.CopyTo(fs);
int n;
using (FileStream fs = File.Create(fileName))
using (GZipStream input = new GZipStream(new MemoryStream(content),
CompressionMode.Decompress, false))
{
while ((n = input.Read(buffer, 0, buffer.Length)) > 0)
{
fs.Write(buffer, 0, n);
}
}
} }
catch (Exception ex) catch (Exception ex)
{ {
@@ -55,24 +43,21 @@ namespace v2rayN.Tool
{ {
try try
{ {
using (FileStream fs = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)) using FileStream fs = new(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
using (StreamReader sr = new StreamReader(fs, encoding)) using StreamReader sr = new(fs, encoding);
{
return sr.ReadToEnd(); return sr.ReadToEnd();
} }
}
catch (Exception ex) catch (Exception ex)
{ {
Utils.SaveLog(ex.Message, ex); Utils.SaveLog(ex.Message, ex);
throw ex; throw;
} }
} }
public static bool ZipExtractToFile(string fileName, string toPath, string ignoredName) public static bool ZipExtractToFile(string fileName, string toPath, string ignoredName)
{ {
try try
{ {
using (ZipArchive archive = ZipFile.OpenRead(fileName)) using ZipArchive archive = ZipFile.OpenRead(fileName);
{
foreach (ZipArchiveEntry entry in archive.Entries) foreach (ZipArchiveEntry entry in archive.Entries)
{ {
if (entry.Length == 0) if (entry.Length == 0)
@@ -93,7 +78,6 @@ namespace v2rayN.Tool
} }
} }
} }
}
catch (Exception ex) catch (Exception ex)
{ {
Utils.SaveLog(ex.Message, ex); Utils.SaveLog(ex.Message, ex);

View File

@@ -16,12 +16,12 @@ namespace v2rayN
{ {
handle = CreateJobObject(IntPtr.Zero, null); handle = CreateJobObject(IntPtr.Zero, null);
IntPtr extendedInfoPtr = IntPtr.Zero; IntPtr extendedInfoPtr = IntPtr.Zero;
JOBOBJECT_BASIC_LIMIT_INFORMATION info = new JOBOBJECT_BASIC_LIMIT_INFORMATION JOBOBJECT_BASIC_LIMIT_INFORMATION info = new()
{ {
LimitFlags = 0x2000 LimitFlags = 0x2000
}; };
JOBOBJECT_EXTENDED_LIMIT_INFORMATION extendedInfo = new JOBOBJECT_EXTENDED_LIMIT_INFORMATION JOBOBJECT_EXTENDED_LIMIT_INFORMATION extendedInfo = new()
{ {
BasicLimitInformation = info BasicLimitInformation = info
}; };
@@ -100,7 +100,7 @@ namespace v2rayN
#region Interop #region Interop
[DllImport("kernel32.dll", CharSet = CharSet.Unicode)] [DllImport("kernel32.dll", CharSet = CharSet.Unicode)]
private static extern IntPtr CreateJobObject(IntPtr a, string lpName); private static extern IntPtr CreateJobObject(IntPtr a, string? lpName);
[DllImport("kernel32.dll", SetLastError = true)] [DllImport("kernel32.dll", SetLastError = true)]
private static extern bool SetInformationJobObject(IntPtr hJob, JobObjectInfoType infoType, IntPtr lpJobObjectInfo, UInt32 cbJobObjectInfoLength); private static extern bool SetInformationJobObject(IntPtr hJob, JobObjectInfoType infoType, IntPtr lpJobObjectInfo, UInt32 cbJobObjectInfoLength);

View File

@@ -9,8 +9,8 @@ namespace v2rayN.Tool
{ {
public static void Setup() public static void Setup()
{ {
LoggingConfiguration config = new LoggingConfiguration(); LoggingConfiguration config = new();
FileTarget fileTarget = new FileTarget(); FileTarget fileTarget = new();
config.AddTarget("file", fileTarget); config.AddTarget("file", fileTarget);
fileTarget.Layout = "${longdate}-${level:uppercase=true} ${message}"; fileTarget.Layout = "${longdate}-${level:uppercase=true} ${message}";
fileTarget.FileName = Utils.GetLogPath("${shortdate}.txt"); fileTarget.FileName = Utils.GetLogPath("${shortdate}.txt");

View File

@@ -48,12 +48,11 @@ namespace v2rayN
try try
{ {
Assembly assembly = Assembly.GetExecutingAssembly(); Assembly assembly = Assembly.GetExecutingAssembly();
using (Stream stream = assembly.GetManifestResourceStream(res)) using Stream? stream = assembly.GetManifestResourceStream(res);
using (StreamReader reader = new StreamReader(stream)) ArgumentNullException.ThrowIfNull(stream);
{ using StreamReader reader = new(stream);
result = reader.ReadToEnd(); result = reader.ReadToEnd();
} }
}
catch (Exception ex) catch (Exception ex)
{ {
SaveLog(ex.Message, ex); SaveLog(ex.Message, ex);
@@ -72,10 +71,12 @@ namespace v2rayN
try try
{ {
using (StreamReader reader = new StreamReader(res)) if (!File.Exists(res))
{ {
result = reader.ReadToEnd(); return result;
} }
using StreamReader reader = new(res);
result = reader.ReadToEnd();
} }
catch (Exception ex) catch (Exception ex)
{ {
@@ -90,7 +91,7 @@ namespace v2rayN
/// <typeparam name="T"></typeparam> /// <typeparam name="T"></typeparam>
/// <param name="strJson"></param> /// <param name="strJson"></param>
/// <returns></returns> /// <returns></returns>
public static T FromJson<T>(string strJson) public static T? FromJson<T>(string strJson)
{ {
try try
{ {
@@ -98,8 +99,7 @@ namespace v2rayN
{ {
return default; return default;
} }
T obj = JsonConvert.DeserializeObject<T>(strJson); return JsonConvert.DeserializeObject<T>(strJson);
return obj;
} }
catch catch
{ {
@@ -112,7 +112,7 @@ namespace v2rayN
/// </summary> /// </summary>
/// <param name="obj"></param> /// <param name="obj"></param>
/// <returns></returns> /// <returns></returns>
public static string ToJson(Object obj, bool indented = true) public static string ToJson(object? obj, bool indented = true)
{ {
string result = string.Empty; string result = string.Empty;
try try
@@ -141,13 +141,12 @@ namespace v2rayN
/// <param name="obj"></param> /// <param name="obj"></param>
/// <param name="filePath"></param> /// <param name="filePath"></param>
/// <returns></returns> /// <returns></returns>
public static int ToJsonFile(Object obj, string filePath, bool nullValue = true) public static int ToJsonFile(object? obj, string filePath, bool nullValue = true)
{ {
int result; int result;
try try
{ {
using (StreamWriter file = File.CreateText(filePath)) using StreamWriter file = File.CreateText(filePath);
{
JsonSerializer serializer; JsonSerializer serializer;
if (nullValue) if (nullValue)
{ {
@@ -159,7 +158,6 @@ namespace v2rayN
} }
serializer.Serialize(file, obj); serializer.Serialize(file, obj);
}
result = 0; result = 0;
} }
catch (Exception ex) catch (Exception ex)
@@ -170,7 +168,7 @@ namespace v2rayN
return result; return result;
} }
public static JObject ParseJson(string strJson) public static JObject? ParseJson(string strJson)
{ {
try try
{ {
@@ -202,7 +200,7 @@ namespace v2rayN
} }
if (wrap) if (wrap)
{ {
return string.Join("," + Environment.NewLine, lst.ToArray()); return string.Join("," + Environment.NewLine, lst);
} }
else else
{ {
@@ -225,7 +223,7 @@ namespace v2rayN
try try
{ {
str = str.Replace(Environment.NewLine, ""); str = str.Replace(Environment.NewLine, "");
return new List<string>(str.Split(new string[] { "," }, StringSplitOptions.RemoveEmptyEntries)); return new List<string>(str.Split(',', StringSplitOptions.RemoveEmptyEntries));
} }
catch (Exception ex) catch (Exception ex)
{ {
@@ -244,8 +242,9 @@ namespace v2rayN
try try
{ {
str = str.Replace(Environment.NewLine, ""); str = str.Replace(Environment.NewLine, "");
List<string> list = new List<string>(str.Split(new string[] { "," }, StringSplitOptions.RemoveEmptyEntries)); List<string> list = new(str.Split(',', StringSplitOptions.RemoveEmptyEntries));
return list.OrderBy(x => x).ToList(); list.Sort();
return list;
} }
catch (Exception ex) catch (Exception ex)
{ {
@@ -337,7 +336,7 @@ namespace v2rayN
{ {
try try
{ {
return (obj == null ? string.Empty : obj.ToString()); return obj?.ToString() ?? string.Empty;
} }
catch (Exception ex) catch (Exception ex)
{ {
@@ -414,10 +413,9 @@ namespace v2rayN
public static string GetMD5(string str) public static string GetMD5(string str)
{ {
var md5 = MD5.Create();
byte[] byteOld = Encoding.UTF8.GetBytes(str); byte[] byteOld = Encoding.UTF8.GetBytes(str);
byte[] byteNew = md5.ComputeHash(byteOld); byte[] byteNew = MD5.HashData(byteOld);
StringBuilder sb = new StringBuilder(); StringBuilder sb = new(32);
foreach (byte b in byteNew) foreach (byte b in byteNew)
{ {
sb.Append(b.ToString("x2")); sb.Append(b.ToString("x2"));
@@ -440,7 +438,7 @@ namespace v2rayN
} }
try try
{ {
Uri uri = new Uri(url); Uri uri = new(url);
if (uri.Host == uri.IdnHost) if (uri.Host == uri.IdnHost)
{ {
return url; return url;
@@ -568,18 +566,14 @@ namespace v2rayN
public static bool IsIpv6(string ip) public static bool IsIpv6(string ip)
{ {
IPAddress address; if (IPAddress.TryParse(ip, out IPAddress? address))
if (IPAddress.TryParse(ip, out address))
{ {
switch (address.AddressFamily) return address.AddressFamily switch
{ {
case AddressFamily.InterNetwork: AddressFamily.InterNetwork => false,
return false; AddressFamily.InterNetworkV6 => true,
case AddressFamily.InterNetworkV6: _ => false,
return true; };
default:
return false;
}
} }
return false; return false;
} }
@@ -682,13 +676,13 @@ namespace v2rayN
return Application.StartupPath; return Application.StartupPath;
} }
public static string RegReadValue(string path, string name, string def) public static string? RegReadValue(string path, string name, string def)
{ {
RegistryKey regKey = null; RegistryKey? regKey = null;
try try
{ {
regKey = Registry.CurrentUser.OpenSubKey(path, false); regKey = Registry.CurrentUser.OpenSubKey(path, false);
string value = regKey?.GetValue(name) as string; string? value = regKey?.GetValue(name) as string;
if (IsNullOrEmpty(value)) if (IsNullOrEmpty(value))
{ {
return def; return def;
@@ -711,7 +705,7 @@ namespace v2rayN
public static void RegWriteValue(string path, string name, object value) public static void RegWriteValue(string path, string name, object value)
{ {
RegistryKey regKey = null; RegistryKey? regKey = null;
try try
{ {
regKey = Registry.CurrentUser.CreateSubKey(path); regKey = Registry.CurrentUser.CreateSubKey(path);
@@ -743,15 +737,13 @@ namespace v2rayN
public static bool CheckForDotNetVersion(int release = 528040) public static bool CheckForDotNetVersion(int release = 528040)
{ {
const string subkey = @"SOFTWARE\Microsoft\NET Framework Setup\NDP\v4\Full\"; const string subkey = @"SOFTWARE\Microsoft\NET Framework Setup\NDP\v4\Full\";
using (RegistryKey ndpKey = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Registry32).OpenSubKey(subkey)) using RegistryKey? ndpKey = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Registry32).OpenSubKey(subkey);
{
if (ndpKey != null && ndpKey.GetValue("Release") != null) if (ndpKey != null && ndpKey.GetValue("Release") != null)
{ {
return (int)ndpKey.GetValue("Release") >= release ? true : false; return (int)ndpKey.GetValue("Release") >= release ? true : false;
} }
return false; return false;
} }
}
/// <summary> /// <summary>
/// Auto Start via TaskService /// Auto Start via TaskService
@@ -771,8 +763,7 @@ namespace v2rayN
string taskDescription = description; string taskDescription = description;
string deamonFileName = fileName; string deamonFileName = fileName;
using (var taskService = new TaskService()) using var taskService = new TaskService();
{
var tasks = taskService.RootFolder.GetTasks(new Regex(TaskName)); var tasks = taskService.RootFolder.GetTasks(new Regex(TaskName));
foreach (var t in tasks) foreach (var t in tasks)
{ {
@@ -786,13 +777,16 @@ namespace v2rayN
var task = taskService.NewTask(); var task = taskService.NewTask();
task.RegistrationInfo.Description = taskDescription; task.RegistrationInfo.Description = taskDescription;
task.Settings.DisallowStartIfOnBatteries = false; task.Settings.DisallowStartIfOnBatteries = false;
task.Settings.StopIfGoingOnBatteries = false;
task.Settings.RunOnlyIfIdle = false;
task.Settings.IdleSettings.StopOnIdleEnd = false;
task.Settings.ExecutionTimeLimit = TimeSpan.Zero;
task.Triggers.Add(new LogonTrigger { UserId = logonUser, Delay = TimeSpan.FromMinutes(1) }); task.Triggers.Add(new LogonTrigger { UserId = logonUser, Delay = TimeSpan.FromMinutes(1) });
task.Principal.RunLevel = TaskRunLevel.Highest; task.Principal.RunLevel = TaskRunLevel.Highest;
task.Actions.Add(new ExecAction(deamonFileName)); task.Actions.Add(new ExecAction(deamonFileName));
taskService.RootFolder.RegisterTaskDefinition(TaskName, task); taskService.RootFolder.RegisterTaskDefinition(TaskName, task);
} }
}
#endregion #endregion
@@ -900,16 +894,13 @@ namespace v2rayN
public static T DeepCopy<T>(T obj) public static T DeepCopy<T>(T obj)
{ {
object retval; object retval;
using (MemoryStream ms = new MemoryStream()) MemoryStream ms = new MemoryStream();
{
BinaryFormatter bf = new BinaryFormatter(); BinaryFormatter bf = new BinaryFormatter();
//序列化成流 //序列化成流
bf.Serialize(ms, obj); bf.Serialize(ms, obj);
ms.Seek(0, SeekOrigin.Begin); ms.Seek(0, SeekOrigin.Begin);
//反序列化成对象 //反序列化成对象
retval = bf.Deserialize(ms); retval = bf.Deserialize(ms);
ms.Close();
}
return (T)retval; return (T)retval;
} }
@@ -917,7 +908,7 @@ namespace v2rayN
/// 获取剪贴板数 /// 获取剪贴板数
/// </summary> /// </summary>
/// <returns></returns> /// <returns></returns>
public static string GetClipboardData() public static string? GetClipboardData()
{ {
string strData = string.Empty; string strData = string.Empty;
try try
@@ -1004,7 +995,7 @@ namespace v2rayN
return fileName; return fileName;
} }
public static IPAddress GetDefaultGateway() public static IPAddress? GetDefaultGateway()
{ {
return NetworkInterface return NetworkInterface
.GetAllNetworkInterfaces() .GetAllNetworkInterfaces()
@@ -1067,14 +1058,11 @@ namespace v2rayN
public static string UnGzip(byte[] buf) public static string UnGzip(byte[] buf)
{ {
MemoryStream sb = new MemoryStream(); using MemoryStream sb = new();
using (GZipStream input = new GZipStream(new MemoryStream(buf), using GZipStream input = new(new MemoryStream(buf), CompressionMode.Decompress, false);
CompressionMode.Decompress,
false))
{
input.CopyTo(sb); input.CopyTo(sb);
} sb.Position = 0;
return Encoding.UTF8.GetString(sb.ToArray()); return new StreamReader(sb, Encoding.UTF8).ReadToEnd();
} }
public static string GetBackupPath(string filename) public static string GetBackupPath(string filename)
@@ -1117,8 +1105,15 @@ namespace v2rayN
Directory.CreateDirectory(_tempPath); Directory.CreateDirectory(_tempPath);
} }
} }
if (string.IsNullOrEmpty(filename))
{
return _tempPath;
}
else
{
return Path.Combine(_tempPath, filename); return Path.Combine(_tempPath, filename);
} }
}
public static string GetLogPath(string filename = "") public static string GetLogPath(string filename = "")
{ {
string _tempPath = Path.Combine(StartupPath(), "guiLogs"); string _tempPath = Path.Combine(StartupPath(), "guiLogs");
@@ -1183,9 +1178,8 @@ namespace v2rayN
{ {
foreach (Screen screen in Screen.AllScreens) foreach (Screen screen in Screen.AllScreens)
{ {
using (Bitmap fullImage = new Bitmap(screen.Bounds.Width, using Bitmap fullImage = new Bitmap(screen.Bounds.Width,
screen.Bounds.Height)) screen.Bounds.Height);
{
using (Graphics g = Graphics.FromImage(fullImage)) using (Graphics g = Graphics.FromImage(fullImage))
{ {
g.CopyFromScreen(screen.Bounds.X, g.CopyFromScreen(screen.Bounds.X,
@@ -1222,7 +1216,6 @@ namespace v2rayN
} }
} }
} }
}
catch (Exception ex) catch (Exception ex)
{ {
SaveLog(ex.Message, ex); SaveLog(ex.Message, ex);

View File

@@ -106,7 +106,7 @@ namespace v2rayN.ViewModels
{ {
UI.Show(ResUI.CustomServerTips); UI.Show(ResUI.CustomServerTips);
OpenFileDialog fileDialog = new OpenFileDialog OpenFileDialog fileDialog = new()
{ {
Multiselect = false, Multiselect = false,
Filter = "Config|*.json|YAML|*.yaml;*.yml|All|*.*" Filter = "Config|*.json|YAML|*.yaml;*.yml|All|*.*"
@@ -121,10 +121,7 @@ namespace v2rayN.ViewModels
return; return;
} }
var item = LazyConfig.Instance.GetProfileItem(SelectedSource.indexId); var item = LazyConfig.Instance.GetProfileItem(SelectedSource.indexId);
if (item is null) item ??= SelectedSource;
{
item = SelectedSource;
}
item.address = fileName; item.address = fileName;
if (ConfigHandler.AddCustomServer(ref _config, item, false) == 0) if (ConfigHandler.AddCustomServer(ref _config, item, false) == 0)
{ {

View File

@@ -37,7 +37,7 @@ namespace v2rayN.ViewModels
private string _serverFilter = string.Empty; private string _serverFilter = string.Empty;
private static Config _config; private static Config _config;
private NoticeHandler? _noticeHandler; private NoticeHandler? _noticeHandler;
private readonly PaletteHelper _paletteHelper = new PaletteHelper(); private readonly PaletteHelper _paletteHelper = new();
private Dictionary<int, bool> _dicHeaderSort = new(); private Dictionary<int, bool> _dicHeaderSort = new();
private Action<string> _updateView; private Action<string> _updateView;
@@ -254,7 +254,7 @@ namespace v2rayN.ViewModels
SystemProxySelected = (int)_config.sysProxyType; SystemProxySelected = (int)_config.sysProxyType;
this.WhenAnyValue( this.WhenAnyValue(
x => x.SystemProxySelected, x => x.SystemProxySelected,
y => y != null && y >= 0) y => y >= 0)
.Subscribe(c => DoSystemProxySelected(c)); .Subscribe(c => DoSystemProxySelected(c));
this.WhenAnyValue( this.WhenAnyValue(
@@ -506,7 +506,7 @@ namespace v2rayN.ViewModels
//MainFormHandler.Instance.BackupGuiNConfig(_config, true); //MainFormHandler.Instance.BackupGuiNConfig(_config, true);
_coreHandler = new CoreHandler(UpdateHandler); _coreHandler = new CoreHandler(UpdateHandler);
if (_config.enableStatistics) if (_config.guiItem.enableStatistics)
{ {
_statistics = new StatisticsHandler(_config, UpdateStatisticsHandler); _statistics = new StatisticsHandler(_config, UpdateStatisticsHandler);
} }
@@ -532,7 +532,7 @@ namespace v2rayN.ViewModels
{ {
_noticeHandler?.SendMessage(msg); _noticeHandler?.SendMessage(msg);
} }
private async void UpdateTaskHandler(bool success, string msg) private void UpdateTaskHandler(bool success, string msg)
{ {
_noticeHandler?.SendMessage(msg); _noticeHandler?.SendMessage(msg);
if (success) if (success)
@@ -664,6 +664,8 @@ namespace v2rayN.ViewModels
SysProxyHandle.UpdateSysProxy(_config, true); SysProxyHandle.UpdateSysProxy(_config, true);
} }
ProfileExHandler.Instance.SaveTo();
_statistics?.SaveTo(); _statistics?.SaveTo();
_statistics?.Close(); _statistics?.Close();
@@ -708,19 +710,19 @@ namespace v2rayN.ViewModels
private void RefreshServers() private void RefreshServers()
{ {
List<ProfileItemModel> lstModel = LazyConfig.Instance.ProfileItems(_subId, _serverFilter); List<ProfileItemModel> lstModel = LazyConfig.Instance.ProfileItems(_subId, _serverFilter);
_lstProfile = Utils.FromJson<List<ProfileItem>>(Utils.ToJson(lstModel)); ConfigHandler.SetDefaultServer(_config, lstModel);
ConfigHandler.SetDefaultServer(_config, _lstProfile);
List<ServerStatItem> lstServerStat = new(); List<ServerStatItem> lstServerStat = new();
if (_statistics != null && _statistics.Enable) if (_statistics != null && _statistics.Enable)
{ {
lstServerStat = _statistics.ServerStat; lstServerStat = _statistics.ServerStat;
} }
var lstProfileExs = ProfileExHandler.Instance.ProfileExs;
lstModel = (from t in lstModel lstModel = (from t in lstModel
join t2 in lstServerStat join t2 in lstServerStat on t.indexId equals t2.indexId into t2b
on t.indexId equals t2.indexId into t2b
from t22 in t2b.DefaultIfEmpty() from t22 in t2b.DefaultIfEmpty()
join t3 in lstProfileExs on t.indexId equals t3.indexId into t3b
from t33 in t3b.DefaultIfEmpty()
select new ProfileItemModel select new ProfileItemModel
{ {
indexId = t.indexId, indexId = t.indexId,
@@ -733,14 +735,15 @@ namespace v2rayN.ViewModels
streamSecurity = t.streamSecurity, streamSecurity = t.streamSecurity,
subRemarks = t.subRemarks, subRemarks = t.subRemarks,
isActive = t.indexId == _config.indexId, isActive = t.indexId == _config.indexId,
delay = t.delay, sort = t33 == null ? 0 : t33.sort,
delayVal = t.delay != 0 ? $"{t.delay} {Global.DelayUnit}" : string.Empty, delayVal = t33?.delay != 0 ? $"{t33?.delay} {Global.DelayUnit}" : string.Empty,
speedVal = t.speed != 0 ? $"{t.speed} {Global.SpeedUnit}" : string.Empty, speedVal = t33?.speed != 0 ? $"{t33?.speed} {Global.SpeedUnit}" : string.Empty,
todayDown = t22 == null ? "" : Utils.HumanFy(t22.todayDown), todayDown = t22 == null ? "" : Utils.HumanFy(t22.todayDown),
todayUp = t22 == null ? "" : Utils.HumanFy(t22.todayUp), todayUp = t22 == null ? "" : Utils.HumanFy(t22.todayUp),
totalDown = t22 == null ? "" : Utils.HumanFy(t22.totalDown), totalDown = t22 == null ? "" : Utils.HumanFy(t22.totalDown),
totalUp = t22 == null ? "" : Utils.HumanFy(t22.totalUp) totalUp = t22 == null ? "" : Utils.HumanFy(t22.totalUp)
}).ToList(); }).OrderBy(t => t.sort).ToList();
_lstProfile = Utils.FromJson<List<ProfileItem>>(Utils.ToJson(lstModel));
Application.Current.Dispatcher.Invoke((Action)(() => Application.Current.Dispatcher.Invoke((Action)(() =>
{ {
@@ -773,7 +776,7 @@ namespace v2rayN.ViewModels
private void RefreshServersMenu() private void RefreshServersMenu()
{ {
_servers.Clear(); _servers.Clear();
if (_lstProfile.Count > _config.trayMenuServersLimit) if (_lstProfile.Count > _config.guiItem.trayMenuServersLimit)
{ {
return; return;
} }
@@ -801,8 +804,15 @@ namespace v2rayN.ViewModels
{ {
_subItems.Add(item); _subItems.Add(item);
} }
if (_subId != null && _subItems.FirstOrDefault(t => t.id == _subId) != null)
{
SelectedSub = _subItems.FirstOrDefault(t => t.id == _subId);
}
else
{
SelectedSub = _subItems[0]; SelectedSub = _subItems[0];
} }
}
#endregion #endregion
@@ -810,7 +820,7 @@ namespace v2rayN.ViewModels
private int GetProfileItems(out List<ProfileItem> lstSelecteds) private int GetProfileItems(out List<ProfileItem> lstSelecteds)
{ {
lstSelecteds = new List<ProfileItem>(); lstSelecteds = new List<ProfileItem>();
if (SelectedProfiles == null || SelectedProfiles.Count() <= 0) if (SelectedProfiles == null || SelectedProfiles.Count <= 0)
{ {
return -1; return -1;
} }
@@ -834,7 +844,6 @@ namespace v2rayN.ViewModels
{ {
subid = _subId, subid = _subId,
configType = eConfigType, configType = eConfigType,
displayLog = false
}; };
} }
else else
@@ -876,6 +885,7 @@ namespace v2rayN.ViewModels
int ret = ConfigHandler.AddBatchServers(ref _config, clipboardData, _subId, false); int ret = ConfigHandler.AddBatchServers(ref _config, clipboardData, _subId, false);
if (ret > 0) if (ret > 0)
{ {
InitSubscriptionView();
RefreshServers(); RefreshServers();
_noticeHandler?.Enqueue(string.Format(ResUI.SuccessfullyImportedServerViaClipboard, ret)); _noticeHandler?.Enqueue(string.Format(ResUI.SuccessfullyImportedServerViaClipboard, ret));
} }
@@ -900,6 +910,7 @@ namespace v2rayN.ViewModels
int ret = ConfigHandler.AddBatchServers(ref _config, result, _subId, false); int ret = ConfigHandler.AddBatchServers(ref _config, result, _subId, false);
if (ret > 0) if (ret > 0)
{ {
InitSubscriptionView();
RefreshServers(); RefreshServers();
_noticeHandler?.Enqueue(ResUI.SuccessfullyImportedServerViaScan); _noticeHandler?.Enqueue(ResUI.SuccessfullyImportedServerViaScan);
} }
@@ -974,7 +985,7 @@ namespace v2rayN.ViewModels
return; return;
} }
if (ConfigHandler.SetDefaultServer(ref _config, item) == 0) if (ConfigHandler.SetDefaultServerIndex(ref _config, indexId) == 0)
{ {
RefreshServers(); RefreshServers();
Reload(); Reload();
@@ -1158,7 +1169,7 @@ namespace v2rayN.ViewModels
return; return;
} }
StringBuilder sb = new StringBuilder(); StringBuilder sb = new();
foreach (var it in lstSelecteds) foreach (var it in lstSelecteds)
{ {
string url = ShareHandler.GetShareUrl(it); string url = ShareHandler.GetShareUrl(it);
@@ -1183,10 +1194,10 @@ namespace v2rayN.ViewModels
return; return;
} }
StringBuilder sb = new StringBuilder(); StringBuilder sb = new();
foreach (var it in lstSelecteds) foreach (var it in lstSelecteds)
{ {
string url = ShareHandler.GetShareUrl(it); string? url = ShareHandler.GetShareUrl(it);
if (Utils.IsNullOrEmpty(url)) if (Utils.IsNullOrEmpty(url))
{ {
continue; continue;
@@ -1257,7 +1268,7 @@ namespace v2rayN.ViewModels
private void ImportOldGuiConfig() private void ImportOldGuiConfig()
{ {
OpenFileDialog fileDialog = new OpenFileDialog OpenFileDialog fileDialog = new()
{ {
Multiselect = false, Multiselect = false,
Filter = "guiNConfig|*.json|All|*.*" Filter = "guiNConfig|*.json|All|*.*"
@@ -1301,7 +1312,7 @@ namespace v2rayN.ViewModels
MyAppExit(false); MyAppExit(false);
} }
}; };
(new UpdateHandle()).CheckUpdateGuiN(_config, _updateUI, _config.checkPreReleaseUpdate); (new UpdateHandle()).CheckUpdateGuiN(_config, _updateUI, _config.guiItem.checkPreReleaseUpdate);
} }
private void CheckUpdateCore(ECoreType type) private void CheckUpdateCore(ECoreType type)
@@ -1316,7 +1327,7 @@ namespace v2rayN.ViewModels
string fileName = Utils.GetTempPath(Utils.GetDownloadFileName(msg)); string fileName = Utils.GetTempPath(Utils.GetDownloadFileName(msg));
string toPath = Utils.GetBinPath("", type); string toPath = Utils.GetBinPath("", type);
FileManager.ZipExtractToFile(fileName, toPath, _config.ignoreGeoUpdateCore ? "geo" : ""); FileManager.ZipExtractToFile(fileName, toPath, _config.guiItem.ignoreGeoUpdateCore ? "geo" : "");
_noticeHandler?.SendMessage(ResUI.MsgUpdateV2rayCoreSuccessfullyMore); _noticeHandler?.SendMessage(ResUI.MsgUpdateV2rayCoreSuccessfullyMore);
@@ -1330,7 +1341,7 @@ namespace v2rayN.ViewModels
} }
} }
}; };
(new UpdateHandle()).CheckUpdateCore(type, _config, _updateUI, _config.checkPreReleaseUpdate); (new UpdateHandle()).CheckUpdateCore(type, _config, _updateUI, _config.guiItem.checkPreReleaseUpdate);
} }
private void CheckUpdateGeo() private void CheckUpdateGeo()
@@ -1434,7 +1445,7 @@ namespace v2rayN.ViewModels
private void RefreshRoutingsMenu() private void RefreshRoutingsMenu()
{ {
_routingItems.Clear(); _routingItems.Clear();
if (!_config.enableRoutingAdvanced) if (!_config.routingBasicItem.enableRoutingAdvanced)
{ {
BlRouting = false; BlRouting = false;
return; return;
@@ -1445,7 +1456,7 @@ namespace v2rayN.ViewModels
foreach (var item in routings) foreach (var item in routings)
{ {
_routingItems.Add(item); _routingItems.Add(item);
if (item.id.Equals(_config.routingIndexId)) if (item.id.Equals(_config.routingBasicItem.routingIndexId))
{ {
SelectedRouting = item; SelectedRouting = item;
} }
@@ -1469,7 +1480,7 @@ namespace v2rayN.ViewModels
{ {
return; return;
} }
if (_config.routingIndexId == item.id) if (_config.routingBasicItem.routingIndexId == item.id)
{ {
return; return;
} }
@@ -1521,7 +1532,7 @@ namespace v2rayN.ViewModels
public void ShowHideWindow(bool? blShow) public void ShowHideWindow(bool? blShow)
{ {
var bl = blShow.HasValue ? blShow.Value : !Global.ShowInTaskbar; var bl = blShow ?? !Global.ShowInTaskbar;
if (bl) if (bl)
{ {
//Application.Current.MainWindow.ShowInTaskbar = true; //Application.Current.MainWindow.ShowInTaskbar = true;
@@ -1616,8 +1627,9 @@ namespace v2rayN.ViewModels
_config.uiItem.currentFontSize = CurrentFontSize; _config.uiItem.currentFontSize = CurrentFontSize;
double size = (long)CurrentFontSize; double size = (long)CurrentFontSize;
Application.Current.Resources["StdFontSize"] = size; Application.Current.Resources["StdFontSize"] = size;
Application.Current.Resources["StdFontSize1"] = size + 2; Application.Current.Resources["StdFontSize1"] = size + 1;
Application.Current.Resources["StdFontSize2"] = size + 4; Application.Current.Resources["StdFontSize2"] = size + 2;
Application.Current.Resources["StdFontSizeMsg"] = size - 1;
ConfigHandler.SaveConfig(ref _config); ConfigHandler.SaveConfig(ref _config);
} }
@@ -1639,7 +1651,7 @@ namespace v2rayN.ViewModels
public void InboundDisplayStaus() public void InboundDisplayStaus()
{ {
StringBuilder sb = new StringBuilder(); StringBuilder sb = new();
sb.Append($"[{Global.InboundSocks}:{LazyConfig.Instance.GetLocalPort(Global.InboundSocks)}]"); sb.Append($"[{Global.InboundSocks}:{LazyConfig.Instance.GetLocalPort(Global.InboundSocks)}]");
sb.Append(" | "); sb.Append(" | ");
//if (_config.sysProxyType == ESysProxyType.ForcedChange) //if (_config.sysProxyType == ESysProxyType.ForcedChange)
@@ -1650,21 +1662,21 @@ namespace v2rayN.ViewModels
//{ //{
sb.Append($"[{Global.InboundHttp}:{LazyConfig.Instance.GetLocalPort(Global.InboundHttp)}]"); sb.Append($"[{Global.InboundHttp}:{LazyConfig.Instance.GetLocalPort(Global.InboundHttp)}]");
//} //}
InboundDisplay = $"{ResUI.LabLocal}:{sb.ToString()}"; InboundDisplay = $"{ResUI.LabLocal}:{sb}";
if (_config.inbound[0].allowLANConn) if (_config.inbound[0].allowLANConn)
{ {
if (_config.inbound[0].newPort4LAN) if (_config.inbound[0].newPort4LAN)
{ {
StringBuilder sb2 = new StringBuilder(); StringBuilder sb2 = new();
sb2.Append($"[{Global.InboundSocks}:{LazyConfig.Instance.GetLocalPort(Global.InboundSocks2)}]"); sb2.Append($"[{Global.InboundSocks}:{LazyConfig.Instance.GetLocalPort(Global.InboundSocks2)}]");
sb2.Append(" | "); sb2.Append(" | ");
sb2.Append($"[{Global.InboundHttp}:{LazyConfig.Instance.GetLocalPort(Global.InboundHttp2)}]"); sb2.Append($"[{Global.InboundHttp}:{LazyConfig.Instance.GetLocalPort(Global.InboundHttp2)}]");
InboundLanDisplay = $"{ResUI.LabLAN}:{sb2.ToString()}"; InboundLanDisplay = $"{ResUI.LabLAN}:{sb2}";
} }
else else
{ {
InboundLanDisplay = $"{ResUI.LabLAN}:{sb.ToString()}"; InboundLanDisplay = $"{ResUI.LabLAN}:{sb}";
} }
} }
else else
@@ -1701,10 +1713,10 @@ namespace v2rayN.ViewModels
.Delay(TimeSpan.FromSeconds(1)) .Delay(TimeSpan.FromSeconds(1))
.Subscribe(x => .Subscribe(x =>
{ {
Application.Current.Dispatcher.Invoke((Action)(() => Application.Current.Dispatcher.Invoke(() =>
{ {
ShowHideWindow(false); ShowHideWindow(false);
})); });
}); });
} }
} }

View File

@@ -63,6 +63,8 @@ namespace v2rayN.ViewModels
[Reactive] public int autoUpdateSubInterval { get; set; } [Reactive] public int autoUpdateSubInterval { get; set; }
[Reactive] public int trayMenuServersLimit { get; set; } [Reactive] public int trayMenuServersLimit { get; set; }
[Reactive] public string currentFontFamily { get; set; } [Reactive] public string currentFontFamily { get; set; }
[Reactive] public int SpeedTestTimeout { get; set; }
[Reactive] public string SpeedTestUrl { get; set; }
#endregion #endregion
@@ -73,6 +75,7 @@ namespace v2rayN.ViewModels
#region Tun mode #region Tun mode
[Reactive] public bool TunShowWindow { get; set; } [Reactive] public bool TunShowWindow { get; set; }
[Reactive] public bool TunEnabledLog { get; set; }
[Reactive] public bool TunStrictRoute { get; set; } [Reactive] public bool TunStrictRoute { get; set; }
[Reactive] public string TunStack { get; set; } [Reactive] public string TunStack { get; set; }
[Reactive] public int TunMtu { get; set; } [Reactive] public int TunMtu { get; set; }
@@ -114,12 +117,12 @@ namespace v2rayN.ViewModels
newPort4LAN = inbound.newPort4LAN; newPort4LAN = inbound.newPort4LAN;
user = inbound.user; user = inbound.user;
pass = inbound.pass; pass = inbound.pass;
muxEnabled = _config.muxEnabled; muxEnabled = _config.coreBasicItem.muxEnabled;
logEnabled = _config.logEnabled; logEnabled = _config.coreBasicItem.logEnabled;
loglevel = _config.loglevel; loglevel = _config.coreBasicItem.loglevel;
defAllowInsecure = _config.defAllowInsecure; defAllowInsecure = _config.coreBasicItem.defAllowInsecure;
defFingerprint = _config.defFingerprint; defFingerprint = _config.coreBasicItem.defFingerprint;
defUserAgent = _config.defUserAgent; defUserAgent = _config.coreBasicItem.defUserAgent;
#endregion #endregion
#region Core DNS #region Core DNS
@@ -138,21 +141,23 @@ namespace v2rayN.ViewModels
#endregion #endregion
#region UI #region UI
AutoRun = _config.autoRun; AutoRun = _config.guiItem.autoRun;
EnableStatistics = _config.enableStatistics; EnableStatistics = _config.guiItem.enableStatistics;
StatisticsFreshRate = _config.statisticsFreshRate; StatisticsFreshRate = _config.guiItem.statisticsFreshRate;
KeepOlderDedupl = _config.keepOlderDedupl; KeepOlderDedupl = _config.guiItem.keepOlderDedupl;
IgnoreGeoUpdateCore = _config.ignoreGeoUpdateCore; IgnoreGeoUpdateCore = _config.guiItem.ignoreGeoUpdateCore;
EnableAutoAdjustMainLvColWidth = _config.uiItem.enableAutoAdjustMainLvColWidth; EnableAutoAdjustMainLvColWidth = _config.uiItem.enableAutoAdjustMainLvColWidth;
EnableSecurityProtocolTls13 = _config.enableSecurityProtocolTls13; EnableSecurityProtocolTls13 = _config.guiItem.enableSecurityProtocolTls13;
AutoHideStartup = _config.uiItem.autoHideStartup; AutoHideStartup = _config.uiItem.autoHideStartup;
EnableCheckPreReleaseUpdate = _config.checkPreReleaseUpdate; EnableCheckPreReleaseUpdate = _config.guiItem.checkPreReleaseUpdate;
EnableDragDropSort = _config.uiItem.enableDragDropSort; EnableDragDropSort = _config.uiItem.enableDragDropSort;
DoubleClick2Activate = _config.uiItem.doubleClick2Activate; DoubleClick2Activate = _config.uiItem.doubleClick2Activate;
autoUpdateInterval = _config.autoUpdateInterval; autoUpdateInterval = _config.guiItem.autoUpdateInterval;
autoUpdateSubInterval = _config.autoUpdateSubInterval; autoUpdateSubInterval = _config.guiItem.autoUpdateSubInterval;
trayMenuServersLimit = _config.trayMenuServersLimit; trayMenuServersLimit = _config.guiItem.trayMenuServersLimit;
currentFontFamily = _config.uiItem.currentFontFamily; currentFontFamily = _config.uiItem.currentFontFamily;
SpeedTestTimeout = _config.speedTestItem.speedTestTimeout;
SpeedTestUrl = _config.speedTestItem.speedTestUrl;
#endregion #endregion
@@ -164,6 +169,7 @@ namespace v2rayN.ViewModels
#region Tun mode #region Tun mode
TunShowWindow = _config.tunModeItem.showWindow; TunShowWindow = _config.tunModeItem.showWindow;
TunEnabledLog = _config.tunModeItem.enabledLog;
TunStrictRoute = _config.tunModeItem.strictRoute; TunStrictRoute = _config.tunModeItem.strictRoute;
TunStack = _config.tunModeItem.stack; TunStack = _config.tunModeItem.stack;
TunMtu = _config.tunModeItem.mtu; TunMtu = _config.tunModeItem.mtu;
@@ -283,12 +289,12 @@ namespace v2rayN.ViewModels
{ {
_config.inbound.RemoveAt(1); _config.inbound.RemoveAt(1);
} }
_config.logEnabled = logEnabled; _config.coreBasicItem.logEnabled = logEnabled;
_config.loglevel = loglevel; _config.coreBasicItem.loglevel = loglevel;
_config.muxEnabled = muxEnabled; _config.coreBasicItem.muxEnabled = muxEnabled;
_config.defAllowInsecure = defAllowInsecure; _config.coreBasicItem.defAllowInsecure = defAllowInsecure;
_config.defFingerprint = defFingerprint; _config.coreBasicItem.defFingerprint = defFingerprint;
_config.defUserAgent = defUserAgent; _config.coreBasicItem.defUserAgent = defUserAgent;
//DNS //DNS
@@ -308,25 +314,27 @@ namespace v2rayN.ViewModels
//UI //UI
Utils.SetAutoRun(AutoRun); Utils.SetAutoRun(AutoRun);
_config.autoRun = AutoRun; _config.guiItem.autoRun = AutoRun;
_config.enableStatistics = EnableStatistics; _config.guiItem.enableStatistics = EnableStatistics;
_config.statisticsFreshRate = StatisticsFreshRate; _config.guiItem.statisticsFreshRate = StatisticsFreshRate;
if (_config.statisticsFreshRate > 100 || _config.statisticsFreshRate < 1) if (_config.guiItem.statisticsFreshRate > 100 || _config.guiItem.statisticsFreshRate < 1)
{ {
_config.statisticsFreshRate = 1; _config.guiItem.statisticsFreshRate = 1;
} }
_config.keepOlderDedupl = KeepOlderDedupl; _config.guiItem.keepOlderDedupl = KeepOlderDedupl;
_config.ignoreGeoUpdateCore = IgnoreGeoUpdateCore; _config.guiItem.ignoreGeoUpdateCore = IgnoreGeoUpdateCore;
_config.uiItem.enableAutoAdjustMainLvColWidth = EnableAutoAdjustMainLvColWidth; _config.uiItem.enableAutoAdjustMainLvColWidth = EnableAutoAdjustMainLvColWidth;
_config.enableSecurityProtocolTls13 = EnableSecurityProtocolTls13; _config.guiItem.enableSecurityProtocolTls13 = EnableSecurityProtocolTls13;
_config.uiItem.autoHideStartup = AutoHideStartup; _config.uiItem.autoHideStartup = AutoHideStartup;
_config.autoUpdateInterval = autoUpdateInterval; _config.guiItem.autoUpdateInterval = autoUpdateInterval;
_config.autoUpdateSubInterval = autoUpdateSubInterval; _config.guiItem.autoUpdateSubInterval = autoUpdateSubInterval;
_config.checkPreReleaseUpdate = EnableCheckPreReleaseUpdate; _config.guiItem.checkPreReleaseUpdate = EnableCheckPreReleaseUpdate;
_config.uiItem.enableDragDropSort = EnableDragDropSort; _config.uiItem.enableDragDropSort = EnableDragDropSort;
_config.uiItem.doubleClick2Activate = DoubleClick2Activate; _config.uiItem.doubleClick2Activate = DoubleClick2Activate;
_config.trayMenuServersLimit = trayMenuServersLimit; _config.guiItem.trayMenuServersLimit = trayMenuServersLimit;
_config.uiItem.currentFontFamily = currentFontFamily; _config.uiItem.currentFontFamily = currentFontFamily;
_config.speedTestItem.speedTestTimeout = SpeedTestTimeout;
_config.speedTestItem.speedTestUrl = SpeedTestUrl;
//systemProxy //systemProxy
_config.systemProxyExceptions = systemProxyExceptions; _config.systemProxyExceptions = systemProxyExceptions;
@@ -334,6 +342,7 @@ namespace v2rayN.ViewModels
//tun mode //tun mode
_config.tunModeItem.showWindow = TunShowWindow; _config.tunModeItem.showWindow = TunShowWindow;
_config.tunModeItem.enabledLog = TunEnabledLog;
_config.tunModeItem.strictRoute = TunStrictRoute; _config.tunModeItem.strictRoute = TunStrictRoute;
_config.tunModeItem.stack = TunStack; _config.tunModeItem.stack = TunStack;
_config.tunModeItem.mtu = TunMtu; _config.tunModeItem.mtu = TunMtu;

View File

@@ -71,9 +71,9 @@ namespace v2rayN.ViewModels
ConfigHandler.InitBuiltinRouting(ref _config); ConfigHandler.InitBuiltinRouting(ref _config);
enableRoutingAdvanced = _config.enableRoutingAdvanced; enableRoutingAdvanced = _config.routingBasicItem.enableRoutingAdvanced;
domainStrategy = _config.domainStrategy; domainStrategy = _config.routingBasicItem.domainStrategy;
domainMatcher = _config.domainMatcher; domainMatcher = _config.routingBasicItem.domainMatcher;
RefreshRoutingItems(); RefreshRoutingItems();
@@ -163,7 +163,7 @@ namespace v2rayN.ViewModels
foreach (var item in routings) foreach (var item in routings)
{ {
bool def = false; bool def = false;
if (item.id.Equals(_config.routingIndexId)) if (item.id.Equals(_config.routingBasicItem.routingIndexId))
{ {
def = true; def = true;
} }
@@ -176,15 +176,16 @@ namespace v2rayN.ViewModels
remarks = item.remarks, remarks = item.remarks,
url = item.url, url = item.url,
customIcon = item.customIcon, customIcon = item.customIcon,
sort = item.sort,
}; };
_routingItems.Add(it); _routingItems.Add(it);
} }
} }
private void SaveRouting() private void SaveRouting()
{ {
_config.domainStrategy = domainStrategy; _config.routingBasicItem.domainStrategy = domainStrategy;
_config.enableRoutingAdvanced = enableRoutingAdvanced; _config.routingBasicItem.enableRoutingAdvanced = enableRoutingAdvanced;
_config.domainMatcher = domainMatcher; _config.routingBasicItem.domainMatcher = domainMatcher;
EndBindingLockedData(); EndBindingLockedData();

View File

@@ -18,6 +18,7 @@
Background="{DynamicResource MaterialDesignPaper}" Background="{DynamicResource MaterialDesignPaper}"
FontFamily="{x:Static conv:MaterialDesignFonts.MyFont}" FontFamily="{x:Static conv:MaterialDesignFonts.MyFont}"
ResizeMode="NoResize" ResizeMode="NoResize"
ShowInTaskbar="False"
TextElement.FontFamily="{x:Static conv:MaterialDesignFonts.MyFont}" TextElement.FontFamily="{x:Static conv:MaterialDesignFonts.MyFont}"
TextElement.Foreground="{DynamicResource MaterialDesignBody}" TextElement.Foreground="{DynamicResource MaterialDesignBody}"
TextOptions.TextFormattingMode="Display" TextOptions.TextFormattingMode="Display"

View File

@@ -11,6 +11,7 @@ namespace v2rayN.Views
public AddServer2Window(ProfileItem profileItem) public AddServer2Window(ProfileItem profileItem)
{ {
InitializeComponent(); InitializeComponent();
this.Owner = Application.Current.MainWindow;
this.Loaded += Window_Loaded; this.Loaded += Window_Loaded;
ViewModel = new AddServer2ViewModel(profileItem, this); ViewModel = new AddServer2ViewModel(profileItem, this);

View File

@@ -16,6 +16,7 @@
Background="{DynamicResource MaterialDesignPaper}" Background="{DynamicResource MaterialDesignPaper}"
FontFamily="{x:Static conv:MaterialDesignFonts.MyFont}" FontFamily="{x:Static conv:MaterialDesignFonts.MyFont}"
ResizeMode="NoResize" ResizeMode="NoResize"
ShowInTaskbar="False"
TextElement.FontFamily="{x:Static conv:MaterialDesignFonts.MyFont}" TextElement.FontFamily="{x:Static conv:MaterialDesignFonts.MyFont}"
TextElement.Foreground="{DynamicResource MaterialDesignBody}" TextElement.Foreground="{DynamicResource MaterialDesignBody}"
TextOptions.TextFormattingMode="Display" TextOptions.TextFormattingMode="Display"

View File

@@ -16,6 +16,7 @@ namespace v2rayN.Views
public AddServerWindow(ProfileItem profileItem) public AddServerWindow(ProfileItem profileItem)
{ {
InitializeComponent(); InitializeComponent();
this.Owner = Application.Current.MainWindow;
this.Loaded += Window_Loaded; this.Loaded += Window_Loaded;
cmbNetwork.SelectionChanged += CmbNetwork_SelectionChanged; cmbNetwork.SelectionChanged += CmbNetwork_SelectionChanged;
cmbStreamSecurity.SelectionChanged += CmbStreamSecurity_SelectionChanged; cmbStreamSecurity.SelectionChanged += CmbStreamSecurity_SelectionChanged;

View File

@@ -18,6 +18,7 @@
FontFamily="{x:Static conv:MaterialDesignFonts.MyFont}" FontFamily="{x:Static conv:MaterialDesignFonts.MyFont}"
KeyDown="GlobalHotkeySettingWindow_KeyDown" KeyDown="GlobalHotkeySettingWindow_KeyDown"
ResizeMode="NoResize" ResizeMode="NoResize"
ShowInTaskbar="False"
TextElement.FontFamily="{x:Static conv:MaterialDesignFonts.MyFont}" TextElement.FontFamily="{x:Static conv:MaterialDesignFonts.MyFont}"
TextElement.Foreground="{DynamicResource MaterialDesignBody}" TextElement.Foreground="{DynamicResource MaterialDesignBody}"
TextOptions.TextFormattingMode="Display" TextOptions.TextFormattingMode="Display"

View File

@@ -16,6 +16,7 @@ namespace v2rayN.Views
public GlobalHotkeySettingWindow() public GlobalHotkeySettingWindow()
{ {
InitializeComponent(); InitializeComponent();
this.Owner = Application.Current.MainWindow;
_config = LazyConfig.Instance.GetConfig(); _config = LazyConfig.Instance.GetConfig();
if (_config.globalHotkeys == null) if (_config.globalHotkeys == null)

View File

@@ -333,13 +333,12 @@
</materialDesign:PopupBox> </materialDesign:PopupBox>
</ToolBar> </ToolBar>
</ToolBarTray> </ToolBarTray>
<ToolBarTray DockPanel.Dock="Top"> <WrapPanel Margin="2" DockPanel.Dock="Top">
<ToolBar <ListBox
HorizontalAlignment="Center" x:Name="lstGroup"
VerticalAlignment="Center" FontSize="{DynamicResource StdFontSize}"
ClipToBounds="True" ItemContainerStyle="{StaticResource MyChipListBoxItem}"
Style="{StaticResource MaterialDesignToolBar}"> Style="{StaticResource MaterialDesignChoiceChipPrimaryOutlineListBox}">
<ListBox x:Name="lstGroup" Style="{StaticResource MaterialDesignChoiceChipPrimaryOutlineListBox}">
<ListBox.ItemTemplate> <ListBox.ItemTemplate>
<DataTemplate> <DataTemplate>
<TextBlock Text="{Binding remarks}" /> <TextBlock Text="{Binding remarks}" />
@@ -350,20 +349,18 @@
x:Name="btnAddSub" x:Name="btnAddSub"
Width="30" Width="30"
Height="30" Height="30"
Margin="8,0" Margin="4,0"
Style="{StaticResource MaterialDesignFloatingActionMiniLightButton}"> Style="{StaticResource MaterialDesignFloatingActionMiniLightButton}">
<materialDesign:PackIcon Kind="Plus" /> <materialDesign:PackIcon Kind="Plus" />
</Button> </Button>
<Separator />
<TextBox <TextBox
x:Name="txtServerFilter" x:Name="txtServerFilter"
Width="200" Width="200"
Margin="8,0" Margin="4,0"
materialDesign:HintAssist.Hint="{x:Static resx:ResUI.MsgServerTitle}" materialDesign:HintAssist.Hint="{x:Static resx:ResUI.MsgServerTitle}"
materialDesign:TextFieldAssist.HasClearButton="True" materialDesign:TextFieldAssist.HasClearButton="True"
Style="{StaticResource DefTextBox}" /> Style="{StaticResource DefTextBox}" />
</ToolBar> </WrapPanel>
</ToolBarTray>
<materialDesign:ColorZone <materialDesign:ColorZone
Height="50" Height="50"

View File

@@ -434,7 +434,7 @@ namespace v2rayN.Views
var width = ConfigHandler.GetformMainLvColWidth(ref _config, ((EServerColName)k).ToString(), Convert.ToInt32(lstProfiles.Columns[k].Width.Value)); var width = ConfigHandler.GetformMainLvColWidth(ref _config, ((EServerColName)k).ToString(), Convert.ToInt32(lstProfiles.Columns[k].Width.Value));
lstProfiles.Columns[k].Width = width; lstProfiles.Columns[k].Width = width;
} }
if (!_config.enableStatistics) if (!_config.guiItem.enableStatistics)
{ {
colTodayUp.Visibility = Visibility.Hidden; colTodayUp.Visibility = Visibility.Hidden;
colTodayDown.Visibility = Visibility.Hidden; colTodayDown.Visibility = Visibility.Hidden;

View File

@@ -29,7 +29,8 @@
materialDesign:HintAssist.Hint="{x:Static resx:ResUI.MsgFilterTitle}" materialDesign:HintAssist.Hint="{x:Static resx:ResUI.MsgFilterTitle}"
materialDesign:TextFieldAssist.HasClearButton="True" materialDesign:TextFieldAssist.HasClearButton="True"
IsEditable="True" IsEditable="True"
Style="{StaticResource DefComboBox}" /> Style="{StaticResource DefComboBox}"
TextBoxBase.TextChanged="cmbMsgFilter_TextChanged" />
<TextBlock <TextBlock
Margin="8,0" Margin="8,0"
VerticalAlignment="Center" VerticalAlignment="Center"
@@ -44,9 +45,10 @@
<TextBox <TextBox
Name="txtMsg" Name="txtMsg"
BorderThickness="0" BorderThickness="0"
FontSize="{DynamicResource StdFontSize}" FontSize="{DynamicResource StdFontSizeMsg}"
HorizontalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Auto"
IsReadOnly="True" IsReadOnly="True"
TextAlignment="Left"
TextWrapping="Wrap" TextWrapping="Wrap"
VerticalScrollBarVisibility="Visible"> VerticalScrollBarVisibility="Visible">
<TextBox.ContextMenu> <TextBox.ContextMenu>

View File

@@ -3,19 +3,27 @@ using System.Reactive.Linq;
using System.Text.RegularExpressions; using System.Text.RegularExpressions;
using System.Windows.Threading; using System.Windows.Threading;
using v2rayN.Base; using v2rayN.Base;
using v2rayN.Handler;
using v2rayN.Mode;
namespace v2rayN.Views namespace v2rayN.Views
{ {
public partial class MsgView public partial class MsgView
{ {
private static Config _config;
public MsgView() public MsgView()
{ {
InitializeComponent(); InitializeComponent();
_config = LazyConfig.Instance.GetConfig();
MessageBus.Current.Listen<string>("MsgView").Subscribe(x => DelegateAppendText(x)); MessageBus.Current.Listen<string>("MsgView").Subscribe(x => DelegateAppendText(x));
Global.PresetMsgFilters.ForEach(it => Global.PresetMsgFilters.ForEach(it =>
{ {
cmbMsgFilter.Items.Add(it); cmbMsgFilter.Items.Add(it);
}); });
if (!_config.uiItem.mainMsgFilter.IsNullOrEmpty())
{
cmbMsgFilter.Text = _config.uiItem.mainMsgFilter;
}
} }
void DelegateAppendText(string msg) void DelegateAppendText(string msg)
@@ -87,6 +95,10 @@ namespace v2rayN.Views
{ {
ClearMsg(); ClearMsg();
} }
private void cmbMsgFilter_TextChanged(object sender, System.Windows.Controls.TextChangedEventArgs e)
{
_config.uiItem.mainMsgFilter = cmbMsgFilter.Text.TrimEx();
}
} }
} }

View File

@@ -16,6 +16,7 @@
Background="{DynamicResource MaterialDesignPaper}" Background="{DynamicResource MaterialDesignPaper}"
FontFamily="{x:Static conv:MaterialDesignFonts.MyFont}" FontFamily="{x:Static conv:MaterialDesignFonts.MyFont}"
ResizeMode="NoResize" ResizeMode="NoResize"
ShowInTaskbar="False"
TextElement.FontFamily="{x:Static conv:MaterialDesignFonts.MyFont}" TextElement.FontFamily="{x:Static conv:MaterialDesignFonts.MyFont}"
TextElement.Foreground="{DynamicResource MaterialDesignBody}" TextElement.Foreground="{DynamicResource MaterialDesignBody}"
TextOptions.TextFormattingMode="Display" TextOptions.TextFormattingMode="Display"
@@ -478,6 +479,8 @@
<RowDefinition Height="Auto" /> <RowDefinition Height="Auto" />
<RowDefinition Height="Auto" /> <RowDefinition Height="Auto" />
<RowDefinition Height="Auto" /> <RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions> </Grid.RowDefinitions>
<Grid.ColumnDefinitions> <Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" /> <ColumnDefinition Width="Auto" />
@@ -660,6 +663,7 @@
Grid.Column="1" Grid.Column="1"
Width="200" Width="200"
Margin="{StaticResource SettingItemMargin}" Margin="{StaticResource SettingItemMargin}"
HorizontalAlignment="Left"
Style="{StaticResource DefTextBox}" /> Style="{StaticResource DefTextBox}" />
<TextBlock <TextBlock
@@ -675,6 +679,7 @@
Grid.Column="1" Grid.Column="1"
Width="200" Width="200"
Margin="{StaticResource SettingItemMargin}" Margin="{StaticResource SettingItemMargin}"
HorizontalAlignment="Left"
Style="{StaticResource DefTextBox}" /> Style="{StaticResource DefTextBox}" />
<TextBlock <TextBlock
@@ -690,6 +695,7 @@
Grid.Column="1" Grid.Column="1"
Width="200" Width="200"
Margin="{StaticResource SettingItemMargin}" Margin="{StaticResource SettingItemMargin}"
HorizontalAlignment="Left"
Style="{StaticResource DefTextBox}" /> Style="{StaticResource DefTextBox}" />
<TextBlock <TextBlock
@@ -714,6 +720,36 @@
VerticalAlignment="Center" VerticalAlignment="Center"
Style="{StaticResource ToolbarTextBlock}" Style="{StaticResource ToolbarTextBlock}"
Text="{x:Static resx:ResUI.TbSettingsCurrentFontFamilyTip}" /> Text="{x:Static resx:ResUI.TbSettingsCurrentFontFamilyTip}" />
<TextBlock
Grid.Row="16"
Grid.Column="0"
Margin="{StaticResource SettingItemMargin}"
VerticalAlignment="Center"
Style="{StaticResource ToolbarTextBlock}"
Text="{x:Static resx:ResUI.TbSettingsSpeedTestTimeout}" />
<ComboBox
x:Name="cmbSpeedTestTimeout"
Grid.Row="16"
Grid.Column="1"
Width="200"
Margin="{StaticResource SettingItemMargin}"
Style="{StaticResource DefComboBox}" />
<TextBlock
Grid.Row="17"
Grid.Column="0"
Margin="{StaticResource SettingItemMargin}"
VerticalAlignment="Center"
Style="{StaticResource ToolbarTextBlock}"
Text="{x:Static resx:ResUI.TbSettingsSpeedTestUrl}" />
<ComboBox
x:Name="cmbSpeedTestUrl"
Grid.Row="17"
Grid.Column="1"
Width="300"
Margin="{StaticResource SettingItemMargin}"
Style="{StaticResource DefComboBox}" />
</Grid> </Grid>
</ScrollViewer> </ScrollViewer>
</TabItem> </TabItem>
@@ -780,7 +816,7 @@
</Grid.ColumnDefinitions> </Grid.ColumnDefinitions>
<TextBlock <TextBlock
Grid.Row="1" Grid.Row="0"
Grid.Column="0" Grid.Column="0"
Margin="{StaticResource SettingItemMargin}" Margin="{StaticResource SettingItemMargin}"
VerticalAlignment="Center" VerticalAlignment="Center"
@@ -788,6 +824,20 @@
Text="{x:Static resx:ResUI.TbSettingsTunModeShowWindow}" /> Text="{x:Static resx:ResUI.TbSettingsTunModeShowWindow}" />
<ToggleButton <ToggleButton
x:Name="togShowWindow" x:Name="togShowWindow"
Grid.Row="0"
Grid.Column="1"
Margin="{StaticResource SettingItemMargin}"
HorizontalAlignment="Left" />
<TextBlock
Grid.Row="1"
Grid.Column="0"
Margin="{StaticResource SettingItemMargin}"
VerticalAlignment="Center"
Style="{StaticResource ToolbarTextBlock}"
Text="{x:Static resx:ResUI.TbSettingsLogEnabled}" />
<ToggleButton
x:Name="togEnabledLog"
Grid.Row="1" Grid.Row="1"
Grid.Column="1" Grid.Column="1"
Margin="{StaticResource SettingItemMargin}" Margin="{StaticResource SettingItemMargin}"

View File

@@ -17,6 +17,7 @@ namespace v2rayN.Views
public OptionSettingWindow() public OptionSettingWindow()
{ {
InitializeComponent(); InitializeComponent();
this.Owner = Application.Current.MainWindow;
_config = LazyConfig.Instance.GetConfig(); _config = LazyConfig.Instance.GetConfig();
ViewModel = new OptionSettingViewModel(this); ViewModel = new OptionSettingViewModel(this);
@@ -63,6 +64,15 @@ namespace v2rayN.Views
cmbCoreType6.Items.Add(it); cmbCoreType6.Items.Add(it);
}); });
for (int i = 2; i <= 6; i++)
{
cmbSpeedTestTimeout.Items.Add(i * 5);
}
Global.SpeedTestUrls.ForEach(it =>
{
cmbSpeedTestUrl.Items.Add(it);
});
//fill fonts //fill fonts
try try
{ {
@@ -79,11 +89,11 @@ namespace v2rayN.Views
foreach (Typeface typeface in typefaces) foreach (Typeface typeface in typefaces)
{ {
typeface.TryGetGlyphTypeface(out GlyphTypeface glyph); typeface.TryGetGlyphTypeface(out GlyphTypeface glyph);
var fontFace = glyph.Win32FaceNames[new CultureInfo("en-us")]; //var fontFace = glyph.Win32FaceNames[new CultureInfo("en-us")];
if (!fontFace.Equals("Regular") && !fontFace.Equals("Normal")) //if (!fontFace.Equals("Regular") && !fontFace.Equals("Normal"))
{ //{
continue; // continue;
} //}
var fontFamily = glyph.Win32FamilyNames[new CultureInfo(culture)]; var fontFamily = glyph.Win32FamilyNames[new CultureInfo(culture)];
if (Utils.IsNullOrEmpty(fontFamily)) if (Utils.IsNullOrEmpty(fontFamily))
{ {
@@ -153,6 +163,8 @@ namespace v2rayN.Views
this.Bind(ViewModel, vm => vm.autoUpdateSubInterval, v => v.txtautoUpdateSubInterval.Text).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.autoUpdateSubInterval, v => v.txtautoUpdateSubInterval.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.trayMenuServersLimit, v => v.txttrayMenuServersLimit.Text).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.trayMenuServersLimit, v => v.txttrayMenuServersLimit.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.currentFontFamily, v => v.cmbcurrentFontFamily.Text).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.currentFontFamily, v => v.cmbcurrentFontFamily.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.SpeedTestTimeout, v => v.cmbSpeedTestTimeout.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.SpeedTestUrl, v => v.cmbSpeedTestUrl.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.systemProxyAdvancedProtocol, v => v.cmbsystemProxyAdvancedProtocol.Text).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.systemProxyAdvancedProtocol, v => v.cmbsystemProxyAdvancedProtocol.Text).DisposeWith(disposables);
@@ -160,6 +172,7 @@ namespace v2rayN.Views
this.Bind(ViewModel, vm => vm.TunShowWindow, v => v.togShowWindow.IsChecked).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.TunShowWindow, v => v.togShowWindow.IsChecked).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.TunEnabledLog, v => v.togEnabledLog.IsChecked).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.TunStrictRoute, v => v.togStrictRoute.IsChecked).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.TunStrictRoute, v => v.togStrictRoute.IsChecked).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.TunStack, v => v.cmbStack.Text).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.TunStack, v => v.cmbStack.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.TunMtu, v => v.cmbMtu.Text).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.TunMtu, v => v.cmbMtu.Text).DisposeWith(disposables);

View File

@@ -16,6 +16,7 @@
Background="{DynamicResource MaterialDesignPaper}" Background="{DynamicResource MaterialDesignPaper}"
FontFamily="{x:Static conv:MaterialDesignFonts.MyFont}" FontFamily="{x:Static conv:MaterialDesignFonts.MyFont}"
ResizeMode="NoResize" ResizeMode="NoResize"
ShowInTaskbar="False"
TextElement.FontFamily="{x:Static conv:MaterialDesignFonts.MyFont}" TextElement.FontFamily="{x:Static conv:MaterialDesignFonts.MyFont}"
TextElement.Foreground="{DynamicResource MaterialDesignBody}" TextElement.Foreground="{DynamicResource MaterialDesignBody}"
TextOptions.TextFormattingMode="Display" TextOptions.TextFormattingMode="Display"

View File

@@ -12,6 +12,7 @@ namespace v2rayN.Views
public RoutingRuleDetailsWindow(RulesItem rulesItem) public RoutingRuleDetailsWindow(RulesItem rulesItem)
{ {
InitializeComponent(); InitializeComponent();
this.Owner = Application.Current.MainWindow;
this.Loaded += Window_Loaded; this.Loaded += Window_Loaded;
clbProtocol.SelectionChanged += ClbProtocol_SelectionChanged; clbProtocol.SelectionChanged += ClbProtocol_SelectionChanged;
clbInboundTag.SelectionChanged += ClbInboundTag_SelectionChanged; clbInboundTag.SelectionChanged += ClbInboundTag_SelectionChanged;

View File

@@ -16,6 +16,7 @@
Background="{DynamicResource MaterialDesignPaper}" Background="{DynamicResource MaterialDesignPaper}"
FontFamily="{x:Static conv:MaterialDesignFonts.MyFont}" FontFamily="{x:Static conv:MaterialDesignFonts.MyFont}"
ResizeMode="NoResize" ResizeMode="NoResize"
ShowInTaskbar="False"
TextElement.FontFamily="{x:Static conv:MaterialDesignFonts.MyFont}" TextElement.FontFamily="{x:Static conv:MaterialDesignFonts.MyFont}"
TextElement.Foreground="{DynamicResource MaterialDesignBody}" TextElement.Foreground="{DynamicResource MaterialDesignBody}"
TextOptions.TextFormattingMode="Display" TextOptions.TextFormattingMode="Display"
@@ -92,6 +93,7 @@
<RowDefinition Height="Auto" /> <RowDefinition Height="Auto" />
<RowDefinition Height="Auto" /> <RowDefinition Height="Auto" />
<RowDefinition Height="Auto" /> <RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions> </Grid.RowDefinitions>
<Grid.ColumnDefinitions> <Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" /> <ColumnDefinition Width="Auto" />
@@ -177,6 +179,23 @@
Content="{x:Static resx:ResUI.TbBrowse}" Content="{x:Static resx:ResUI.TbBrowse}"
Style="{StaticResource DefButton}" /> Style="{StaticResource DefButton}" />
<TextBlock
Grid.Row="4"
Grid.Column="0"
Margin="4"
VerticalAlignment="Center"
Style="{StaticResource ToolbarTextBlock}"
Text="{x:Static resx:ResUI.LvSort}" />
<TextBox
x:Name="txtSort"
Grid.Row="4"
Grid.Column="1"
Width="200"
Margin="4"
HorizontalAlignment="Left"
AcceptsReturn="True"
Style="{StaticResource DefTextBox}" />
</Grid> </Grid>
<TabControl x:Name="tabAdvanced"> <TabControl x:Name="tabAdvanced">

View File

@@ -12,6 +12,7 @@ namespace v2rayN.Views
public RoutingRuleSettingWindow(RoutingItem routingItem) public RoutingRuleSettingWindow(RoutingItem routingItem)
{ {
InitializeComponent(); InitializeComponent();
this.Owner = Application.Current.MainWindow;
this.Loaded += Window_Loaded; this.Loaded += Window_Loaded;
this.PreviewKeyDown += RoutingRuleSettingWindow_PreviewKeyDown; this.PreviewKeyDown += RoutingRuleSettingWindow_PreviewKeyDown;
lstRules.SelectionChanged += lstRules_SelectionChanged; lstRules.SelectionChanged += lstRules_SelectionChanged;
@@ -33,6 +34,7 @@ namespace v2rayN.Views
this.Bind(ViewModel, vm => vm.SelectedRouting.domainStrategy, v => v.cmbdomainStrategy.Text).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.SelectedRouting.domainStrategy, v => v.cmbdomainStrategy.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.SelectedRouting.url, v => v.txtUrl.Text).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.SelectedRouting.url, v => v.txtUrl.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.SelectedRouting.customIcon, v => v.txtCustomIcon.Text).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.SelectedRouting.customIcon, v => v.txtCustomIcon.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.SelectedRouting.sort, v => v.txtSort.Text).DisposeWith(disposables);
this.BindCommand(ViewModel, vm => vm.RuleAddCmd, v => v.menuRuleAdd).DisposeWith(disposables); this.BindCommand(ViewModel, vm => vm.RuleAddCmd, v => v.menuRuleAdd).DisposeWith(disposables);
this.BindCommand(ViewModel, vm => vm.ImportRulesFromFileCmd, v => v.menuImportRulesFromFile).DisposeWith(disposables); this.BindCommand(ViewModel, vm => vm.ImportRulesFromFileCmd, v => v.menuImportRulesFromFile).DisposeWith(disposables);

View File

@@ -16,6 +16,7 @@
Background="{DynamicResource MaterialDesignPaper}" Background="{DynamicResource MaterialDesignPaper}"
FontFamily="{x:Static conv:MaterialDesignFonts.MyFont}" FontFamily="{x:Static conv:MaterialDesignFonts.MyFont}"
ResizeMode="NoResize" ResizeMode="NoResize"
ShowInTaskbar="False"
TextElement.FontFamily="{x:Static conv:MaterialDesignFonts.MyFont}" TextElement.FontFamily="{x:Static conv:MaterialDesignFonts.MyFont}"
TextElement.Foreground="{DynamicResource MaterialDesignBody}" TextElement.Foreground="{DynamicResource MaterialDesignBody}"
TextOptions.TextFormattingMode="Display" TextOptions.TextFormattingMode="Display"
@@ -197,15 +198,19 @@
Binding="{Binding remarks}" Binding="{Binding remarks}"
Header="{x:Static resx:ResUI.LvAlias}" /> Header="{x:Static resx:ResUI.LvAlias}" />
<DataGridTextColumn <DataGridTextColumn
Width="70" Width="60"
Binding="{Binding ruleNum}" Binding="{Binding ruleNum}"
Header="{x:Static resx:ResUI.LvCount}" /> Header="{x:Static resx:ResUI.LvCount}" />
<DataGridTextColumn <DataGridTextColumn
Width="280" Width="60"
Binding="{Binding sort}"
Header="{x:Static resx:ResUI.LvSort}" />
<DataGridTextColumn
Width="260"
Binding="{Binding url}" Binding="{Binding url}"
Header="{x:Static resx:ResUI.LvUrl}" /> Header="{x:Static resx:ResUI.LvUrl}" />
<DataGridTextColumn <DataGridTextColumn
Width="280" Width="260"
Binding="{Binding customIcon}" Binding="{Binding customIcon}"
Header="{x:Static resx:ResUI.LvCustomIcon}" /> Header="{x:Static resx:ResUI.LvCustomIcon}" />
</DataGrid.Columns> </DataGrid.Columns>

View File

@@ -1,5 +1,6 @@
using ReactiveUI; using ReactiveUI;
using System.Reactive.Disposables; using System.Reactive.Disposables;
using System.Windows;
using System.Windows.Input; using System.Windows.Input;
using v2rayN.Mode; using v2rayN.Mode;
using v2rayN.ViewModels; using v2rayN.ViewModels;
@@ -11,6 +12,7 @@ namespace v2rayN.Views
public RoutingSettingWindow() public RoutingSettingWindow()
{ {
InitializeComponent(); InitializeComponent();
this.Owner = Application.Current.MainWindow;
this.Closing += RoutingSettingWindow_Closing; this.Closing += RoutingSettingWindow_Closing;
this.PreviewKeyDown += RoutingSettingWindow_PreviewKeyDown; this.PreviewKeyDown += RoutingSettingWindow_PreviewKeyDown;
lstRoutings.SelectionChanged += lstRoutings_SelectionChanged; lstRoutings.SelectionChanged += lstRoutings_SelectionChanged;

View File

@@ -16,6 +16,7 @@
Background="{DynamicResource MaterialDesignPaper}" Background="{DynamicResource MaterialDesignPaper}"
FontFamily="{x:Static conv:MaterialDesignFonts.MyFont}" FontFamily="{x:Static conv:MaterialDesignFonts.MyFont}"
ResizeMode="NoResize" ResizeMode="NoResize"
ShowInTaskbar="False"
TextElement.FontFamily="{x:Static conv:MaterialDesignFonts.MyFont}" TextElement.FontFamily="{x:Static conv:MaterialDesignFonts.MyFont}"
TextElement.Foreground="{DynamicResource MaterialDesignBody}" TextElement.Foreground="{DynamicResource MaterialDesignBody}"
TextOptions.TextFormattingMode="Display" TextOptions.TextFormattingMode="Display"

View File

@@ -11,6 +11,7 @@ namespace v2rayN.Views
public SubEditWindow(SubItem subItem) public SubEditWindow(SubItem subItem)
{ {
InitializeComponent(); InitializeComponent();
this.Owner = Application.Current.MainWindow;
this.Loaded += Window_Loaded; this.Loaded += Window_Loaded;
ViewModel = new SubEditViewModel(subItem, this); ViewModel = new SubEditViewModel(subItem, this);

View File

@@ -16,6 +16,7 @@
Background="{DynamicResource MaterialDesignPaper}" Background="{DynamicResource MaterialDesignPaper}"
FontFamily="{x:Static conv:MaterialDesignFonts.MyFont}" FontFamily="{x:Static conv:MaterialDesignFonts.MyFont}"
ResizeMode="NoResize" ResizeMode="NoResize"
ShowInTaskbar="False"
TextElement.FontFamily="{x:Static conv:MaterialDesignFonts.MyFont}" TextElement.FontFamily="{x:Static conv:MaterialDesignFonts.MyFont}"
TextElement.Foreground="{DynamicResource MaterialDesignBody}" TextElement.Foreground="{DynamicResource MaterialDesignBody}"
TextOptions.TextFormattingMode="Display" TextOptions.TextFormattingMode="Display"

View File

@@ -1,6 +1,7 @@
using ReactiveUI; using ReactiveUI;
using System.ComponentModel; using System.ComponentModel;
using System.Reactive.Disposables; using System.Reactive.Disposables;
using System.Windows;
using System.Windows.Input; using System.Windows.Input;
using v2rayN.ViewModels; using v2rayN.ViewModels;
@@ -11,6 +12,7 @@ namespace v2rayN.Views
public SubSettingWindow() public SubSettingWindow()
{ {
InitializeComponent(); InitializeComponent();
this.Owner = Application.Current.MainWindow;
ViewModel = new SubSettingViewModel(this); ViewModel = new SubSettingViewModel(this);
this.Closing += SubSettingWindow_Closing; this.Closing += SubSettingWindow_Closing;

View File

@@ -1,6 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<GenerateSatelliteAssembliesForCore>true</GenerateSatelliteAssembliesForCore>
<OutputType>WinExe</OutputType> <OutputType>WinExe</OutputType>
<TargetFramework>net6.0-windows</TargetFramework> <TargetFramework>net6.0-windows</TargetFramework>
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
@@ -9,10 +10,11 @@
<ImplicitUsings>enable</ImplicitUsings> <ImplicitUsings>enable</ImplicitUsings>
<ApplicationIcon>v2rayN.ico</ApplicationIcon> <ApplicationIcon>v2rayN.ico</ApplicationIcon>
<Copyright>Copyright © 2017-2023 (GPLv3)</Copyright> <Copyright>Copyright © 2017-2023 (GPLv3)</Copyright>
<FileVersion>6.9</FileVersion> <FileVersion>6.13</FileVersion>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Downloader" Version="3.0.3" />
<PackageReference Include="MaterialDesignThemes" Version="4.7.1" /> <PackageReference Include="MaterialDesignThemes" Version="4.7.1" />
<PackageReference Include="Hardcodet.NotifyIcon.Wpf" Version="1.1.0" /> <PackageReference Include="Hardcodet.NotifyIcon.Wpf" Version="1.1.0" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.2" /> <PackageReference Include="Newtonsoft.Json" Version="13.0.2" />
@@ -25,7 +27,7 @@
<PackageReference Include="ReactiveUI.Fody" Version="18.4.1" /> <PackageReference Include="ReactiveUI.Fody" Version="18.4.1" />
<PackageReference Include="ReactiveUI.Validation" Version="3.0.22" /> <PackageReference Include="ReactiveUI.Validation" Version="3.0.22" />
<PackageReference Include="ReactiveUI.WPF" Version="18.4.1" /> <PackageReference Include="ReactiveUI.WPF" Version="18.4.1" />
<PackageReference Include="Splat.NLog" Version="14.6.1" /> <PackageReference Include="Splat.NLog" Version="14.6.8" />
<PackageReference Include="System.Reactive" Version="5.0.0" /> <PackageReference Include="System.Reactive" Version="5.0.0" />
</ItemGroup> </ItemGroup>